pax_global_header00006660000000000000000000000064136046276460014530gustar00rootroot0000000000000052 comment=c8e8e9cc5049e6964c95049323e92875c16f2977 pgmodeler-0.9.2/000077500000000000000000000000001360462764600135165ustar00rootroot00000000000000pgmodeler-0.9.2/.github/000077500000000000000000000000001360462764600150565ustar00rootroot00000000000000pgmodeler-0.9.2/.github/ISSUE_TEMPLATE/000077500000000000000000000000001360462764600172415ustar00rootroot00000000000000pgmodeler-0.9.2/.github/ISSUE_TEMPLATE/Bug_report.md000066400000000000000000000017671360462764600217060ustar00rootroot00000000000000--- name: Report a bug about: Instructions on how to report pgModeler bugs. Before report any bug please check if someone already has submited issues similiar to yours. Duplicated issues will be ignored. --- **Bug description** _A clear and concise description of what the bug is._ **How to reproduce** _Please, if the bug can be reproduceable describe the steps in full details. If possible provide a sample model and/or a SQL dump for test purposes._ **Expected behavior** _A clear and concise description of what you expected to happen._ **Screenshots** _If applicable, add screenshots to help explain your problem._ **Info about your desktop** - OS: - Version: - Window manager: - pgModeler version: - Qt version: **Stacktrace / Debug info** _If pgModeler crashed after the bug raised attach the stacktrace below_ ``` Put the stacktrace here! ``` **Additional info** _Add any other information that you may find useful to help in the problem solving._ pgmodeler-0.9.2/.github/ISSUE_TEMPLATE/Custom.md000066400000000000000000000002051360462764600210320ustar00rootroot00000000000000--- name: General discussion about: For any discussion not related to bugs or feature requests please use this one. --- pgmodeler-0.9.2/.github/ISSUE_TEMPLATE/Feature_request.md000066400000000000000000000006341360462764600227310ustar00rootroot00000000000000--- name: Feature request / improvement about: Give your suggestions for improvements to this project. --- **Feature description** _A clear and concise description of what the problem is._ **Sample image** _If the feature requested is a visual improvement, please, attach some images to make it clear._ **Additional info** _Add any other context or screenshots about the feature request here._ pgmodeler-0.9.2/.gitignore000066400000000000000000000001501360462764600155020ustar00rootroot00000000000000*.[oa] *.so.* *.so ui_*.h moc_*.cpp obj/* moc/* Makefile build/* *.pro.user *.directory *.run plugins/* pgmodeler-0.9.2/CHANGELOG.md000066400000000000000000006345221360462764600153430ustar00rootroot00000000000000Change Log --------- v0.9.2 ------ Release date: December 26, 2019
* [New] Add support to data dictionaries generation in HTML format in ModelExportForm. * [New] Added options to control data dictionary generation in CLI. * [New] Plugins now can optionally be associated to a menu action or not. Generally, an plugin not associated to a menu action is automatilly executed during the startup (see PgModelerPlugin::initPlugin). * [New] Added a missing model fix step on CLI that removes the IN keyword from functions signatures. * [Change] Making BaseRelationship::getReferenceForeignKey() public. * [Change] Isolated duplicated code in MainWindow::isToolButtonsChecked that checks if any tool button of the bottom or right widget bars is checked. * [Change] Removing the plugins from core code. * [Change] Modified pgmodeler.pro to include plugins folder when present in the source root (either in debug or release mode). * [Change] Ignoring plugins folder in the core code. * [Change] Minor improvement on ModelWidget::rearrangeSchemasInGrid in order to consider the amount of tables to determine the minimum grid size used to rearrange table. * [Change] Minor text adjustments in CLI. * [Change] Added an additional checking during relationship creation in order to avoid the creation of 1-* or n-n relationships involving partition tables. * [Change] Removing the restriction to create 1-1, 1-n and n-n relationships in which the involved tables are partitioned ones. * [Change] Disabling the SQL statment ALTER...OWNER TO in the object's SQL when the owner role has its SQL disabled but the object itself not. This will avoid reference errors when validating/exporting code. * [Fix] Fixed the "Save" action enabled state according to the current model's modified state. * [Fix] Fixed a crash when the user tried to edit connections in ModelDatabaseDiffForm and right after select a connection in the "Compare to" field. * [Fix] Fixed the generation of escaped comments for columns. v0.9.2-beta2 ------ Release date: November 1st, 2019
* [New] Added support to foreign tables. * [New] Added the method DatabaseModel::getObject(QString,vector) to return the first ocurrency in the lists related to the provided types. * [New] Added support to select all foreign tables in ModelWidget. * [New] Created the method BaseTable::isBaseTable to help determining if an object type is of Table, View or ForeignTable. * [New] Added extra support to foreign tables on DatabaseExplorerWidget and DataManipulationForm. * [New] Added the method DatabaseImportHelper::createColumns in order to isolate the code to create table/foreign table columns during reverse engineering. * [New] Added support to foreign table importing as well its children objects (columns, constraints, triggers). * [New] Added server and options fields on TableWidget for foreign table. * [New] TableWidget now fully supporting the edition of foreign tables. * [New] Added the ability to TableView to render ForeignTable objects. * [New] Added support to swap objects ids using arrow keys by changing creation order between two close objects on the grid. * [New] Added support to save diff settings in form of presets. * [New] Added an option to BaseObject to force the comment escaping making multilined comments be presented as single lines but without changing their semantics. * [New] Adding support to parse escaped text delimiters and value separators in CSVLoadWidget. * [Change] Avoiding the usage of "Generate ALTER commands" option when the table is a partition or partitioned. * [Change] Avoid unchecking PK checkboxes on TableWidget when adding a new column. * [Change] Validating the dialogs geometry regarding to screens geometry in order to avoid their appearance in an invalid position (out of range). * [Change] Limiting the size of the exceptions stack in 50 elements. * [Change] Improved the GenericSQL::isObjectReferenced in order to check if, when a referenced object is a column, the provided object is the same as the parent of that referenced object. * [Change] Restricting the usage of "Default partition" option for partitioning relationships when the partition table is a foreign table. * [Change] Making ModelObjectsWidget update the foreign table subtree. * [Change] Making ReferenceWidget to use foreign tables from referenced table selector. * [Change] Improved the Relationship class to accept foreign tables. * [Change] Improved the DatabaseModel::getObjectDependecies and DatabaseModel::getObjectReferences to include ForeignTable. * [Change] Updated View class to accept reference foreign table columns. * [Change] Moved the original implementation of DatabaseModel::createTable to a template method createPhysicalTable in order to reuse it to create tables and foreign tables. * [Change] ForeignObject is not a BaseObject child anymore due to multi inheritance problem that it can generate in ForeignTable class. * [Change] Minor ajustment in Relationship class to accept PhysicalTable in its constructor so relationships can be used by ForeignTable class as well. * [Change] Isolated the code common to Table and ForeignTable classes in a parent class named PhysicalTable. * [Change] Disabling mime type update on installers. * [Change] Minor adjustment on SQLExecutionWidget::generateBuffer to escape line breaks and separators when generating CSV buffer. * [Change] Removing unused code from NumberedTextEditor. * [Change] Changed the way temp source file is handled by the tool in order to solve a sharing violation problem on Windows. * [Change] Minor adjustment on HtmlItemDelegate to avoid creating local variables in paint() everytime the method is called. * [Fix] Fixed an bug in SQL generation of columns that was wrongly removing a comma from decimal data types. * [Fix] Fixed some catalog queries in order to support PostgreSQL 12. * [Fix] Fixed ObjectsScene to remove foreign tables during destruction. * [Fix] Fixed the View::getObjectCount in order to return 0 when the provided object type is invalid. * [Fix] Fixed the ObjectFinderWidget in order to fade out correctly the listed/not listed elements. * [Fix] Fixed the quick actions menu at ModelWidget in order to include the "Edit data" action for foreing tables. * [Fix] Fixed the DatabaseImportHelper::assignSequencesToColumns in order to correctly assign sequences to foreign table columns. * [Fix] Fixed a crash in ModelValidationHelper that was caused by wrong checking when validating generic sql objects. * [Fix] Fixed the source code display for tables and foreign tables on DatabaseExplorerWidget. * [Fix] Fixed the CodeCompletionWidget to display foreign table children. * [Fix] Fixed the loading of generic SQL objects when a referenced object was a column. * [Fix] Additional fixes to correctly reference foreign tables and tables in the portions were both classes are acceptable/desirable. * [Fix] Fixed the diff process in order recognize partition foreign tables attach/detach. * [Fix] Fixed the generation of XML code of partitioning relationships. * [Fix] Fixed the Relationship::getAlterRelationshipDefinition to include foreign tables. * [Fix] Fixed the preset.sch since it was not registering the "Reuse sequences" options correctly. * [Fix] Improved the DataManipulationForm in order to restore the columns visibility when retrieving again the data of the current table. * [Fix] Fixed the drop action in DatabaseExplorerWidget for user mappings. * [Fix] Fixed the ModelWidget::rearrangeTablesInGrid to adjust position of foreign tables. * [Fix] Fixed the generation of SQL code of partition tables in order to avoid the inclusion of partitioned tables columns on the code. * [Fix] Fixed a crash on DatabaseImportHelper when destroying detached inherited columns. * [Fix] Fixed the object duplication operation in model widget to accept duplicate foreign table children objects. * [Fix] Fixed the creation of relationships involving foreign tables. * [Fix] Fixed the permission object in order to support foreign tables. * [Fix] Fixed the model export helper to support foreign tables. * [Fix] Fixed ModelWidget to show missing popup actions for foreign tables. * [Fix] Fixed the NewObjectOverlayWidget to display tool buttons related to foreign table children. * [Fix] Fixed the SchemaView::fetchChildren to include foreign tables in the returned list. * [Fix] Fixed the ModelValidationHelper to validate foreign tables and table-view relationships. * [Fix] Fixed ColumnWidget and ConstraintWidget to accept foreign tables usage. * [Fix] Fixed a regression when importing permissions related to functions. * [Fix] Fixed the OperationList to handle foreign tables. * [Fix] Fixed create methods in DatabaseModel related to table children object in order to accept foreign tables. * [Fix] Fixed the SwapIdsWidget postion/size saving and restoration. * [Fix] Minor tooltip fix in GeneralConfigWidget. * [Fix] Minor fix in default conf files removing unused tag attribute. * [Fix] Additional fix to the extension import to correctly indetify it as a data type handler. * [Fix] Fixed a bug on Role's SQL generation due to a missing attribute. * [Fix] Additional fix in GeneralConfigWidget to save correctly the settings of dockwidgets. * [Fix] Minor fix in DatabaseModel to write ddl end token in the appended/prepended custom code. * [Fix] Fixed a false-positive result when doing the diff between two fuctions that contains the same signature. * [Fix] Fixed the diff generation for Role objects when setting up an blank password. * [Fix] Fixed the "Prepend at the beggining of the model" option behavior on CustomSQLWidget. * [Fix] Fixed the catalog query for extension in order to indetify correctly if this object handles a data type. * [Fix] Fixed the Variadic option enabling on ParameterWidget. * [Fix] Fixed the saving of validator widget settings. There was a conflict between pgsql-ver attributes present on the validator settings and the default attribute added by the schema parser. The solution was to use a different attribute (version) in the validator. * [Fix] Fixed the "Clear items" action in popup menu at DataManipulationForm. * [Fix] Fixed the importing of tables and views in such way to automatically create correctly the domains referenced by their columns. * [Fix] Fixed a bug on ModelDatabaseDiffForm that was causing the form to be reseted on the middle of a diff process when the user minimize the diff dialog causing unexpected behavior (or even crashes sometimes). * [Fix] Minor fix in AboutWidget. * [Fix] Minor fix in ModelDatabaseDiffForm to avoid using uniform items height in output widget. v0.9.2-beta1 ------ Release date: September 2, 2019
* [New] Added a routine to write a backup file during the saving of model files in order to avoid data loss in some rare cases. * [New] Added a new action on DataManipulationForm to clear the selected items by pressing Ctrl+R. * [New] Enabling/disabling the save model action according to the model's modified status. * [New] The main window instance is now exposed to plugins to make the extra features development more flexible. * [New] Avoiding selecting table items in BaseTableView::mousePressEvent which doens't contain an underlying (source) object. * [New] Adding support to duplicate several table objects at once. * [New] Added support to table children multiselection by using Ctrl+Shift+Click on them. * [New] Added support to load the generated diff code in the SQL tool and automatically browsing the destination server for manual diff applying. * [New] Added a button to create a new data manipulation form from within another data manipulation form. * [New] Added a confirmation message before closing a database explorer widget. * [Change] Minor adjustments in PgModelerUiNs::createOutputListItem and PgModelerUiNs::createOutputTreeItem to better display formatted messages. * [Change] Minor improvement on CSV text copying to exclude from the buffer the hidden columns. * [Change] Adjusted the font weight on WelcomeWidget (only for Linux). * [Change] Minor adjustment on tool buttons font size on DataManipulationForm. * [Change] Improved the UI of the DataManipulationForm by rearranging the tool buttons to the left of the dialog. * [Change] Improved the clipboard text pasting on DataManipulationForm in order to parse the text as CSV when Ctrl+Shift+V is pressed. * [Change] The filter input on SQLExecutionWidget is now automatically focused when toggling the filter widget. * [Change] Changed the default behavior of result set filtering to Qt::MatchContains on SQLExecutionWidget. * [Change] Avoiding showing the "Swap ids" action in popup menu when we have only columns/constraints selected * [Change] Minor adjustment on SceneInfoWidget to avoid display dimensions of selected columns/constraints on the canvas. * [Change] Renamed the method BaseGraphicObject::getReceiverObject to getOverlyingObject (to make sense with its counter part BaseObjctView::getUnderlyingObject) * [Change] Avoiding clear the whole scene selection when the table is already selected and the user requested popup menu. * [Change] Renamed BaseObjectView::getSourceObject to getUnderlyingObject. * [Change] Improved the object protection action in ModelWidget in order to accept the multi item selection on tables. * [Change] Changed the way the PSVI attribute is handled in xmlparser to retrieve big line numbers on a xml document. * [Change] Improved the diff code preview allowing the user to close the dialog without going back to previous tab and click 'Cancel'. * [Change] Minor adjustment on buttons shortcuts/tooltips on DataManipulationForm. * [Change] Changed the way the model saving timers are controlled to avoid infinity savings on the model (when the auto saving option is disabled) making the application unusable. * [Change] Making the mime update operation return exit code 0 even if there was errors (still displayed in the console). This will avoid the installer to abort installation when the dbm mime update fails. * [Change] Avoiding applying fillfactor to gin indexes. * [Change] Moved the method DatabaseImportHelper::parseIndexExpressions to Catalog class. * [Fix] Fixed a broken diff code generation for policies. * [Fix] Fixed the object duplication action when only a single table object is selected. * [Fix] Fixed a bug in ModelWidget::removeObjects that was causing the removal of relationship added columns * [Fix] Fixed the ModelWidget::configurePopupMenu to consider the table's multi item selection. * [Fix] Fixed a false-positive diff result when dealing with timestamptz. * [Fix] Fixed the progress calculation of dbm files loading. * [Fix] Fixed a bug that was causing the generation of broken view code. * [Fix] Fixed the display of index expressions on DatabaseExplorerWidget. * [Fix] Minor fix on SQLExecutionWidget to avoid results grid to overlap command execution history widget in certain cases. v0.9.2-beta ------ Release date: May 31, 2019
* [New] Added support to user mapping. * [New] Added support to foreign server. * [New] Added support to foreign data wrapper. * [New] Added support to reduced verbosity on diff, export and import processes in order to improve performance. * [New] Adding missing tootip on ObjectFinderWidget. * [New] Generic SQL objects now support dynamic references to objects which can be used in the definition code. * [New] Added support to compare foreign servers on diff process. * [New] Created a generic getAlterDefinition on ForeignObject. * [New] Added ForeignServer toolbutton in NewObjectOverlayWidget. * [New] Added support to the reverse engineering user mapping objects. * [New] Added support to the reverse engineering foreign server objects. * [New] Added code snippets for foreign data wrapper and foreign server. * [New] Added support to diff user mapping. * [New] Added support to diff foreign data wrappers. * [New] Added support to set permissions to foreign data wrapper. * [New] Added the WRAPPER, SERVER and MAPPING key words to sql-highlight.conf. * [New] Added the method PgSqlType::isExactTo in order to do a full comparison (all attributes) between two data types. * [New] Added the ability to view references to store referenced tables. This feature will cause relationships to be created between the view and the referenced tables. This is useful when we're using reverse engineering feature in which, in previous versions, couldn't determine the tables that were linked to a view. Now, with this feature a relationship is created between the view and all involved tables. * [New] Added missing data type macaddr8. * [New] Enabling quick clear button on several input fields. * [New] Added support to result set filtering in the SQL execution widget. * [New] Adding a column labeled "Comment" in TableWidget and ViewWidget to hold comments of children objects. * [Change] Changed the shortcut of run SQL action in SQLExecutionWidget to F5. * [Change] Changed the shortcut of tree update action in DatabaseExplorerWidget to F6. * [Change] Change "New object" action in popup menu in order categorize object types when clicking the database object diminishing the amount of items displayed on the screen. * [Change] Improved the object search mechanism in such way that various attributes of the object can be matched. New searchable attribute may be added in the future. * [Change] Added missing code documentation. * [Change] Minor adjustment on ForeignDataWrapper::getAlterDefinition. * [Change] Minor improvement on ModelDatabaseDiffForm to show the connection id of the databases being imported in the output tree. * [Change] Formatting server objects' attributes on DatabaseExplorerWidget. * [Change] Minor adjustments on the icons of the buttons in ObjectsTableWidget. * [Change] Improved the method DatabaseModel::getObjectReferences to detected foreign data wrappers as functions' references. * [Change] Minor code refactoring on Table and View classes. * [Change] Renamed the method Exception::getErrorType to Exception::getErrorCode. * [Change] Improved the ModelValidationWidget in such way that is possible to operate over objects on the output list through their respective context menu (the same as in the ModelWidget). * [Change] Now its possible to trigger the swap ids dialog for two selected objects, causing their ids to be swapped more quickly. * [Change] Minor refactor on schema files. * [Change] Minor attributes refactoring on several classes. * [Change] Minor change in the PgSqlType constructor by turning some parameters optional in order to facilitate the creation of array only types. * [Change] Minor update on disclaimer text at start of the source files. * [Change] Allowing copied object to be pasted multiple times. This feature works only with copy/paste operation without remove the pasted objects from the clipboard, for cut/paste the behaviour is unchanged. * [Change] Increased the maximum limit of SQL history. * [Change] Updated the windeploy.sh and the installer scripts. * [Change] Adjusted the installer scripts. * [Change] Changed the windows deploy script to use Qt Installer Framework. * [Change] Adjusted the deploy script to use Qt 5.12. * [Change] Fixed the windows deploy script to use newer version of the compiler in 64 bits environment. * [Change] Minor improvements in SQLToolWidget and SQLExecutionWidget to avoid segmentation faults when trying to close a execution tab while the command is still running. * [Change] Adjusted the resize parameters in DataManipulationForm to avoid wrong dialog resizings mainly on Windows. * [Fix] Fixed a bug in DataManipulationForm that was deleting new rows wrongly. * [Fix] Fixed a bug that was causing domain constraints not to be extracted correctly during reverse engineering. * [Fix] Fixed a bug that was causing a fk relationship not to be deleted if the fk tied to it was changed by the user. * [Fix] Fixed a bug on CLI that was not fixing broken models correctly when they had no role declaration. * [Fix] Fixed a bug that was causing tables not to be moved on the canvas using mouse. * [Fix] Fixed a crash related to destruction of special objects on DatabaseModel::destroyObjects. * [Fix] Fixed a bug that could crash the application when no language was specified to a funcion and the SQL/XML code was being generated. * [Fix] Minor fix a bug on index importing. * [Fix] Minor fix on View::isReferencingTable. * [Fix] Fixed a crash when a query executed in SQLExecutionWidget was a DDL one or was not returning results. * [Fix] Fixed a bug in CLI that was failing to fix model in certain cases. * [Fix] Minor fix on buttons tooltips. * [Fix] Fixed a bug that was causing syntax error if the last column of a table had the SQL code disabled. * [Fix] Fixed a bug on diff process due to a missing attribute on the generation of diff code for inheritance relationships. * [Fix] Fixed a bug when rendering several self relationships attached to the same table. * [Fix] Fixed the CLI in order to restore the layers information when fixing a broken model. * [Fix] Fixed a bug in object finder that was causing objects from a hidden layer to be displayed causing inconsistency on the layer state. v0.9.2-alpha1 ------ Release date: December 17, 2018
* [New] Added support to scene layers. * [New] Added support to view's columns importing in DatabaseImportHelper. * [New] Added the ability to load view columns from database model file in DatabaseModel::createView. * [New] Added a tab "Columns" in ReferenceWidget where the user will be able to insert columns to be used as view columns. * [New] Added support to pagination of tables and views columns pagination. * [New] Added a pagination toggler action on context menu at ModelWidget. * [New] Added a fix step on CLI to remove the deprecated attribute hide-ext-attribs from tables and views xml code. * [New] Added a configuration option to control attributes per pages in tables and views. * [New] Added support to save collapsing states and current attributes pages to the database model file. * [New] Added constants to reference child objects of TableObjectView. * [New] Added the class TextPolygonItem which can be used to draw a text over a background polygon. * [New] Added support to OLD/NEW tables aliases on triggers. * [New] Added a hint text on RelationshipWidget to document the correct usage of default partitions. * [New] Added support for partition attaching/detaching detection in diff process. * [New] Added auxiliary methods in Table class in order to add/remove and retrieve partition tables. * [New] Added support to importing partitioned/partition tables on DatabaseImportHelper. * [New] Added a missing validation in Relationship to avoid creating other types of relationships involving partitioned or partition tables. * [New] Added support to specify partition bounding expression on partitioning relationships. * [New] Added support to resize grid cells to fit contents on ObjectsTableWidget. * [New] Added a tab "Partition keys" that will handle partitioning configuration on TableWidget. * [New] Added a method in ObjectsTableWidget to hide some horizontal header sections. * [New] Added some validations when creating partitioning relationships. * [New] Added support to hide columns on data manipulation dialog. * [New] Added a transient attribute to objects DatabaseModel, Table and View in order to give a hint on the maximum count of objects held. This attribute is used to preallocate the vectors which store the children objects in order to avoid excessive memory allocation/deallocation due to vector resizing. * [New] Added a column labeled "Alias" on all objects tables in TableWidget so the aliases of children can be displayed. * [New] Added support to adding tabs via shortcut or corner button in the SQL Execution panel. * [Change] Minor adjustments on MainWindow to make the overview widget to update its contents whenever the active layers change on the current model. * [Change] Minor adjusment in ObjectsScene::addItem to make the item (in)visible according to the visibility of its related layer. * [Change] Minor fix in AttributesTogglerItem in order to consider the parent's opacity during painting. * [Change] Minor fixes in OperationList in order to force views to be updated correctly when operating over a table which is referenced by those objects. * [Change] Minor adjustments on SchemaView and BaseTableView (and its children classes) to update the geometry when they switch from invisble to visible state. * [Change] Changed views in such way so they can use the struct SimpleColumn to represent their deduced columns. * [Change] Improved the update of views when referenced columns and tables change their structure. * [Change] Improved database model loading times by avoiding the rendering of tables while the children objects (indexes, trigger, rules, etc) are being added. * [Change] Removed the several operators ~ overloading that statically cast enums to their underlying type and created a template function called enum_cast in C++14 syntax. * [Change] The zoom in/out level is now sensible on how much the user rolls the mouse wheel. * [Change] Move the default implementation of configureObjectShadow and configureObjectSelection from BaseObjectView to BaseTableView. * [Change] Disabling configureObjectSelection and configureObjectShadow on TableObjectView and RelationshipView. * [Change] Minor adjustment on protected icon position on TableTitleView and TextboxView. * [Change] Minor performance adjustments in ModelWidget. * [Change] Minor improvement in TextboxView to use only a TextPolygonItem to hold text and the object's rectangle instead of a box and a text items. * [Change] Replaced the sql_info_txt and sql_info_box items by a single instance of TextPolygonItem to denote SQL disabled status. * [Change] Replace the tag_body and tag_name elements on BaseTableView by the tag_item which is a instance of TextPolygonItem. * [Change] Improved the TableObjectView to avoid adding extra scene items. * [Change] Improved the TableTitleView to avoid adding children items. A custom paint() method now draws them. * [Change] Removing unused fr_FR UI translations. * [Change] Minor update on known issues sections at README.md. * [Change] Renamed the namespace ParsersAttributes to Attributes and its attributes has been refactored. * [Change] Refactored all static const attributes of the classes present in pgsqltypes.h. * [Change] Renamed PgModelerNS to PgModelerNs. * [Change] Renamed PgModelerUiNs to PgModelerUiNs. * [Change] Renamed XMLParser to XmlParser. * [Change] Removing uneeded temporary QString instance created from Exception::getErroMessage call before throwing exceptions. * [Change] Refactored static const attributes of BaseObject. * [Change] Refactored the items in the enum ObjectType by removing the prefix 'OBJ'. * [Change] The enums ErrorType and ObjectType were transformed into scoped enums. Also the ErrorType enum was renamed to ErrorCode. * [Change] Code refactoring done in order to make it more close to C++14 in order to take advantage of new features introduced by that standard. * [Change] Removed unused labels and fixed warning frame on ModelWidget. * [Change] Minor improvements on table's attributes displaying on DatabaseExplorerWidget. * [Change] Improved the diff process in such way to avoid generating unnecessary/noise commands related to changing types of columns to integer and setting nextval() call as default value. * [Change] Partition tables are now displayed in the "Tables" tab at TableWidget. * [Change] Removed the cached catalog query test feature from Catalog. * [Change] Fine tuning on the validation of the entities used in the partitioning relationship creation. * [Change] Forcing the partitioning relationship to be invalidated when the reference table (partitioned) partitioning type is set to null (no partitioning). * [Change] Move the FK settings, copy options and name patterns group boxes to a dedicated tab on RelationshipWidget. * [Change] Improved the models destruction when closing the application. * [Change] Improved the Index/Exclude/ParitionKey elements handling by creating a generic form/grid that handles these kinds of objects (ElementsTableWidget). * [Change] Modified the RelationshipWidget in order to handle partitioning relationships. * [Change] Modified RelationshipConfigWidget in order to write name partterns for partitioning relationships. * [Change] Improved the column copying and validation on class Relationship to include partitioning relationship logics. * [Change] Improved the reverse engineering performance by avoiding update relationships as they are being imported. * [Change] Improved the object duplication feature in ModelWidget. * [Change] When the model is loaded it is copied to the temporary models storage as a first version of the temporary dbm file. * [Change] Simplified the temporary models saving process by removing the thread that was controlling it. Actually the thread was unnacessary because the process was being executed in the main thread no matter if there was another thread to control the saving. * [Change] Minor adjustment on the hint text resizing. * [Change] Increasing to 5 minutes the period in which the temporary model saving will be executed. * [Change] pgModeler will now use the official docs url in the help buttons. * [Fix] Fixed a minor bug that was preventing the copy action to be enabled in DataManipulationForm. * [Fix] Fixed some sample models to remove deprecated attributes. * [Fix] Fixed a crash while renaming view's children objects. * [Fix] Fixed the rendering of views which contain only a single reference that is the whole object's defintion. * [Fix] Fixed the column name deduction for recursive views. * [Fix] Fixed a bug that was causing crashes while configure new constraints on tables. * [Fix] Fixed the view's resizing. * [Fix] Fixed a regression in schema's rectangle selection. * [Fix] Fixed the StyledTextboxView bounding rectangle. * [Fix] Fixed an artifact when user switched on and off the compact view. * [Fix] Fixed the Linux deploy script. * [Fix] Fixed the macOs deploy script. * [Fix] Fixed some compilation problems on macOs due to the usage of C++14. * [Fix] Fixed some compilation problems on Windows due to the usage of C++14. * [Fix] Fixed a bug in DatabaseModel::destroyObjects that could lead to segfault when the destroyed model had permissions on it. * [Fix] Fixed a bug when importing columns which data types is some user defined type in form of array, e.g., custom_type[]. * [Fix] Fixed a bug in SchemaParser that was causing only the first %set line in a if block to be parsed no matter that there were others %set below the same block. * [Fix] Fixed the tooltip of some graphical objects by adding their comments and aliases. * [Fix] Fixed the catalog query for tables to select partitioned tables correctly. * [Fix] Fixed the catalog query for types to avoid selecting partitioned tables as being data types. * [Fix] Fixed a bug that was causing special primary key configured on a relationship to make the original primary key of the table to disappear after disconnect the relationship. Now pgModeler stores in memory the original PK prior the connection of relationship and creation of the special PK. When disconnected the relationship, the original primary key is restored on its parent table. * [Fix] Fixed the creation of elements (index, exclude, patition key) on DatabaseModel. * [Fix] Fixed the class Relationship to reuse compatible columns when handling partitioning relationships. * [Fix] Fixed the diff process in such way to create new columns with their respective COMMENT ON statement when present. * [Fix] Fixed the detection of comment changes for columns on diff process. * [Fix] Fixed the order of recent models saved on the file pgmodeler.conf. * [Fix] Fixed a bug when creating a view reference as the whole view definition. * [Fix] Minor tooltip fix on DatabaseExplorerWidget. * [Fix] Making pgModeler honor the columns arrangement in primary keys. * [Fix] Fixed a bug that was causing FK relationship deletion to crash the application sometimes. * [Fix] Some fixes were done in the ModelOverviewWidget in order to support large models without exceed the screen size when configuring the size of the overall widget. * [Fix] Fixes a bad erase in View::removeReference. * [Fix] Fixed some bugs related to dialog size restoration in DataManipulationForm and TableWidget. v0.9.2-alpha ------ Release date: August 20, 2018
* [New] Added the support to cancelling SQL execution in SQLExecutionWidget. * [New] Added support to save/restore the dialogs sizes and positions. * [New] Added support to truncate tables in DataManipulationForm. * [New] Added support to aliases on some graphical objects that is used in the compact view mode. * [New] Added support to save/load object's metadata containing aliases information. * [New] Added support to compact view of the model where graphical objects can have a more friendly name for a reduced view as well for those who don't need to see details about tables (clients of the business, for instance). * [New] Added support to sequence options for identity columns. * [New] Added the ability to paste CSV text from clipboard into the TableDataWidget. * [New] Added support to bulk data edit in TableDataWidget. * [Change] Added missing copy options on copy relationships. * [Change] Minor adjustments on the item delegates in order draw text in the right alignment. * [Change] Minor adjustment on buttons style in DatabaseExplorerWidget, DataManipulationForm and SQLExecutionWidget. * [Change] Minor adjustment on OperationList::removeFromPool to avoid throw an exception when an invalid index is passed. * [Change] Changed the behaviour of the fade in/out of relationships linked to a table by applying the effect on the other tables that are related to the selected one. * [Change] Refactored the view editing dialog by moving the references handling form to a dedicated modal dialog. * [Change] Improved the model loading from file by blocking signals of relationships avoiding excessive/repetive rendering of objects. The whole model is fully rendered when the file was completely loaded. * [Change] Minor adjustment on constraints rendering at extended attributes section of tables. * [Change] French translation update. * [Change] Updated the other lang dictionaries with the new text brought by new releases. * [Change] Removing icons at the top of the dialogs: DatabaseImportForm, MetaDataHandlingForm, ModelDatabaseDiffForm, ModelExportForm, ModelFixForm. * [Change] Minor adjustments in the features of the demo version. * [Change] Minor adjustments in the UI stylesheet. * [Change] In DatabaseExplorerWidget the root item will come automatically selcted when browsing a database. * [Change] Minor performance tuning when handling big models. * [Change] Added some statistics attributes for tables on DatabaseExplorerWidget. * [Change] Minor adjustment in NewObjectOverlayWidget by putting the tool buttons under categories. * [Fix] Fixed a bug in ObjectFinderWidget that was forcing schemas rectangles to appear even if the flag indicating them to be visible was set to false. * [Fix] Fixed the editing form cancel operation. Now operations done when the form was active are undone correctly. * [Fix] Fixed a bug that was preventing to create a view containing the same name as a table but in different schema. * [Fix] Fixed a regression that caused notices not to be shown in the output panel at SQLExecutionWidget. * [Fix] Fixed the query catalog for policies which was causing syntax error when combining import system objects and extension objects options. * [Fix] Fixed the disabling of some actions related to design when switching to manage view. * [Fix] Minor fix on stylesheet in order to display the extended button on general toolbar. * [Fix] Fix a shortcut conflict in DataManipulationform. * [Fix] Fixed the offset of strings composing the StorageType. * [Fix] Minor form size adjustments. * [Fix] Minor fix in sqlexecutionwidget.ui to force the exhibition of grid headers * [Fix] Minor fix in SQLExecutionWidget allowing the output widget to be resized to a size lower than the default one. * [Fix] Fixed the tab order in PolicyWidget. * [Fix] Fixed the generation of Database object source in DatabaseExplorerWidget. * [Fix] Fixed the method BaseObjectWidget::setRequiredField to make object selector fields as required correctly. * [Fix] Minor fix in HintTextWidget to stay on top of all widget when being displayed. * [Fix] Fixed a bug that was not quoting extension name when needed. * [Fix] Fixed a crash when trying to remove a fk relationship when it was created from a foreign key which references protected columns (added by relationship). * [Fix] Fix a crash when importing CSV files into DataManipulationForm. * [Fix] Minor typo in TableDataWidget. * [Fix] Minor fix on schema file sql/table.sch. v0.9.1 ------ Release date: May 14, 2018
* [New] Added support to line selection by clicking and moving the mouse over the line numbers widget in any source code field. * [New] The validator now checks if the model has columns referencing spatial data types and creates the postgis extension automatically when fixing the model. * [New] Added support to RESTART IDENTITY on truncate tables in DatabaseExplorerWidget. * [New] Added an custom option checkbox in Messagebox for general purpose usage. * [New] Added support to diff operation in CLI. * [New] Added support to import database from CLI. * [New] Adding missing types regrole and regnamespace. * [Change] Improved the copy/duplicate operation in order to copy rules, index, trigger and policies together to their parents. * [Change] Added column names to the code completion widget used in the filter widget at DataManipulationForm. * [Change] Improved the SQLExecutionWidget in such way that it'll display large amount of data more quickly and consuming less memory. * [Change] Minor improvement in SQLExecutionWidget to show the amount of time took to run a query. * [Change] Minor improvement in the text find widgets in SQL tool in order to make them closable via dedicated button. * [Change] Improved the set tag operation in ModelWidget in order to cleanup the assigned tags to a set of objects. * [Change] Minor improvement on DatabaseExplorerWidget to show the rls attributes labels correctly in the attributes grid. * [Change] Refactored all the CLI options. * [Change] Minor change in Connection::generateConnectionString in order to put the dbname param in the start of the string. * [Change] Improved the performance of the row duplication action in DataManipulationForm. * [Change] Minor improvement in order to update the schemas boxes when the tables have their extended attributes box toggled. * [Change] Improved the performance of "Move to schema" operation. * [Change] Added an busy cursor while closing a model. * [Change] Improved the object selection in object finder. * [Change] Changed the behaviour of select and fade buttons in ObjectFinderWidget in such way to enable the user to select/fade the objects in the listing (or not included in the results). * [Fix] Fixed a bug when import identity columns in certain cases when the identity column was followed by another column which data type was not accepted for identity, e.g, text after smallint. * [Fix] Fixed the check boxes disabling when dealing with identifier relationships. * [Fix] Disabled the drag & drop for items in the side listing at ConfigurationForm. * [Fix] Fixed the tab behavior on comment box in all editing forms of database objects. * [Fix] Fixed the catalog query for user defined types. * [Fix] Fixed the import of user defined types which names contains uppercase characters. * [Fix] Minor typo fixes in CLI. * [Fix] Fix window scaling on HiDPI/Retina screens. * [Fix] Minor fix in Connection::getConnectionId in order to omit port when that parameter is not configured in the connection. * [Fix] Fixed a bug in ModelExportHelper that was failing to remane the database when the command appeared. * [Fix] Fixed a bug in CollationWidget that was referencing the collation attributes LC_??? using the wrong constant. * [Fix] Fixed the behaviour of the message box that warns about the need of validate the model prior to export, save or diff. Now rejecting the dialog (i.e. closing it) will be considered that the user wants to proceed with the pending operation even with an invalid model. * [Fix] Fixed the import of comments for constraints,triggers, index and rules. * [Fix] The value input in BulkDataEditWidget will be focused as soon as the widget appears. * [Fix] Fixed a bug in the aggregate import process. * [Fix] Minor fix in DataManipulationForm to avoid the generation of a where clause when the filter is filled only with spaces. * [Fix] Minor fix in the magnfier tool to use the same render hints as the canvas viewport. * [Fix] Fixed a bug in the diff process that was trying to recreate the whole database when the "Force recreation" option was set. * [Fix] Fixed a bug when showing the source of tables in DatabaseExplorerWidget when these objects have permissions assigned. * [Fix] Adjusting tables position when the parent schema is moved and the alignment to grid is enabled. * [Fix] Minor fix in the CLI menu. * [Fix] Fixed the saving process for large models by stopping the threads related to temp models saving while the model file is being written. v0.9.1-beta1 ------ Release date: April 6, 2018
* [New] Added the ability to create multiples one-to-many and many-to-many relatationships between the same pair of tables. * [New] Added the ability to use more special ascii chars in the middle of object names. * [New] Added missing SQL keywords into sql-highlight.conf * [New] Added support to multi line comments in UI. * [New] Added code snippets for CREATE and ALTER policy. * [New] Added full support to row level security (RLS), including export, import and diff of this kind of object. * [New] Added the method DatabaseExplorerWidget::formatPolicyAttribs in order to display some attributes values correctly. * [New] Added support to bulk data editing in DataManipulationForm. * [New] Added an option to diff process to force the generation of DROP commands for columns and constraints even if the missing objects need to be preserved. This is useful to work with partial models and the user need to remove columns/constraints and preserve the rest of objects. * [New] Added the ability to generate diff code to Enable/Force RLS attribute of tables. * [New] Added support to RLS on tables. * [New] Added the support to detect identity columns in diff. * [New] Added support to identity columns (PostgreSQL 10). * [New] Added the support to BYPASSRLS option on roles. * [New] Added support to IS_TEMPLATE and ALLOW_CONNECTIONS options in database object. * [New] Added the procedures to fix old style domains in CLI. * [New] Added support to multiple check constraint in domains. * [New] Added support to sort items alphabetically (ascending) or by oid in DatabaseExplorerWidget. * [Change] Changed the input mode of the password field in ConnectionsConfigWidget in order to hide the passwords in the form. NOTE: the passwords are still in plain text in the config file. * [Change] Moved extensions from schema level to database level in order to reproduce better the PostgreSQL's behavior. * [Change] The filter widget is now toggled in DatabaseExplorerWidget via filter menu. * [Change] Minor adjustments on forms sizes. * [Change] In GeneralConfigWidget when restoring default settings the default settings for syntax highlight are restored as well. * [Change] pgModeler will not try to create the plugins path anymore. This will avoid constant error messages during startup. Now, it'll silently ignore the absence of that folder and skip the plugin loading. * [Change] Minor improvements on catalog queries for index, trigger, rule, policy, constraint in order to use the comment catalog query. * [Change] Removed an uneeded form adjustment code in Table::openEditingForm. * [Change] Minor improvements on DatabaseModel::getCreationOrder. * [Change] Improved the source editing in external application. The use is informed about the app running state and the contents for the source editor field are locked until the user closes the external app. * [Change] Improved the model loading on macOs in such way to avoid showing the visual objects creation while they are being loaded from file. * [Change] Improved the reverse engineering and diff process to accept the new attributes of database object. * [Fix] Fixed the query catalog for built-in types to include the types related to domains. * [Fix] Fixed the Extension::setSchema method to accept null schemas. * [Fix] Fixed the generation of XML code for casts. * [Fix] Fixed the extension creation, allowing only one instance of the named extension per database no matter the schema used to allocate its children objects. * [Fix] Minor fix in ObjectDepsRefsWidget to correctly list the indirect references. * [Fix] Fixed a bug when dropping Functions in DatabaseExplorerWidget. * [Fix] Improved the import of sequences in such way to avoid unsolvable reference breaking. * [Fix] Fixed a bug that cause the disabling of connections for database models created prior to 0.9.1-beta1. * [Fix] Fixed a bug on import process that was wrongly creating types derivated from tables/sequence/views causing duplication problems during validation. * [Fix] Fixed a crash on macOs when opening a second model. * [Fix] Fixed the import of sequences which now assigns owner columns correctly. If the owner column is an identity one the SQL code of the sequence is disabled by default which will not cause confusion in the diff process trying to drop it in some cases. * [Fix] Fixed an issue in diff process that was generating a malformed DROP command for extensions. * [Fix] Minor fixed in the "Filter by OID" feature in DatabaseExplorerWidget and DatabaseImportForm. * [Fix] Fixed the diff for domains which contain multiple check constraints. * [Fix] Fixed a bug that was not selecting the correct spatial type in the widget. * [Fix] Fixed a conflict of shortcuts in DatabaseExplorerWidget. Now F5 updates a leaf/subtree and Alt+F5 performs quick refresh of the tree. * [Fix] Fixed a problem with sqlexecutionwidget.ui that is not building properly in Qt 5.10. v0.9.1-beta ------ Release date: January 26, 2018
* [New] Added support to GROUP BY/HAVING clauses in Views by adding a new kind of reference. Proper changes done in ViewWidget to allow configuring those clauses. * [New] Added the method Catalog::isSystemObject(oid) which indicates if the provided OID is related to a system object. * [Change] Minor adjustment in the copy/paste operation to generate suffix in the pasted objects only when there're conflics. * [Change] Removed the port range limitation in connection configuration dialog. * [Change] Updated the default version of Qt and PostgreSQL to, respectively, 5.9.3 and 10.1 in deployment scripts. * [Change] Changed the method PgSQLType::getTypeName by adding a bool parameter so the name can be returned with dimension descriptor (when dimension is > 0). Useful for configuring operator's signatures. * [Fix] Fixed the drop action for materialized views in database explorer. * [Fix] Fixed a crash when importing extension objects. * [Fix] Fixed the generation of operator's signature that must consider dimensions of the arguments' types. * [Fix] Fixed the bounding rect calculation for relationship instances when one or more labels are hidden. * [Fix] Fixed the SVG & PNG export to properly determine the area to be drawn in the destination graphics file. * [Fix] Fixed a crash when adding attributes into many-to-many relationships. v0.9.1-alpha1 ------ Release date: November 30, 2017
* [New] Added the ability to compare two databases, and not only a model and a database, in diff tool. * [New] Added the relationship creation buttons on the object overlay when a single table is selected. * [New] Added the "Relationship" action in "New" submenu on table's popup menu so the user can create relationships using the selected table as source. This avoids the need to use blank areas of the canvas to start creating relationships. * [New] Improved the data manipulation dialog in such way that when dealing with deletes in tables without PK, tuples with NULL values can be correctly considered. * [New] Improved the validations on ResultSet class. * [New] Added a method to indicate if a column value is null in ResultSet. * [New] Added support to fade in/out objects in object finder in order to highlight the graphical objects retrieved from the search. * [New] Added an attribute in pgmodeler.conf to store the current status of the "Fade in" button in object finder widget. * [Change] Minor improvement in the diff generated metadata. * [Change] Increased the maximum allowed amount of lines in command history. * [Change] Minor adjustment on diff tool so the connections combo can be correctly updated when the user edit connections from within that form. * [Change] Improved the progress info of diff process so it can be more accurate. * [Fix] Fixed the way PostgreSQL 10+ version is returned from Connection::getPgSQLVersion. * [Fix] Fixed the sequence importing on PostgreSQL 10. v0.9.1-alpha ------ Release date: October 20, 2017
* [New] Added support to crow's foot notation. * [New] Added the crow's foot notation switch in RelationshipConfigWidget. * [New] Added the grid arrangement in the arrangment menu at MainWindow. * [New] Added the schema arrangement (scattered). * [New] Added an action to toggle schemas rectangle on ModelWidget. * [New] CLI now loads the relationship and general settings to reflect relationship styles in export modes. * [New] Added support to connect relatinship on tables' edges when using classical notation. * [New] Added support to apostrophes in the middle of object's name. * [Change] Removed the controls related to arragement in DatabaseImportForm. * [Change] Minor adjustments in tables' spacing in auto arrangement process. * [Change] Minor improvement on SQLExecutionWidget and DataManipulationForm in order to make possible to paste csv buffer from SQLExecutionWidget to DataManipulationForm. * [Change] Improvements done in the Spanish UI translation. * [Change] Changed the position of the zoom info icon in SceneInfoWidget. * [Change] Minor adjustments in the pen width of relationship lines and objects borders. * [Change] Minor improvement when aligning objects to grid forcing the relationships updating. * [Change] Minor arrangement of the connection modes in RelationshipConfigWidget. * [Change] Improved the performance of (de)selection of several objects at once in ModelWidget and ObjectsScene. * [Change] Removed unused attributes from BezierCurveItem. * [Change] Improved the BezierCurveItem class to enable the drawing of inverted curve by inverting its bounding rect. * [Change] Improved the import of index objects. * [Change] Minor tweak to enable clipboard usage in macOS when copying data in DataManipulationForm. * [Fix] Fixed a bug in ObjectsScene that was not emitting signals of deselection correctly. * [Fix] Fixed a bug in SQLToolWidget that was not cleaning up the source code pane when all databases were disconnected. * [Fix] Fixed a bug that was causing the diff process to try to remove the not null constraint of a primary key. * [Fix] Fixed a bug that was causing relationship line to be wrongly constructed in case the tables bounding rects don't intercepted. * [Fix] Fixed a bug that was recognizing the creation of a constraint but wasn't generating the SQL in diff process. * [Fix] Minor fix in order to avoid the inheritance/dependency descriptor to be rotated to the wrong size when curved lines are being used. * [Fix] Fixed the generation of sql comments for database and tablespace. * [Fix] Minor fix in example.dbm * [Fix] Fixed the configuration of bidirectional fk relationships when crow's foot is enabled. * [Fix] Fix a bug in GeneralConfigWidget that was reverting the grid optins everytime the user applyed settings. * [Fix] Fixed the genaration of index elements containing expressions. * [Fix] Fixed the import of operators and operator classes. * [Fix] Fixed the generation of operator signature by removing the length/precision of the types. * [Fix] Minor fix in CSVLoadWidget::loadCsvFromBuffer in order to preserve the line breaks avoiding the creation of unecessary lines. * [Fix] Fixed the import of exclude constraint. * [Fix] Fixed the import of timestamp(0) type. v0.9.0 ------ Release date: September 1st, 2017
* [New] Added the ability to paste text from clipboard to data grid in DataManipulationForm. * [New] Created the method CsvLoadWidget::loadCsvFromBuffer to make the code that extract csv document from string buffer reusable by other classes. * [New] Added a new sample model donated by the maintainers of 3D City DB project. * [New] Added the language "internal" to the set of system languages available when creating a new model. * [New] Added support to override the default language settings via GeneralConfigWidget. * [New] Added support to toggle curved relationship lines in GeneralConfigWidget. * [Change] Improved the MetadataHandlingForm enabling user to only extract metada to a backup file. * [Change] Small update on sample models. * [Change] Minor adjustments in the graphical points when relationships are selected. * [Change] Adjusted the calculation of the descriptor object. * [Change] Fixed the rotation of the descriptor object for identifier relationship when curved lines are activated. * [Change] Minor code documentation. * [Change] Moved the class BezierCurve to its own source files. * [Change] Improved the way bezier curves are generated for relationships. * [Change] Changed the default action to reset label's position from middle button click to Alt + Ctrl + left click. * [Change] Minor enhancement in auto arrange feature to avoid breaking lines when curved relationship lines are enabled. * [Change] Minor size adjustment in GeneralConfigWidget. * [Change] Minor update in README.md. * [Change] Minor size adjustment for DatabaseImportForm. * [Change] Minor adjustment in the methods which automatically resize dialogs depending on the resolution. * [Change] Changed the default font for objects and source code. * [Fix] Minor fix in RelationshipView to hide the circles at end of lines for self relationships. * [Fix] Fixed the catalog query for event triggers. * [Fix] Fixed the icons and labels of the "Select all" submenu in ModelWidget. * [Fix] Fixed a rare crash when configuring self relationships. * [Fix] Minor fix when rendering self n:n relationships. * [Fix] Minor fix in the HintTextWidget to resize more properly according to the held text. * [Fix] Minor adjustment in SceneInfoWidget. * [Fix] Minor fix in default confs for source code font style. * [Fix] Fixed the generation of objects style configuration file that was missing constraints settings. * [Fix] Fixed a bug in the index / exclude constraint import which was not creating expressions of these objects correctly and sometimes trucating them. v0.9.0-beta2 ------ Release date: July 1st, 2017
* [New] Added an action to reset labels distance in BaseRelationship and ModelWidget. * [New] Added a widget that shows some info about the canvas and the selected objects at the bottom of main window in design view. * [New] Enabled the usage of snippets in other portions of the software like GenericSQLWidget, FunctionWidget, ViewWidget, CustomSQLWidget. * [New] Added the ability to quickly jump to the tables related to a relationship. * [New] Added support to select all objects in the canvas by type (table, view, textbox, schema, relationship). * [New] Added support to bulk relationship points removal. * [New] Added a magnifier tool so the user can visualize objects when the zoom is too small. This tool allows the user to click to select or activate the context menu over the objects. * [New] Added support to generic sql objects that serve as an improved way to use custom SQL. * [New] Added support to handle metadata related to generic sql objects. * [New] Added the first object auto-arrange algorithm. * [Change] pgModeler will now accept (connect) to a PostgreSQL server even if the version of the server is not supported falling back to the most recent supported. * [Change] Minor improvements on DatabaseImportForm, ModelExportForm, ModelDatabaseDiffForm and MetadataHandlingForm to toggle uniformRowsHeight of the output tree at the start and the end of each process to avoid slowdowns and allow the items to be resized correctly when expanded. * [Change] Changed the way color are stored in Tag. * [Change] Minor adjustement on position info of objects in canvas. * [Change] Improvements on import/diff/export performances by adjusting the way the output widget handles items height. * [Change] Move the code from MainWindow::showEvent to the constructor of that class so all operations that load resources and restore configurations can be performed prior the window display. * [Change] Improved the ModelOverviewWidget to handle huge models better. * [Change] Improved the objects swapping by adding an objects grid where user can interact with it in order to choose which objects to swap. * [Change] Improved the schema parser to allow comparisons forcing the cast of values to float or int in the expression by using special letters attached to logical operators. * [Fix] Fixed the DatabaseModel::destroyObjects in order to include missing object types and avoiding leaks. * [Fix] Several memory leaks removed in different portions of the application. * [Fix] Minor fix in RelationshipView to show the line circles for n:n relationships. * [Fix] Minor warning fixes related to unused variables/values. * [Fix] Minor fix in Catalog that was trying to retrieve catalog info for generic sql objects. * [Fix] Fixed a bug when zooming out using wheel that was causing duplicated zoom in a single wheel turn. * [Fix] Minor fix in TableView and TableObjectView to present tables in a more compact fashion minimizing the space used in the canvas. * [Fix] Minor typo fix in swapobjectsidswidget.ui. * [Fix] Minor fix in lambdas slots usages. * [Fix] Fixed a bug in generateTextBuffer method in SQLExecutionWidget. v0.9.0-beta1 ------ Release date: May 13, 2017
* [New] Added the ability to standalone dialogs like import, diff, export and others to be resized according to the screen dpi and resolution. * [New] Added an experimental routine that will resize windows according to the current screen resolution and font dpi. * [New] Added support to browse referrer and referenced in DataManipulationForm. * [New] Added an item under table items that stores the referrer tables in the DatabaseExplorerWidget. * [New] Added the method BaseObjectView::getScreenDpiFactor to help resize scene objects according to the screen dpi/resolution. * [Change] Minor adjustment on readonly items regarding to referenced and referrer tables in DatabaseExplorerWidget. * [Change] Improved the tabs handling in SQLToolWidget in order to avoid confusion related to which database is being managed or queried currently. * [Change] Improvements done in the context menu at DataManipulationForm to include the key actions related to the control buttons at the top right portion of the dialog. * [Change] Improved the external script handling in SQLExecutionWidget. * [Change] Applied automatic resize for TaskProgressWidget. * [Change] Improvement done in model restoration dialog that is now displayed after the main windows is exposed. * [Fix] Fixed a problem in UpdateNotifierWidget that was receiving error 403 from the site. * [Fix] Fix a bug in DataManipulationForm that was causing order by clause to be nullified by comments added in the filter field. * [Fix] Fixed a regression in permission code generation. * [Fix] Fixed a bug in the generation of grant/revoke commands for columns. * [Fix] Fixed a bug that was causing the sorting options of index elements to be wrongly hidden. * [Fix] Minor fix in the site url. * [Fix] Minor fix in the filter toggling action in ObjectFinderWidget. v0.9.0-beta ------ Release date: April 4, 2017
* [New] Added support to indexes in Views. * [New] Added the support to edit/load the source code in NumberedTextEditor in external application. * [New] Added the ability to save/load metadata related to fade out status and extended attributes display status. * [New] Added the ability toggle the extended attributes area in tables and views. The toggle status is persisted in the model file and restores during loading * [New] Added constraints to the extended attributes section in the tables at canvas area in order to improve the quick access to these objects. * [New] Enabled the importing of view's indexes. * [New] Fade status is now persisted in the dbm file and restored during loading. * [New] Added the ability to control zoom factor from overview widget. * [New] Added a shortcut for "Duplicate" action in design view. * [New] Added support to (back)slash char in object's names. * [New] Enabled the usage of NewObjectOverlayWidget for views. * [Change] Changed the default characters used to escape values in DataManipulationForm and TableDataWidget from {} to // due to problems with json data. * [Change] Improved the file manipulation in SQLExecutionWidget. Added option to save the commands to the current file or in another file (save as). * [Change] Minor improvements done in Linux deployment script to support multiarch systems. * [Change] View's children (indexes, rules, triggers) are now listed under their respective parent view in DatabaseExplorerWidget. * [Change] Minor improvement in ElementsWidget to disable/hide columns combo when creating index elements for a index associated to a view. * [Change] Improved the diff between the complete database and a partial model representing it. * [Fix] Minor fix in AppearanceConfigWidget in order to set the font color correctly. * [Fix] Minor fix in the default file objects-style.conf * [Fix] Added the missing support to drop event triggers from database model. * [Fix] Fixed the drop cast command generation. * [Fix] Minor fix in windows deploy script to use newer PostgreSQL. * [Fix] Minor fix in template connections.conf file. * [Fix] Minor fix in config files related to installer generation (Linux). * [Fix] Minor fix in paste operation to restore the viewport position in design view. * [Fix] Minor fix in diff process to detect view's index changes. * [Fix] Fixed a bug in EventTrigger that was causing unknown exception to be thrown. * [Fix] Fixed a bug on RoleWidget that was preventing roles to be removed from "Members Of" tab. * [Fix] Minor fix in mouse cursor override operations. * [Fix] Fixed a bug when importing functions and composite types that somehow depend upon array types. * [Fix] Fixed a bug in function importing that was causing default values of parameters to be placed in the wrong position. v0.9.0-alpha1 ------ Release date: February 07, 2017
* [New] Added support to object moving via arrow keys in canvas area. * [New] Added support to easily create primary keys just by checking the desired columns in table's editing form. * [New] Added support to use middle button to handle panning mode. * [New] Added a more user friendly message at startup whenever a missing or corrupted configuration file is detected. The user is now presented to an option to restore default settings for the problematic file. * [New] Now any default file restored in ConfigurationForm has a backup saved into the directory 'backups' inside the configuration storage. * [New] Added support to hide the database explorer widget in SQL tool via splitter handler. * [New] Added a method to disable the custom context menu of the class NumberedTextEditor. * [New] Added support to object fading in ModelWidget. * [New] Added the support to persist the object opacity factor in config file. * [New] Added the method PgModelerUiNS::getIconPath() in order to retrieve icons from resource. * [New] Added support to column, constraint, trigger, rule and index duplication in TableWidget. * [New] Added support to item duplication in ObjectTableWidget. * [New] Added a loading cursor when the user opens the DataManipulationForm. * [New] The database explorer now creates the root item in the tree as the server itself which contains data related to this latter. * [New] Added the support to parenthesis in the middle of objects' names. * [Change] Improvements done in the SQL history at SQL execution widget. Now the command history is saved into a specific file and restored when the application starts. * [Change] Minor improvement in DataManipulationForm to show a wait cursor while filtering results. * [Change] Minor improvements in GeneralConfigWidget. Added an readonly input that exposes the path to the current user's configuration storage. * [Change] Improvements done in the object duplication feature. * [Change] Remove hardcoded icon paths in the code. * [Change] Improved the PgSQLTypeWidget to enable the length, precision, dimension fields as the user types the desired datatype. This will avoid jumping to the wrong field when pressing tab. * [Change] Updated the urls related to download and donation of the new site. * [Change] Changed the url to check for updates in GlobalAttributes to point to the new site. * [Change] Improvements done in the linux deploy script to use Qt 5.6.2. * [Change] Minor tweaks done in order to minimize the diff detection related to default values of columns. * [Change] Changed the default framework version used in the windows deployment script to 5.6.2. * [Change] Dropped the automatic LC_COLLATE and LC_CTYPE generation in Database object. Since this was causing more problems than helping when import the database and validating/exporting it. * [Change] In DataManipulationForm the filter input field is automatically focused when the filter toggle button is activated. * [Fix] Fixed a bug when using diff to create columns and update constraints. * [Fix] Fixed a bug that was duplicating the action "New" in the main window's side bar. * [Fix] Fixed a problem when importing database that contains citext extension installed in pg_catalog. * [Fix] Minor fix in ConnectionsConfigWidget that was causing duplicated connections to share de same host info wrongly. * [Fix] Restored the input data type handling in AggregateWidget. * [Fix] Fixed the oldsample.dbm model. * [Fix] Fixed a crash when restoring objects' metadata from backup file. * [Fix] Fixed a bug that was preventing inheritance relationships to be created when the same pair of tables existed in different schemas. * [Fix] Fixed a bug that was causing column name patterns to be used wrongly in many-to-many relationships. * [Fix] Fixed a bug that was preventing the automatic closing of tabs related to a dropped database in manage view. * [Fix] Fixed a bug that was causing the duplication of permissions during the database import which was leading to the complete failure of the entire process. * [Fix] Fixed the problem with invalid type error when trying to edit a 'timestamp with timezone' column. * [Fix] Fixed a bug in Relationship that was not setting NOT NULL flag for columns of the multi-valued primary key of many-to-many relationships causing the diff process to fail in some specific cases. * [Fix] Fixed a regression in RelationshipWidget that was not showing advanced object's form. * [Fix] Fixed the constraint codes display in TableObjectView. Now self relationships do not mark the primary key field as foreign keys. * [Fix] Fixed a regression that was not properly disabling the apply button in editing forms when the handled object was protected somehow. * [Fix] Minor typos fixes in some widgets. v0.9.0-alpha ------ Release date: October 18, 2016
* [New] Enabling pgModeler to connect to PostgreSQL 9.6 servers. * [New] Added the option to ignore error codes during the export process in CLI. * [New] Added the ability to ignore extra errors by their codes in ModelExportForm and ModelDatabaseDiffForm. * [New] Added the ability to load data from CSV file into TableDataWidget and DataManipulationForm. * [Change] Minor update in snippets.conf by adding a SELECT * command. * [Change] Removed deprecated exception ERR_ASG_ZERO_LENGTH. * [Change] Improvements done in CodeCompletionWidget so that the completion can be more accurate mainly when using the form [schema].[table]. * [Change] Methods responsible for dropping and exploring data were moved from SQLToolWidget to DatabaseExplorerWidget. * [Change] Improved the error output in DatabaseImportForm, ModelDatabaseDiffForm, ModelExportForm and Messagebox. * [Change] TableDataWidget widget now can have the column names changed freely not only when there are invalid ones. * [Change] Removed codename from AboutWidget. * [Fix] Fixed a bug in PgSQLType and PgSQLTypeWidget that was not properly setting length = 1 in character, varchar and numeric data types. * [Fix] Fixed a bug that was leading to stack overflow when generating object's sql plus its dependencies in huge models. * [Fix] Fix the structure of the sample model pagila.dbm. * [Fix] Minor fix in diff proccess in order to permit the comparison between a column added by relatinship and other that is not but share the same name. * [Fix] Fixed a bug that could cause crashes when editing connections in DatabaseImportForm or ModelDatabaseDiffForm. * [Fix] Fixed a crash when the user modified a connection on the fly with the SQL tool activated and trying to resume his work in database management. * [Fix] Fixed the tab order in ConnectionsConfigWidget. * [Fix] Fixed a bug in ModelDatabaseDiffForm that was running the export thread several times. * [Fix] Fix the generation of truncate commands in the diff when the types of columns are incompatible. * [Fix] Fixed a bug that was generating broken sql for tables when these objects have no constraints. * [Fix] Fixed a bug in diff that was not detecting column types length changes. v0.8.2 ------ Codename: Faithful Elephant
Release date: June 3, 2016
* [New] Created the PlainTextItemDelegate replacing the ReadOnlyItemDelegate where needed. * [New] Added the ability to the table to create insert commands from the initial data buffer. * [New] Added the support to interpret initial-data tag in DatabaseModel::createTable. * [New] Create the attribute initial-data for Table in order to store the initial set of values in a CSV-like buffer. * [New] Created the form to handle table's initial data. * [New] Added the ability to duplicate rows in DataManipulationForm. * [New] Added shortcuts to tabs in TableWidget. * [New] Added the ability to clear and copy text from history to the sql command input field using middle mouse button in SQL tool. * [New] Added the ability to set the default connection for operations import, export, diff and validation in ConnectionsConfigWidget. * [New] Added the usage of default connections in ModelValidationWidget. * [New] Added support to save/load default connections in the ConnectionsConfigWidget. * [New] Added attributes to the Connection class in order to control wheter the connection is the default for export, import, diff or validation operations. * [New] Added the ability to save the current grid options to the pgmodeler.conf file. * [New] Added a reference the svg library to the deployment scripts. * [New] Added support to export model to SVG file in UI and CLI. * [New] Added the support to change case and identation of the selected text in NumberedTextEditor using context menu or shortcuts. * [New] Added a method PgModelerUiNS::createOutputListItem which created list items with an icon and text. * [New] Connections now can have a timeout between command executions. When this timeout exceeds the next command is not executed. This is a workaround to avoid the crash of the program due to connections being (unexpectedly or not) closed by the server. * [New] Added the ability to show connections notice/warning in SQL tool. * [New] Added an step during the connections.conf loading to fix the connection timeout attribute automatically. * [Change] The class ReadOnlyItemDelegate was removed due to the introduction of PlainTextItemDelegate. * [Change] Minor adjustments in queries generated in DataManipulationForm in order to use PostgreSQL like escaping E'' permitting user to use special chars in the middle of values. * [Change] Simple quotes (') in DataManipulationForm and TableDataWidget will be automatically replaced by double quotes ('') in order to avoid broken commands. * [Change] Updated all translation dicts with new terms to be translated by their mainterners. * [Change] Changes in demo version enabling a limited usage of diff and import features. * [Change] Improved the way QTableWidgets instances are emptied. * [Change] Improvements done in order to correctly enable the column/row control buttons in DataManipulationForm according to the selected items. * [Change] Improved the duplication/delete operation in DataManipulationForm. These operations will happen only if the user selects the entire row. * [Change] Renamed the method DataManipulationForm::insertRow to addRow. * [Change] Changed the icons for Add, Delete rows in DataManipulationForm. * [Change] Improved the metadata handling form. Now the user just need to choose from which model to extract the metadata and the form will do the rest (extract and apply) in one step. * [Change] Minor improvement in ModelsDiffHelper in order to avoid the generation of useless SQL code (SET statments) when no effective changes were found in the process. * [Change] Minor improvement in ObjectSelectorWidget to change the object selection dialog title according to the handled object type. * [Change] Minor improvement in ObjectSelectorWidget to adjust the size of input according to the installed syntax highlighter. * [Change] Renamed the method Connection::setCommandExecTimeout to setSQLExecutionTimout. * [Change] Minor improvements in SQLExecutionWidget to use the command execution timeout. * [Change] Improvements on SQLExecutionWidget to enable the connection stay open in order to permit the usage of commands START TRANSATION, COMMIT and ROLLBACK. * [Change] Changed the icon for info message boxes. * [Fix] Minor typos fixed in UI components. * [Fix] Fix a bug in the Catalog class that was generating broken catalog queries for PostgreSQL releases under 9.3. * [Fix] Fixed a bug in DataManipulationForm that was not quoting columns in the generated UPDATE commands. * [Fix] Fixed some tooltips and shortcuts. * [Fix] Fixed a bug in import process related to permission creation. Now pgModeler removes extra backslash from role's name to avoid it not to be found in the model. * [Fix] Fixed the doxygen 'brief' instructions in code documentation. * [Fix] Fixed a bug that was generating broken table's SQL when the object has one or more inherited column. * [Fix] Fix on the history text copy. Added the correct mouse button (middle) that triggers the copy from the history to the sql input field. * [Fix] Escaping properly columns' comments. * [Fix] Minor fix in RelationshipWidget input fields related to receiver and reference tables. * [Fix] Minor fixes in QPlainTextEdit instances where the SyntaxHighlighter class is used to adjust the height of the field according to the font size. * [Fix] Minor fix in NumberedTextEditor::showContextMenu to use the cursor's postion only when the menu is executed. * [Fix] Fixed the way instances of ResultSet are copied. v0.8.2-beta1 ------ Codename: Faithful Elephant
Release date: March 31, 2016
* [New] Added missing PostGiS types. * [New] Adding the ability to save/load more metadata from objects like model's last zoom and position, protection status, sql disabled status, tags, textboxes and others. * [New] Created the method BaseGraphicObject::isGraphicObject. * [New] Added the ability to show the object's source in the SQL tool. * [New] Added missing encodings descriptors KOI8 and KOI8R. * [New] Added the method PgSQLType::isPolymorphicType that indicates if the type is one of the any*. * [New] Added a new method PgSQLType::canCastTo() that indicates if a type can be casted to another. * [New] pgModeler now stores and restore the state of attributes grid and source pane in SQLTool. * [New] Added the ability to load dummy items contents by clicking them in DatabaseExplorerWidget. * [New] DatabaseExplorerWidget now loads the small set of object in order to improve performance. The user have the ability to load the full database by using the refresh button actions. * [New] Added the ability to retrieve children objects of schemas or tables on demand (as their items are expanded) improving the performance. * [New] Created an specific icon for refresh database tree. * [New] Added a version of the method DatabaseImportHelper::getObjects that accepts a list of types and returns a list of attributes. * [New] Added an new version of Catalog::getObjectNames that retrieve the names according to a list of object types. * [New] Created a second version of PgModelerUiNS::configureWidgetFont that accepts a custom factor value. * [New] Adding the ability to BaseForm to use a ScrollArea when the size of the widget exceeds the 2/3 of the user's screen. * [New] Created template methods to show editing forms according to the kind of database object in ModelWidget. * [New] Created a signal BaseObjectWidget::s_closeRequested to tell the parent form close after successfuly edit an object. * [New] Created template methods in RelationshipWidget and ViewWidget to handle child object manipulation. * [New] Created a template method TableWidget::openEditingForm to handle the editing form for children objects. * [New] Added support to placeholder objects when moving graphical objects improving performance mainly when moving tables and relationships avoiding excessive update operations. * [New] Added an option to protect schema's children when protecting the schema itself. * [New] Added the abitily to diff partial models without drop the not imported ones from the original database. * [Change] CentralWidget renamed to WelcomeWidget. * [Change] Adjusted the build in Windows to use qt 5.5.1 and PostgreSQL 9.5. * [Change] Changed the help action from Wiki to Support and pointing it to GitHub's issues page. * [Change] Minor tweak in GeneralConfigWidget to permit current line to be highlighted even if the text preview field is readonly. * [Change] NumberedTextEditor will not highlight the current line if it is readonly. * [Change] Since label's dtd was moved to its own file the dtd for relationship now includes it. * [Change] Sorting spatial types in PgSQLTypeWidget. * [Change] Minor adjustments in central frame of the dialogs modelfixform.ui and modelrestorationform.ui. * [Change] Replaced the taskprogress widget usage from undo/redo operations by a simple busy cursor. * [Change] Removing duplicated alignment descriptors in generated warning frames at BaseObjectWidget. * [Change] Minor improvements in DatabaseExplorerWidget. Now each operation that take some time the cursor will be changed to a "wait" icon. * [Change] Minor improvements in table SQL generation. Inherited columns will be included in the table's code but in commented lines. * [Change] Minor fix in catalog query for operators. Unary operators will come with NONE key work in the side that the type is missing. * [Change] Minor update in sql-highlight.conf. * [Change] DatabaseImportForm::updateObjectsTree now removes 'without time zone' type modifier from parameters. * [Change] Minor adjustments on table headers in objectdepsrefswidget.ui. * [Change] Improvement on DatabaseImportForm::listObjects method. Now user can opt in load the full database or load only the cluster level ones and creating dummy items as children of these ones. * [Change] Minor size adjustments in AboutWidget. * [Change] Added a default title for ConnectionsConfigWidget. * [Change] Removed the static text 'pgModeler - ' from message box title. * [Change] Changed the default Qt version to 5.5.1 in linuxdeploy.sh. * [Change] Minimum size adjustments for toolbuttons and icons in DataManipulationForm, ModelValidationWidget and SQLExecutionWidget. * [Change] Minor improvement on DatabaseModel::getCreationOrder in order to include generated relationship constraints instead of the relationship themselves (useful in diff process) * [Change] Removed the forced frame shape for BaseForm central widget (Windows only). * [Change] Several size adjustments in all editing forms and dialogs. * [Change] Forcing the usage of Fusion style if the user does not provide a custom style. * [Change] Refactored the usage of SwapObjectsIdsWidget instance in ModelValidationWidget. The aggregate BaseForm instance in SwapObjectsIdsWidget was removed and locally created in ModelValidationWidget. * [Change] Removed the default window title from database objects widgets. * [Change] Decoupled the BaseForm instance from all BaseObjectWidget and their subclasses. Now editing forms are constructed in ModelWidget::showObjectForm. * [Change] Changed the attribute that controls connection timeout in connections.conf from 'connect_timout' to 'connection-timeout'. * [Change] Minor adjustment on connection configuration dialog size. * [Change] Remove the maximum size restrictions from all editing forms in order to better adapt the user's font settings. * [Change] Minor adjustments on bottom margins at mainwindow.ui. * [Change] Adjustments on warning and hint messages in editing forms. * [Change] Changed the size constraints for tool buttons. * [Change] Done modifications in order to avoid the usage of fixed font size and fixed colors in some widgets. * [Change] The option to control render smoothness in canvas now does not requires application restart. * [Change] Improved the CLI fix mode when dealing with broken operator classes, index and exclude constraints. * [Change] Improving the presentation of operator classes and families. Now the index access mode comes attached to their names in tree views. * [Change] Added a message to export progress when an object is renamed due to the option 'use temp. and uniq. names'. * [Change] Moved the "save model" button from "Report" tab to "Database model" tab in CrashHandlerForm. * [Change] Forcing the tree item update in model objects widget when activating some of actions in the popup menu. * [Change] Added colon character (:) as a valid one to appear in the middle of object's names. * [Fix] Added missing dtd file label.dtd. * [Fix] Fixed the label for inheritance relationship action in ModelWidget. * [Fix] Fixed the object schema file for metadata generation. * [Fix] Fixing the splash screen display in MacOSX. * [Fix] Fixed the tooltip of toggle buttons in SQLTool. * [Fix] Minor fix when generating the database source code for visualization in SQLTool. * [Fix] Fixed a bug in import process that was not properly creating dependency objects when auto resolve deps was checked. * [Fix] Fixed the fonts of hint boxes in datamanipulationform.ui. * [Fix] Fixed the conversion catalog query and import process. * [Fix] Fixed the aggregate validations related to assigned functions in order to permit the import of system aggregates. * [Fix] Minor fix in catalog query for triggers. * [Fix] Fixed the import of triggers, index, rules to automatically create their parent table if they are not yet created (when using auto resolve deps). * [Fix] Fixed the reference to "any" type. * [Fix] Fixed the attribute used as function for casts in DatabaseImportHelper::createCast. * [Fix] Additional fixes to cast code generation. * [Fix] Minor fix in the cast SQL schema file. * [Fix] Fixed the OID filtering in DatabaseExplorerWidget. * [Fix] Fixed the code display in SourceCodeWidget. * [Fix] Fixed the drop command generation for extension objects. * [Fix] Fixed a bug that was not updating relationships when importing objects to the current database model. * [Fix] Fixed the deployment script linuxdeploy.sh making it to copy additional Qt libs. * [Fix] Fixed the path to Qt installer framework in linuxdeploy.sh. * [Fix] Additional fix in linuxdeploy.sh to retreive the current compiled version. * [Fix] Fixed a bug when initializing PgSQLType instances when the provided type name is a user defined one. Random precision/dimension is not created anymore. * [Fix] Changed the font factor used by WelcomeWidget buttons. * [Fix] Minor fix in deployment script (Mac OSX). * [Fix] Fixed the object search when using exact match option. * [Fix] Fixed a bug that was not creating new columns in cases when the option to keep missing objects was set. * [Fix] Fixed the diff process that was not processing 1-1 or 1-n relationships correctly. * [Fix] Minor fix in ConnectionsConfigWidget setting up the correct buttons of the parent form in method openConnectionsConfiguration. * [Fix] Minor fix on message box default size of buttons. * [Fix] Fixed some signal connection warnings in BaseForm. * [Fix] Disabling the apply button correctly when the object is protected. * [Fix] Fixed a bug when pressing ESC key in the middle of object's movement that was canceling it. * [Fix] Fixed a bug when selecting a protected object using right button. The parent object is not selected incorrectly anymore. * [Fix] Fixed a bug when importing operator classes that was generating incorrect XML code for this kind of object prior the creation in the output model. * [Fix] Additional fix in SchemaParser::convertCharsToXMLEntities to correctly replace char in operator's names. * [Fix] Fixed the sample files to use the new way to reference opertor classes and families. * [Fix] Additional fix for code generation of operator classes. * [Fix] Fixed the loading of index, exclude constraint and operator classes when referencing some operator class or family. * [Fix] Fixed the code generation for operator classes to use 'signature' attribute. * [Fix] Fix a bug in the method SchemaParser::convertCharsToXMLEntities that was not replacing char by entities in certain cases. * [Fix] Minor fix in SourceCodeWidget to correctly show the progress dialog in the right position on screen. * [Fix] Added a validation in enum types avoiding user to include enum ids with invalid chars. * [Fix] Added a validation when creating operator classes that references an operator family by the name instead of signature. * [Fix] Minor fix in operator class form to install syntax highlighter in the operator family selector. * [Fix] Improved the method DatabaseImportHelper::getObjectName in such way to be able to return the operator families signatures. * [Fix] Fixed operator class code generation to use operator family's signature instead of name. * [Fix] Fixed the code generation for Operator family. Reduced form code (XML) is generated with "signature" attribute instead of "name" * [Fix] Fixed the object search in DatabaseModel. Now duplicated operator families are accepted, the desambiguation term will be the indexing mode. * [Fix] Fixed the creation of operator classes. Now operator families are referenced by their signature not the name. * [Fix] Fixed a bug when importing functions with unamed parameters. * [Fix] Minor typos fixes in PgSQLType source. * [Fix] Fixed some leaks and crashes when canceling the creation of new tables, views or relationship from their editing forms and closing the application. * [Fix] Fixed a bug related to quoted name validation that was wrongly raising errors related to long names. The validation of name size now discards the quotes from the count. v0.8.2-beta ------ Codename: Faithful Elephant
Release date: January 12, 2016
* [New] Added version descriptor for PostgreSQL 9.5 enabling pgModeler to connect to it. * [New] Added access method BRIN for indexes, operator classes and operator families as an initial support to PostgreSQL 9.5. * [New] Added event "table_rewrite" for event triggers as an initial support to PostgreSQL 9.5. * [New] Added "Diff" action to File menu. * [Change] Minor improvement in DataManipulationForm adding the shortcut of "Copy selection" button to its tooltip. * [Change] Improvements on DataManipulationForm on how pk columns are handled and used in the generated DML commands for UPDATE and DELETE. * [Change] Minor improvement on ModelRestorationForm when listing temp models. * [Change] Changed the hint text for "Disable render smoothness" option. * [Change] Changed the hint text for "Validate before save, export and diff". * [Change] Minor improvements on SQLExecutionWidget and DataManipulationForm to scroll items in the results grid by pixel not per item. * [Fix] Fixed a bug in operations that convert integer to serial and vice-versa. * [Fix] Fixed some header items text alignment. * [Fix] Fixed a crash when loading a broken model. Instead of show the error message related to corrupted file pgModeler was being aborted. * [Fix] Minor fix in hint text in SourceCodeWidget and ModelDatabaseDiffForm. * [Fix] Fixed shortcut conflicts in MainWindow. v0.8.2-alpha1 ------ Codename: Faithful Elephant
Release date: November 13, 2015
* [New] Added an additional step in import process to validate inheritance relationships to avoid incomplete tables. * [New] Added an additional relationship validation in model loading process when there are inheritances. This will avoid incomplete columns and validation errors related to "permanent invalidation state". * [New] Created an exclusive exception code when a parent table is not found in the imported set. This error is raised during inheritances creation. * [New] Added the signal s_connectionsUpdateRequest in DatabaseImportForm, ModelExportForm, ModelDatabaseDiffForm, ModelValidationWidget and SQLToolWidget in order to inform the main window that user has changed connections in those forms. * [New] Added the ability to configure connections without using the main configuration form. Now the user is able to do this task by using the "edit connections" option in any combo related to connections. * [Change] Minor adjustments in diff process messages. * [Change] Minor adjustments on ModelValidationWidget, ObjectFinderWidget and SQLExecutionWidget resize event to change the shape of toolbuttons in order to avoid truncate texts when the window size is too small. * [Change] Replaced the explicit hint texts from ModelValidationWidget by HintText instances. * [Change] Minor adjustment on widgets that are used to set connections. * [Fix] Fixed the way objects are destroyed when a model is closed diminishing the time consumed by that operation and the chances of crashes after their destruction. * [Fix] Additional fix in database import feature. Inheritances will be automatically created when "auto resolve dependencies" is checked. * [Fix] Fixed a crash when importing a database that contains big tables that handles multiple inheritances. * [Fix] Fixed a crash in Windows version. A missing initialization in OperatorClassElement was leading to segmentation fault. * [Fix] Fixed a bug in table and view editing form that was permitting to confugure permissions to new objects before create them in the model. * [Fix] Fixed a problem in UpdateNotifierWidget when the server returns http status code 302. v0.8.2-alpha ------ Codename: Faithful Elephant
Release date: October 05, 2015
* [New] Added a toggle button in SQL Execution to show/hide the output pane. * [New] Added the method Permission::isSimilarTo that returns true when a provided permission has the same semantics as the caller permission. * [New] Added missing keywords CASE, ELSE, QUERY, ELSIF, RAISE, EXCEPTION, TG_OP to sql-highlight.conf * [New] Columns that compose primary key and unique key are exposed as children of the constraint in the object tree at DatabaseExplorerWidget. * [New] Foreign key objects selected in DatabaseExplorerWidget now expose, in two children items, the source and referenced tables/columns. * [New] Added a confirmation message in DataManipulationForm to avoid lose uncommited changes before retrieve data. * [New] NumberedTextEditor now is able to set a custom tab width. * [New] Added a configuration option for custom tab width in GeneralConfigWidget. * [New] Added a nl_NL (Dutch - Netherlands) UI translation. * [New] Created a mechanism to make default values of columns in the form nextval(sequence) be transformed in a link between the sequence and the column in the import process. This will diminish the divergences raised by the diff process. * [New] Added a readonly item delegate for attributes grid to permit user to copy contents or navigate through values using keyboard. * [Change] Changed the initial data limit in DataManipulationForm from 100 to 1000. * [Change] Removed the default protected status of public schema in sample models. * [Change] The system schema public now can be protected/unprotected as well moved through the canvas area. * [Change] Changed the method DatabaseModel::getPermissionIndex to search permissions looking into their contents and not only by their internal references. * [Change] Improvements on diff process to avoid include already existent permissions. * [Change] Improvement in diff process to avoid generate code for an unmodifiable object when its code doesn't differs from the same object in database. * [Change] Added an option to DatabaseImportHelper to avoid the fk relationship updates. This will reduce the time to perform the import step in diff process. * [Change] The diff is now capable to detect differences in functions source code and recreate them. * [Change] Minor enhacement in DataManipulationForm to show the query time when retrieving data. * [Change] Minor adjustments on tooltips of buttons in SQLToolWidget and DatabaseExplorerWidget. * [Change] Minor size adjustment in ColumnWidget. * [Change] Minor improvement on SyntaxHighlighter to optionally use the same tab size as NumberedTextEditor. * [Change] Minor improvement on BaseObjectWidget to avoid install event filter in QPlainTextEdit and NumberedTextEditor. * [Change] Replaced the QPlainTextEdit instance for source code input in FunctionWidget by a NumberedTextEditor instance. * [Change] Minor message adjustments on SQLExecutionWidget. * [Change] Minor adjustment on relationship invalidation message in ModelValidationWidget. * [Change] Removed unused code from ModelValidationHelper. * [Change] If a 1:1 or 1:n relationship is removed from the model the receiver table will have its fk relationships updated. This is useful to recreate fk relationships that were replaced by the removed relationship. * [Change] Minor forms adjustments to resize command buttons depending on the size of texts. * [Change] More improvements in the diff process when dealing with foreign keys creation. * [Change] Changed the characters used to specify function call or any unescaped values in DataManipulationForm from <> to {} * [Change] When using snippets in the SQL execution field the current code will not be cleaned up, instead the snippet will be appended to the current code. * [Change] Removed the automatic view switching when saving the model. * [Change] Minor adjustment on buttons positions at NewObjectOverlay. * [Change] Minor message update in MainWindow::saveModel. * [Change] pgModeler now indicates the name of unsaved models before quit. * [Fix] Fixed a regression in trigger drop action in DatabaseExplorerWidget. * [Fix] Fixed a severe bug that was not configuring the connection correctly when adding a new SQL input field from the current browsed database in SQL tool. The bug could cause user to manage a different database other than the one desired. * [Fix] Fixed the "Find" button tooltip in SQLExecutionWidget * [Fix] Minor fix when showing system objects in ModelObjectsWidget. * [Fix] Fixed the view's SQL generation trimming the SQL that defines it to avoid differences between the model's view and the one generated after export. This will cause less divergences in when diff'ing the model and database. * [Fix] Minor fixes in the *::getAlterDefinition() methods do avoid crashes due to null objects handling. * [Fix] Fixed a crash when generating SQL code for recursive views. * [Fix] Minor fix to correclty show the temporary models save progress at the bottom of main window. * [Fix] Minor fixes in the validation process to force graphical objects updates and object's tree updates to reflect the new ids. * [Fix] Minor fixes in the object naming. Now pgModeler will accept dollar signs in any portion of the string or even numbers as object's name but this will automatically quote the name to avoid errors. * [Fix] Fixed the generation of DROP commands for triggers and rules. * [Fix] Fixed a bug in Index and IndexWidget that was permiting btree index elements to have sorting attributes which is not valid according to PostgreSQL rules. * [Fix] Fixed a bug in CodeCompletionWidget that was not retrieving objects with quoted names. * [Fix] Minor fix in DataManipulationForm to clear the changed rows list after save the modifications. * [Fix] Fixing the tab index in generalconfigwidget.ui. * [Fix] Added a workaround to avoid crashes and leaks related to relationship disconnection and validation. * [Fix] Minor fix in ModelsDiffHelper to avoid diff generation errors related to the missing 'fk-defs' attribute. * [Fix] Fixed a crash when trying to create a new foreign key after connect two tables using a 1:1 or 1:n relationship. * [Fix] Translated the pt_BR (Brazilian Portuguese) word found in the code. * [Fix] Minor fix in BaseObject to permit the usage of swapObjectsIds method from ModelWidget class. * [Fix] Fixed a bug that was duplicating some foreign key creation code in diff process. * [Fix] Fixed a bug in the diff process that was dropping columns linked to sequences when these ones were dropped. * [Fix] Fixed a bug when disabling table's SQL code from model widget. The FK constraints are now enabled/disabled correctly. * [Fix] Fixed a bug in import process that was wrongly prepending schema's name in types related to tables. * [Fix] Minor fixes in doxygen.conf. * [Fix] Fixed the feature to convert to sequence a serial column in order to diminsh breaking references between the column's parent table and the newly created sequence. * [Fix] Spelling fixes in es_ES (Spanish) UI translation. * [Fix] Fixed a bug that was not setting up the object's schema correctly when creating new table or view inside a selected schema. * [Fix] Fixed a bug in DatabaseModel::storeSpecialObjectsXML that was causing crashes when closing a model. * [Fix] Fixed the model loading from recent list in order to expose the "fix model" message box in case of errors. * [Fix] Minor adjustment on the generated diff code to include foreign keys definitions at the end of the script. * [Fix] Minor adjustment on ui-style.conf to minimize the problems with dark themes. * [Fix] Fixed a problem with validation that was trying to validate foreign keys without need. * [Fix] Fix a bug that was preventing "deferrable" attribute for constraint triggers to be used in SQL definition. v0.8.1 ------ Codename: Faithful Elephant
Release date: July 30, 2015
* [New] Added the ability to create objects from within the object selectors to shorten up the time spent to create a new objects in the model. The only exception of for selectors in SwapObjectsIdsWidget and table/column selectors in ViewWidget. * [New] Added a new method OperationList::isObjectRegistered to check if an object is registered in the list. * [New] Created a test class for SyntaxHighlighter. * [Change] Code optmizations done in SyntaxHighlighter removing duplicated or unused code. * [Change] Minor adjustments on splitters at DatabaseExplorerWidget and SQLExecutionWidget. * [Change] Changed the way the s_objectAdded signal is captured in ModelObjectsWidget::selectObject in order to work properly in Windows. * [Change] Removed unnecessary message box in BaseObjectWidget. * [Change] Changed the connection mode of the procedures to clear the operation list when a fix is applied in the model by the validation. * [Change] More improvements related to the operation list management when editing/creating objects through forms. * [Change] Improvements on BaseObjectWidget when canceling the creation/edition of objects and there are chained operations in the operations list. * [Change] Additional improvements on TableWidget removing unneeded connection to signals. * [Change] Improvement in TableWidget to register a new table in the operaions list after the user create a dependency object (schema, tag, role, etc) to avoid undo/redo errors. * [Change] Additional improvements on ObjectSelectorWidget and ModelObjectsWidget to automatically set focus on the created object. * [Change] Enhanced the generated view code. Now it should be more readable. * [Fix] Fixed a bug related to unlogged tables exporting. * [Fix] Fixed a small bug in SyntaxHighlighter that was not highlighting properly new lines and text after multline comments. * [Fix] Fixed a bug that was preventing comments to be properly quoted (issue #710) * [Fix] Fixed the SyntaxHighlighter constructor call throught the classes. * [Fix] Minor fixes on xml-highlight.conf * [Fix] Minor fix in the import process to remove quotes from enum type attributes to avoid erroneous modification of attributes when diff a model and database. * [Fix] Fixed the disabled close button on editing forms (Windows only) * [Fix] Fixed a bug in the object selector that was preventing the selector dialog to be shown when user click in the input field. * [Fix] Fixed a regression in method DatabaseModel::getObject(QString,ObjectType) when dealing with operator class or family. * [Fix] Fixed the configuration of Quick menu for relationship added objects. The disable/enable sql action is not visible anymore. * [Fix] Fixed possible memory leaks when creating new objects through editing forms. * [Fix] Fixed a bug on the object name validation that was permitting user to specify object names containing only numbers. * [Fix] Fixed a bug when generating ENUM types without enum attributes. * [Fix] Fixed the generation of DROP command for trigger and rules. * [Fix] Fixed a crash when closing the model. This crash was related to removing permissions from special objects and right after destroy the remaining permisisons. * [Fix] Fixed the method Permission::getSignature to avoid generating the same signature for different objects (permissions must be unique). v0.8.1-beta1 ------ Codename: Faithful Elephant
Release date: June 30, 2015
* [New] Objects can be now renamed in database explorer except for databases and casts. * [New] Added an initial Spanish (es_ES) UI translation (review needed). * [Change] Dropped the startapp script in Mac OSX. All executables now are able to run without explicitly use that script. * [Fix] Fixed the snippet related to object renaming in snippets.conf. * [Fix] Fixed a small bug in schema parser that was ignoring the usage of '$oc' metacharacter in some cases. * [Fix] Fixed shortcut for delete command in data manipulation form. * [Fix] Fixed the deployment script on Mac OSX to make the CLI and crash handler find the core libraries properly. * [Fix] Fixed a bug that was generating ALTER ROLE commands without the semicolon. v0.8.1-beta ------ Codename: Faithful Elephant
Release date: June 04, 2015
* [New] Added the ability to handle databases in different connections at once without the need to disconnect from a server and connect to another. * [New] Added an option to preserve database name (do not rename) in diff process. * [New] Added a numbered code editor in ModelDatabaseDiffForm. * [New] Created a basic structure to start building unit tests based upon Qtest for new features and fixes. * [New] Added an automatic quotation mechanism for PostgreSQL's reserved keywords when they are begin used as object's name. * [New] Created the function createNumberedTextEditor in PgModelerUiNS to be used as a factory of NumberedTextEdit instances. * [New] Added a font preview widget in GeneralConfigWidget. * [New] Added the ability to configure line numbers font/bg colors and highligt color in GeneralConfigWidget. * [New] Created a class ReadOnlyItemDelegate to avoid the edition of items in data grid / tree widgtes. * [New] Added a donate widget in MainWindow. * [New] Created a new class NumberedTextEdit which goal is to display source code with line numbering and highlight color. * [New] Created a html based delegate item in order to render tree items with html format. * [New] Added a fallback value for environment values not set during startup. * [Change] Minor improvement on ConnectionsConfigWidget when user left a connection open for editing and don't save it. The software will ask for save the connection. * [Change] Improvements done to DataManipulationForm in order to avoid let connections open leading to application crash when the connection timeout is reached. * [Change] Added a new constructor to Connection class that accepts a map of connection params. * [Change] Removed the installation of PGMODELER_TMP_DIR environment variable in installer. * [Change] Removed the usage of TEMPDIR variable in pgmodeler.pri * [Change] Moved the code to create temp dir to Application class. * [Change] Temporary folder now is isolated in pgModeler's configuration dir at user's home (platform specific) to avoid a user to see temp files from another. * [Change] Removed the "stay on top" behavior on ModelOverviewWidget to avoid the blocking of application dialogs is some systems. * [Change] Minor improvement on DataManipulationForm when creating the window title based upon the connected database. * [Change] Disabled the cascade drop for roles and tablespaces (not supported) in DatabaseExplorerWidget. * [Change] Minor improvement on SQLToolWidget to remove the excessive usage of buttons to connect and browse databases. * [Change] Removed the "connect" button from ModelDatabaseDiffForm. Now the databases are listed when the connection is selected in combo. * [Change] Removed the "connect" button from DatabaseImportForm. Now when selecting a connection the databases will be listed. * [Change] Minor improvement on DataManipulationForm to load the first 100 rows of the current table each time the index of combobox changes. * [Change] Moved the database drop button from SQLToolWidget to DatabaseExplorerWidget. Now each instance of the latter class emits a signal to SQLToolWidget to perform the db drop. * [Change] Removed the mothod ModelsDiffHelper::setDiffOptions and create setDiffOption and a set of OPT_xxx constants to access the diff options. * [Change] Minor improvement on SQLToolWidget to force focus of the current SQLExecutionWidget instance. * [Change] Replaced the QPlainTextEdit instance in SnippetsConfigWidget by NumberedTextEditor. * [Change] Added instances of NumberedTextEditor to CustomSQLWidget to be used as appended/prepended code input. * [Change] Changed the default font size of source code editors to 10pt. * [Change] Minor size adjustments on aboutwidget.ui and donatewidget.ui * [Change] Improved the windeploy.sh to build binaries in x86 and x64 at once. * [Change] Minor improvement on linuxdeploy.sh to build demo and full versions at once. * [Change] Avoiding the copy of ui-style.conf during startup. * [Change] Attributes and general functions in namespaces are now declared as extern in .h and defined in .cpp to force them to be initialized once. * [Fix] Minor fix on windeploy.sh when building all releases at once. * [Fix] Fixed the demo version build error. * [Fix] Fix a crash when recreating Views that have child objects (rules or triggers) in DatabaseModel::storeSpecialObjectsXML. * [Fix] Fixed a typo when displaying column default values as nextval(seqname). * [Fix] Fixed a bug on DatabaseExplorerWidget that was selecting the wrong database when opening the data grid. * [Fix] Fix a bug on DataManipulationForm that was preventing user to delete rows in tables with no primary key. * [Fix] Minor signal message correction in DatabaseImportHelper. * [Fix] Minor hint text correction in ModelDatabaseDiffForm. * [Fix] Fix a bug on diff process that was not detecting precision/length changes in column types. * [Fix] Fixed a bug in CLI that was not considering the PWD when dealing with input/output files. * [Fix] Fix a crash in PgModelerCLI when exporting model to PNG. * [Fix] Minor fix in SyntaxHighlighter to apply font changes in live objects instead of only apply font changes in new objects (requires the use of rehighlight()) * [Fix] Fixed a bug on SyntaxHighlighter that was rehighlighting endlessly a document leading to application crash. * [Fix] Minor adjust on pgmodeler executable to find libs at runtime (Mac OSX). * [Fix] Fixed a crash when creating a new table containing a new index. * [Fix] Fixed a bug that was permitting to set precision/scale to a user-defined type. * [Fix] Minor fix on catalog query that retrieve types. Now types derivated from materialized views are not listed. * [Fix] More fixes related to inherited columns and check constraints. Now diff infos containing modification for these kind of objects are discarded. * [Fix] Fixed the import of inherited check constraints. * [Fix] Minor fixes on DatabaseImportForm, ModelDatabaseDiffForm, ModelValidationWidget to use the html item delegate. * [Fix] Minor fix on model export and validation progress. v0.8.1-alpha1 ------ Codename: Faithful Elephant
Release date: April 20, 2015
* [New] Added the ability to import objects from an existent database to a currently working model. * [New] Improvements on DatabaseImportHelper to dump the objects attributes in debug mode or to the log file when "ignore errors" is checked. * [New] Added a fix step in CLI to fix functions signatures that includes OUT parameters. * [Change] Minor adjustment on model validation progress and output. * [Change] Minor adjust on model export progress on CLI. * [Change] Minor improvements on objects validation process when dealing with broken relationship config as well with FKs referencing a column created before it. * [Change] Minor improvement on object selector widget to show the constraint name correctly. * [Change] Change in user's configuration copy process. Now only configuration files are copied, folders are not copied anymore. * [Change] The CLI now references template configuration files instead of user's when configuring file association. * [Change] The settings related widgets now references template configuration files in order to load defaults or save settings. * [Change] Improved the way threads are handled in ModelDatabaseDiffForm. * [Change] Changed the way thread is used in ModelValidationWidget. Now it'll be created in each time the "Validate" button is clicked. * [Change] Removed unused actions in MainWindow. * [Change] Removed sleepThread method from ModelExportHelper, ModelValidationHelper and DatabaseImportHelper. * [Change] Disabled the tabChangeFocus property of sql input field in SQLExecutionWidget. * [Change] Minor adjust on tag objects positioning. * [Change] Fixed the generation of function's signature in Function. Now OUT parameters aren't included. * [Change] Fixed the generation of function's signature in DatabaseImportHelper. Parameters signaled with 't' in their modes aren't included. * [Change] Restored the old behavior of Connection class to append only error code as extra info in exceptions to avoid break other features that need that code. * [Fix] Added a proper quotation to the command used to trigger the crash handler. * [Fix] Minor fix when displaying the row amount for the selected table on database explorer. * [Fix] Added a patch into swap id dialog when dealing with broken relationships. * [Fix] Minor fix on relationship line configuration when redrawing them during the relationship validation process. * [Fix] Minor fix when drawing views with extended attributes. * [Fix] Minor fix when enabling/disabling zoom buttons when the current zoom reaches the minimum or maximum values. * [Fix] Minor fix on thread operations on Windows system. * [Fix] Fixed the export to SQL and PNG in thread mode. * [Fix] Added missing breaking points in ModelsDiffHelper to help the thread to shutdown. * [Fix] Fixed the UI hang up when exporting a huge model by using BlockingQueueConnection in some slots to avoid thread consume all CPU resources. * [Fix] Fixed a endless loop in PgModelerUiNS::formatMessage. * [Fix] Minor fix in the generation of ALTER TABLE .. ADD COLUMN command. * [Fix] Fixed current tab index in AboutWidget. * [Fix] Minor fix on SwapObjectsIdsWidget to invalidate the database forcing the validation process. * [Fix] Fixed the operator name validation. * [Fix] Adding missing flag icons in AboutWidget. v0.8.1-alpha ------ Codename: Faithful Elephant
Release date: April 02, 2015
* [New] Added a "Contributors" section in "About pgModeler" dialog. * [New] Introduced the NO_UPDATE_CHECK variable in qmake to turn off update verification code specifically for package maintainers usage. * [New] Generated installers has the ability to install .dbm file association (Windows and Linux). * [New] Introduced a new env var PGMODELER_TMPL_CONF_DIR to override the template configuration location. * [New] The "plugins" folder is created automatically at startup if does not exits. * [New] Added the ability to show original SQL code, dependencies and children's code for test purposes in source code preview dialog. * [New] Added the method DatabaseModel::getCreationOrder(BaseObject *) that retrieves all objects needed to create a certain object. * [New] Added an action to save SQL code to file in source code preview dialog. * [New] Added an option to list indirect refereces to an object in ObjectDepsRefsWidget. * [Change] Minor adjust on Windows installer script. * [Change] Deployment scripts on all platforms now uses PostgreSQL 9.4 and Qt 5.4.1 by default. * [Change] Replaced float data types to double in libobjrenderer and libpgmodeler_ui classes to avoid lost of precision mainly when handling graphical objects. * [Change] File association procedures were moved to CLI. Now the user can install/remove file association by using '--dbm-mime-type' option (Windows and Linux). * [Change] Minor adjustments in PgModelerCLI menu. * [Change] Removed unused variables and commented code throughout the code. * [Change] The build process now uses libxml2 from PostgreSQL installation (Windows). * [Change] Minor adjustment on how the duplicated elements are removed from lists in the methods __getObjectDependencies(), __getObjectReferences(), findObject() in DatabaseModel class. * [Change] Removed uneeded "using namespace" statements. * [Change] Adjustment on start-pgmodeler.sh script to use pgmodeler.vars as source of needed environment variables (Linux). * [Change] Improvements on how objects are recreated using the "recreate unmodifiable" option on Diff process. * [Change] Enhanced the control of database explorer widgets and the SQL execution panes related to them. * [Change] Added a clear error message when required fields are not set when creating/updating object. * [Change] Installation folder/files arrangement reverted to previous settings in order to avoid "DLL entry point errors" errors (Windows). * [Change] Minor change in pgmodeler.pri to set default output paths according to FSH standard (Linux). * [Fix] Minor fixes and adjustments on the deployment script and installer configuration file (windows). * [Fix] Minor fixes when dealing with CLI and crash handler calls inside code (MacOSX). * [Fix] Minor fix on range based loops using auto keyword. * [Fix] Fixing invalid shebang in shell scripts (Linux). * [Fix] Fix tab order in ConnectionsConfigWidget. * [Fix] Minor fix when resizing HintTextWidget instances. * [Fix] Fixed a bug when importing constraint triggers. * [Fix] Minor bug fix when dropping table children objects in database explorer. * [Fix] Minor fix when generating XML code for permissions. * [Fix] Minor bug fix on database explorer at manage view to avoid left opened connections. * [Fix] Added a patch in model fix process to correctly move indexes/triggers/rules from within tables to outside their xml definition. * [Fix] Fixed a bug when configuring encoding for database. Now the "Default" value can be used normally. * [Fix] Fixed a bug on model fix process that was removing empty lines (only with breaks) from functions definitions as well from other objects. * [Fix] Fix crash when converting a serial column which is not assigned to a primary key. v0.8.0 ------ Codename: Faithful Elephant
Release date: February 28, 2015
* [New] Added support to multiple SQL execution widget instances for the same browsed database in SQL tool. * [New] Added truncate table actions on DatabaseExplorerWidget. * [Change] Minor adjustments on ModelValidationHelper. * [Change] Minor adjustments on CustomSQLWidget. * [Change] Included the delete cascade action to Edit menu in MainWindow. * [Change] Minor widget adjustments on ModelDatabaseDiffForm. * [Change] Minor improvements when saving temp models. Now the saving thread will not run if the diff/export/import dialogs are focused avoiding (rare) race conditions. * [Change] Improved the update notifier to display a recover link and purchase link on the "Get binary package" button menu. * [Change] Minor adjustment on output icons at ModelExportForm. * [Change] Improvement on DatabaseModel::getObjectReferences to retrieve indexes as references to columns. This solve the bug related to import and diff processes that was causing detached columns to be dropped even if there were indexes referencing those columns. * [Change] Added a more friendly error message when the user try to undo/redo an invalid operation at operations history. * [Change] Minor improvement on ConnectionsConfigWidget adding the ability to make the configured initial database to be auto browsed when using the connection to manage objects on Manage view. * [Fix] Fixed the output of SQL commands on diff, import and export. The commands now does not comes without original line breaks. * [Fix] Fixed unexpected dialog blockings and form resetting on diff and export dialogs when minimizing and restoring the application. * [Fix] Fix a crash when converting a serial column to sequence in which the first is not assigned to a primary key. * [Fix] Minor fix on crash handler startup. Now exceptions occurred during the process are printed to stdout. * [Fix] Fix a crash when pasting objects right after closing the source model (from where the objects were copied/cut). * [Fix] Minor fix on ModelWidget::showObjectForm to correctly show permissions details. * [Fix] Minor fix on the import process. Now the majority of problems related to objects that are created before their dependencies are solved. * [Fix] Fixed some bug related to object duplication error treatment on ModelExportHelper. * [Fix] Fixed a crash on connections config dialog when user removed a single connection and close the application, causing segmentation fault. * [Fix] Minor fix on SQLToolWidget to avoid the disabling of SQL command input and controls when a database is dropped and there is at least one database being browsed. * [Fix] Minor fix on session saving process. * [Fix] Fixed a bug that was causing relationship points to be moved twice when multiple objects were selected on the canvas area. * [Fix] Fixed some syntax errors on snippets.conf file. * [Fix] Fixed a bug that was preventing global settings for relationships to be persisted. * [Fix] Fixed a bug when importing permissions related to functions. * [Fix] Minor fix on signal/slot connection order in NewObjectOverlayWidget. * [Fix] Minor improvements on swap objects ids dialog. v0.8.0-beta2 ------ Codename: Faithful Elephant
Release date: February 07, 2015
* [New] Added the method Connection::getServerInfo that returns some informations about the connected server. * [New] Added an attribute to DatabaseExplorerWidget to show the estimated rows amount for selected table. * [New] Added the ability to cascade delete objects from database model. * [New] Created missing getters and setters for Operation class. * [New] Added the ability to set owner, schema and tag for several objects at once through the quick actions menu. * [New] Added an option to diff process to reuse sequences if the source model has serial columns in which the generated sequence name matches a sequence's name on the imported model. * [New] Added the support to per-user configuration. Now each user on the system will have his separated configuration folder. * [New] Added a bug report form on main window to give user the chance to report a bug without use crash handler. * [New] Added action to enable/disable an object's sql from quick actions menu at ModelWidget. * [New] Created a new namespace PgModelerUiNS to store shared constants and function in libpgmodeler_ui subproject. * [New] Added the ability to execute the DROP statements attached to object's SQL when exporting model to DBMS. * [Change] The method PgModelerNS::formatString was moved to PgModelerUiNS::formatMessage. * [Change] Simplified the layout of DataManipulationForm making the Advanced tab (filter) be moved to the same tab of result set facilitating the access to filtering features. * [Change] Restored previous behavior of ModelWidget::cancelObjectAddition and ModelWidget::enableModelActions methods. * [Change] Removed empty destructors from classes TableView and GraphicalView. * [Change] Minor changes on destructors of classes that represents graphical objects on libobjrenderer to correctly undo the link between the graphical object and the source object. * [Change] Improvements on ModelExportHelper adding the ability to ignore certain error triggered by PostgreSQL referencing their codes. * [Change] Improvements on crash handler to reuse the code from bug report form. * [Change] Changed the default PREFIX on pgmodeler.pri to /opt/pgmodeler when building on Linux. * [Change] Several adjustments on deployments scripts to use the new build variable settings. * [Change] Minor adjustments on main.pro, pgmodeler.pro and pgmodeler.pri files. * [Change] Additional improvements on start-pgmodeler.sh and startapp. * [Change] Crash/bug report files now have extensions .bug instead of .crash * [Change] Removed the unused class Utf8String. This class was used in earlier versions of pgModeler and Qt 5x to fix some issues related to UTF8 string handling. After removed any reference of the class from code the issue seems fixed. In any moment this class can return if we have regressions. * [Change] All literals throughout the code were replaced by QString() construction. * [Change] Adjustments done in .pro file in order to correctly compile under Windows. * [Change] Modifications done on .pro files that will permit custom output paths when building pgModeler from source, enabling it to be package to several linux distros. * [Change] Moved the method disableReferencesSQL from BaseObjectWidget to PgModelerUiNS. * [Change] Modifications done on DatabaseImportForm in order to be in the same standard as ModelExportForm and ModelDatabaseDiffForm. * [Change] Minor improvements on ModelExportHelper in order to show the correct actions (commands) being executed. * [Change] Improvements on ModelExportForm by including an output tab in order to display all actions taken during the export process. * [Change] Adjustments on PgModelerCLI, ModelExportForm and ModelExportHelper to accept the "drop objects" option. * [Change] Minor adjustment on ModelDatabaseDiffForm in order to lower the chances to crash the app if user try to repeatedly cancel and start over the diff process. * [Change] Minor change on the generation of DROP statements attached to object's SQL. * [Fix] Minor fixes on html formatted messages. * [Fix] Fix on GeneralConfigWidget that was not saving code completion enabling status. * [Fix] Fixed some bugs on libobjrenderer classes that was causing crashes in some models arrangements. Now graphical objects are effectively deallocated only when the whole scene is destroyed. * [Fix] Minor improvement on OperationList::removeOperations to avoid crashes if a pool object is destroyed outside the operation history (e.g. relationship invalidation). * [Fix] Several fixes on OperationList to minimize the crashes when undoing/redoing operations. * [Fix] Minor fix on validation process that was failing sometimes to use temporary names feature. * [Fix] Minor fix on ModelsDiffHelper to correctly recreate foreign keys that references recreated primary keys. * [Fix] Minor fix on Table::removeObject to change not-null state of columns only when the removed object is a primary key. * [Fix] Fixed a bug when converting many-to-many self-relationship and trying to undo the operation. * [Fix] Fixed the query to retrieve the last_value field of sequences on DatabaseExplorerWidget. * [Fix] Minor fix on CLI that was wrongly considering tag attributes default-* as xml code for database objects causing errors on fix process. * [Fix] Minor fix on diff process that was ignoring column's data type changes. * [Fix] Minor fix on column SQL generation that was removing quotation on sequences names when using nextval() function call as default value. * [Fix] Minor fix on ModelFixForm to correctly find the startapp script on MacOSX. * [Fix] Fixed bug when import/diff user defined types that contains $ in the middle of their names. Now the names are quoted to avoid errors when referencing those types. * [Fix] Minor fix when saving/restoring sessions. Now, empty sessions (without loaded files) are correctly saved. * [Fix] Fixed a crash when importing a database in a second time after some error has occurred previously. * [Fix] First version of a fix to solve problems related to inheritance diff/import. Now pgModeler does not try to drop inherited columns on diff process. * [Fix] Fixed a crash when destroying constraints stored on operation history. * [Fix] Fix on the import process to correctly identify and create inherited columns that aren't linked to constraints or other objects. For those referenced by other objects they will be created as detached columns. * [Fix] Fixed a bug on rule.sch catalog query. * [Fix] Minor fix on generation of DROP commands. * [Fix] Fixed some catalog query schema files and the Catalog class itself in order to correctly select/discard objects linked directly or not to extensions. * [Fix] Minor fix on generation of commands related to extensions. According to the rule, extensions names can't be schema qualified. v0.8.0-beta1 ------ Codename: Faithful Elephant
Release date: January 10, 2015
* [New] Created the widget SnippetConfigWidget in order to handle SQL snippets on SQLTool and DatabaseExplorerWidget. * [New] Introduced a new expression %unset on SchemaParser to clear the named attributes. * [New] Added support for permission on objects Type and Domain. * [New] Added the method SchemaParser::extractAttributes that is capable to extract the attributes used in a loaded buffer. * [New] Added methods to handle snippet selection in DatabaseExplorerWidget and SQLToolWidget. * [New] Created the hint text for code completion option on GeneralConfigWidget. * [New] Added an option to enable/disable code completion widget on sql code input fields (linked to CodeCompletionWidget instances). * [New] Created a method Connection::getConnectionId that returns a string to identify that connection. * [New] Created the constant GlobalAttributes::SNIPPET_CONF to store the default name for code snippet config file. * [New] Added some basic code comments on DatabaseExplorerWidget. * [New] Created the global constant SQL_HIGHLIGHT_CONF_PATH and XML_HIGHLIGHT_CONF_PATH on GlobalAttributes in order to avoid code repetition when loading syntax highlight conf files. * [New] Added a method to parse rule commands on Catalog. * [New] Added the method Catalog::getObjectAttributes to retrieve object attributes by its oid. * [New] Introduced a new step on model validation: relationship configuration checking. * [New] Added "properties" action on context menu at DatabaseExplorerWidget. * [New] Added a panel related to object's properties on database explorer widget. * [Change] The operation history is erased whenever a fix is applied to the model by the validator. * [Change] Minor change on ColorPickerWidget in order to change color of pickers using stylesheet instead of QPallete. * [Change] Minor adjustments on AppearanceConfigWidget. * [Change] Minor copyright update on source files. * [Change] Renamed the instruction %define to %set at SchemaParser. * [Change] Removed unused methods from Messagebox. * [Change] Minor improvements on Messagebox class by adding a simple show() method that receives only trhee parameters. * [Change] Minor improvements on SchemaParser::translateMetaCharacter() * [Change] Minor fix on DatabaseExplorerWidget::handleSelectedSnippet() * [Change] Removed duplicated code to handle snippets on SQLToolWidget. * [Change] Methods setIgnoreEmptyAttributes and setIgnoreUnkownAttributes at SchemaParser were renamed to ignoreEmptyAttributes and ignoreUnkownAttributes. * [Change] Minor improvements on ModelNavigationWidget to show the filename associated to a hovered item on combobox. * [Change] Simplified the syntax for attributes on .sch files from @{attrb} to {attrib}. * [Change] Updated all .sch files with the new attribute syntax. * [Change] Minor improvements on configuration widgets in order to detect if the settings was changed, this will avoid the unecessary load/save of the configuration files in ConfigurationForm. * [Change] Replaced ternary ifs like "1" : "" by ParsersAttributes::_TRUE_ : "" * [Change] Extensive changes in BaseConfigWidget and its subclasses in order to remove the use of extern keyword on other libs when there is the need to get the current config params. Now, user must call * [class]::getConfigurationParams() where class must be one of the derivates of BaseConfigWidget. * [Change] The extern pointer configuration_form on mainwindow.cpp was moved into MainWindow class as a subwindow of it. * [Change] Improvement on BaseConfigWidget and its children classes in order to use polymorphism in ConfigurationForm when needing to save or load confs. * [Change] Moved the constants PGSQL_VERSION_xx from SchemaParser to a namespace called PgSQLVersions in order to avoid the "static initialization order" problem. * [Change] Additional constants were created on PgSQLVersions namespace: ALL_VERSIONS and DEFAULT_VERSION. * [Change] Improvement on XMLParser::hasElement method in order to permit user to check if the current element has a child of the specified XML node type. * [Change] Minor improvements on BaseConfigWidget. * [Change] Moved the method DatabaseModel::getObjectType(QString) to BaseObject as a static one. * [Change] Minor updates on sql-highlight.conf * [Change] Updated the version info on platform specific installer files. * [Change] Removed unused constructor on Connection class. * [Change] Minor improvement on DatabaseImportForm::listObjects, now it's possible to include a database root item. * [Change] Minor improvements on class DatabaseImportHelper. * [Fix] Fixed a bug that was crashing application when using special pks in relationshps. * [Fix] Minor fix on windeploy.sh to copy the correct libs. * [Fix] Minor fix on macdeploy.sh in order to use Qt 5.4. * [Fix] Fixes done in order to build pgModeler on Windows using Qt 5.4. * [Fix] Fixed a bug on SchemaParser that was wrongly reading %define instructions inside if's and creating attributes when it was not need to create them. * [Fix] Modifications done on attributes initialization at RelationshipWidget in order to fix some crashes. Now pgModeler runs without crashing when compiled in release mode using g++. * [Fix] Minor fix on aggregates listing on Catalog class. Now the handled types are attached to aggregates' names. * [Fix] Minor fix on config pages indexes on ConfigurationForm. * [Fix] Minor fix on MainWindow when there are errors during configuration files loading. * [Fix] Minor fix on object name formatting at DatabaseExplorerWidget. * [Fix] Minor fix on SQLToolWidget to set the current database explorer instance properly. * [Fix] Minor fix on rule catalog query. * [Fix] Minor fix on table.sch schema file. * [Fix] Fixed the object filter on database explorer. * [Fix] Typo correction on ModelExportHelper. * [Fix] Additional fix to remove g++ warnings. v0.8.0-beta ------ Codename: Faithful Elephant
Release date: November 29, 2014
* [New] Introduced the first version of model database diff feature. * [New] Created the method Constraint::isCodeDiffersFrom in order to correctly generate the xml code and compare it with another object's code. * [New] Created the method PgModelerNS::formatString in order to avoid repeatedly replace special chars by html tags. * [New] Added the method PgSQLType::isEquivalentTo in order to check if a type is equivalent to another. This method helps to avoids unnecessary recreation of columns or type attributes on diff process. * [New] Created the class DatabaseExplorerWidget in order to permit user manage several database instances on the sql tool. * [New] Enabled the usage of cached catalog queries on Catalog class in order to increase the performance of the whole import process. * [New] Added the method PgSQLType::isRegistered that indicates if a type is already registered or not. * [New] Added the method BaseObject::acceptsAlterCommand to indicate if an object type can be changed through ALTER commands. * [New] Added the method BaseObject::acceptsDropCommand to be able to identify which kind of object accepts DROP commands. * [New] Added the method Column::getAlterDefinition in order to get the ALTER definition based upon the differences of two columns. * [New] Added the ability to schema parser to create attributes from within the parsed schema files or buffer. * [New] Added the method Table::getTruncateDefinition to return the proper TRUNCATE command. * [New] Added method Sequence::getAlterDefinition. * [New] Added method Role::getAlterDefinition. * [New] Added method Index::getAlterDefinition. * [New] Created the getAlterDefinition method for Extension and Function. * [New] Created the custom implementation for getSignature() for Aggregate, Cast, Constraint, Index, Operator Class, Operator Family, Rule, Trigger. * [New] Created the own versions of getDropDefinition for Function and Index. * [New] Added to schema parser the ability to evaluate simple comparison expressions in the form (@{attribute} [operator] "value"). * [New] Added a special attribute pgsql-ver when generating code definition to store the currently used pgsql version. * [New] Introduced a new method BaseObject::getSignature() that returns by default the object's name (formatted or not) and with the schema name prepended (when available). * [New] Introduced a new name pattern PK_COL_PATTERN which is used to generate the single pk column name for many-to-many relationships. * [New] Added method getAlterDefinition for Aggregate, Collation and EventTrigger. * [New] Created a styled text box object. * [New] Created the new class RoundedRectItem in order to generate rounded corner rectangle items on scene. * [New] Added a sql disabled info item for relationships. * [New] SQL disabled status are now displayed as a textbox on top of tables and schemas. Other objects will continue to have their names striked out to denote the deactivation of SQL code. * [New] Added the ability to copy text from validation widget output. * [Change] Minor change on Connection class. Added the method Connection::setSilenceConnError in order to silence connection errors in certain cases. * [Change] Major changes on sql tool. Now it's possible to manage several database instances on the same server connection. * [Change] Moved the code that was handling database objects tree from SQLToolWidget to DatabaseExplorerWidget * [Change] Improvements on DBMS export process. Now the process detects when a object is being created, changed or dropped returning the correct message to the user. * [Change] Minor fix on Role::getAlterDefinition. * [Change] Removed the generation of inheritance command from Table::getAlterDefinition and moved to Relationship::getInheritDefinition. * [Change] Minor update on sql highlight configuration file. * [Change] Minor adjustments on schema files for CREATE commands. * [Change] Minor update on sql-highlight.conf. * [Change] Several changes on schema files related to comment command formatting. * [Change] Removed the attribute ParsersAttributes::DIF_SQL due its deprecation. * [Change] Improvements on all schema files that makes use of @{pgsql9x} attribute. Those attributes were deprecated and replaced by comparison expressions. * [Change] The method SchemaParser::storePgSQLVersion was removed due to the deprecation of attribute @{pgsql9x}. * [Change] Minor change on the Connection class to return the full version or only the major one of the server. * [Change] Code blocks where there was a special treatment to get object's name filtering by object's type (specially function and operator) were replaced by a single call to BaseObject::getSignature(). * [Change] Improved the way many-to-many relationships can be configured. Now the generated table can have a single column as primary key or a multi-valued one. * [Change] The ModelWidget::convertRelationshipNN method was improved in order to correctly convert many-to-many relationships with single or multi-valued primary key. * [Change] Removed the restriction from Catalog and DatabaseImportForm to hide the "postgres" database. * [Change] Minor change on how drop command is generated for collations. * [Change] Minor fix on fields which accepts expressions to show scroll bars as needed. * [Change] Changed the order of actions on left control bar at main window. * [Change] Minor improvement on export to png process. The output image is generated with a margin. * [Change] Minor change on sample models and asset images. * [Change] Minor changes on TextboxView. * [Change] Changed the style of graphical resentation for schemas, views, tables. Now they are drawn with rounded borders. * [Change] Minor improvements on how sql disabled info item is generated and managed. * [Change] Change the relationship cardinality pattern from (1,n) to 1:n. * [Change] Minor label adjustment for many-to-many relatinships. * [Change] Minor adjustments on textbox resizing. * [Change] Minor adjustments on relationships custom points descriptors in order to give better selection and movement. * [Change] Minor improve when moving a schema object. Relationship points will be moved together. * [Change] Minor editing forms size adjustments. * [Change] Changed the layout of modeldatabasediffform.ui and added hint text widgets. * [Change] Changed the hint texts on general config, relationship config and model restoration form. * [Change] Minor change on relationship editing form, by default random line colors are enabled. * [Change] Minor fix on temporary models saving process. * [Change] Explicit hint texts were moved to the instances of the new class HintTextWidget. * [Change] Minor improvement on database editing form. LC_COLLATE and LC_CTYPE can be freely modified. * [Change] Minor improvement on primary key constraints. Columns added to them will be marked as not-null by default. This is done to avoid false-positive changes on the model db diff process. * [Change] Improvements on main window in order to give more visibility to SQL tool and central widget. Now there are three different views (welcome, design and manage). * [Fix] Minor fixes throught the code in order to remove g++ warnings. * [Fix] Minor fix on table's SQL schema file. * [Fix] Minor fixes on demo version code. Remove the execution time limit and increased the maximum objects count. * [Fix] Fixed a bug when generating XML code for materialized views that was causing these objects to break DTD rules. * [Fix] Minor fix on code generation of permissions. * [Fix] Minor fix on permissions editing form. * [Fix] Fixed a bug on database import process that was crashing the application whenever importing a composite type. * [Fix] Minor fix on reverse engineering process when importing columns which reference user defined type that are in pg_catalog. * [Fix] Minor bug fix on database import process that was causing some crashes. * [Fix] Minor improvements on "move to schema" feature on model widget. The references to moved object are now correctly updated. * [Fix] Minor fix on SyntaxHighlighter that was not correctly applying the default font to the parent object. * [Fix] Minor fix on index class and editing form to accept FILLFACTOR no matter the indexing method used. * [Fix] Minor fix when removing table children objects and restoring them from operations list. * [Fix] Fixed a crash when reverse engineering a model. The crash was due to trying to handle a not existent graphical object for pg_catalog schema. * [Fix] Fixed the resizing of schema objects. * [Fix] Minor fixes on schema editing form. * [Fix] Additional fixes for export model to png. Now the correct bounding rect is calculated. * [Fix] Fixed a bug when exporting model to png that was exporting unnecessary blank areas. * [Fix] Fixed the click on the object selector input field. When the control is disabled the object selection dialog will not be opened. * [Fix] Minor fix on domain class and editing form that was not resetting the constraint name attribute. * [Fix] Minor fix on model validation helper to avoid include the database as a referer of other objects. * [Fix] Fixed a bug when renaming objects and invalidating their references. * [Fix] Fixed a bug on schema parser when converting chars to xml entities. v0.8.0-alpha2 ------ Codename: Faithful Elephant
Release date: September 30, 2014
* [New] Added an option on general settings to disable ask to validate model before save, export and diff. * [New] If the user try to save, export or diff a model and it is invalidated, pgModeler will first validate and then proceed with the pending operation. * [New] Added an entry on general settings to control how graphical objects are created. * [New] Added an option to disable render smoothness to improve performance on large models. * [New] Added the method Catalog::getObjectsOIDs in order to retrieve all database objects oid and store them in maps. This method is used as an auxiliary for model-database diff process. * [New] Added the method ConnectionsConfigWidget::fillConnectionsComboBox() in order to reuse the code that fills up a combobox with configured connections. * [New] Added the ability to create special primary key on many-to-many relationships. * [New] Added the ability to save the dock widgets configuration on the main configuration file. * [New] Added methods to retrieve objects by their names on DatabaseModel class. * [Change] The configuration form was reestrucured decreasing the size occupied on the screen. * [Change] Minor improvement on model fix dialog. * [Change] Minor improvement on constraint import. Fillfactor attribute now is correcly retrieved. * [Change] Removed extern directives referencing configurations from SyntaxHighlighter and ModelWidget converting the used attributes to static ones. * [Change] Changed the way threads are created, as well the import and diff helpers instances to avoid race conditions and crashes. * [Change] Schemas by default will be created to show the bounding rectangle. * [Change] Minor improvement on BaseObject::getTypes() in order to exclude some types from the resulting vector. * [Change] Minor widgets adjustment on modeldatabasediffform.ui, modelexportform.ui and databaseimportform.ui. * [Change] Updates on several resource images. * [Change] Minor change on example.dbm file. * [Change] Minor change on DatabaseImportHelper to accept a DatabaseModel instance instead of ModelWidget. * [Change] Minor adjustments on deployment scripts. * [Fix] Fixed issue with Inno Setup invalid bitmap error (Windows). * [Fix] Fixed a bug that was preventing encrypted password to be configured for roles. * [Fix] Fixed a crash whenever user quit the application on Mac OSX. * [Fix] Minor fixes in order to compile using Qt 5.3.2. * [Fix] Fixed a bug when starting the creation process of relationships on model widget. * [Fix] Fixed a bug related to individual permission exclusion and object removal error when there are permissions attached to it. * [Fix] Fixed typos on demo version warning messages. * [Fix] Fixed a bug that was not generating FILLFACTOR attribute for constraints. * [Fix] Minor fix on object naming rules. Now the dollar sign ($) is accepted in the middle of object's name. * [Fix] Fixed a bug when import domains which have the same name as some tables. * [Fix] Fixed a bug on trigger class and editing form that was preventing the "FOR EACH ROW" attribute to be saved. * [Fix] Fixed a infinite loop on operation list class when calculating the chain size. * [Fix] Fixed a crash when creating relationships. Apparently this crash was caused by a faulty access on some threads right after close the relationship dialog. * [Fix] Fixed the bug that was preventing a sequence to be assinged to a column. * [Fix] Fixed a bug on relationship validation process that was causing errors mainly related to generalization relationships. * [Fix] Fixed a bug on xml parser when reading DTD files from paths that contains accentuated chars. * [Fix] Minor fix on Messagebox class when replacing
tags on message text. * [Fix] Minor fix on conditional compilation macros entries for demo version. v0.8.0-alpha1 ------ Codename: Faithful Elephant
Release date: August 15, 2014
* [New] pgModeler now is capable to handle table's data through the new data manipulation form. * [New] The SQL tool received a basic find/replace widget. * [New] Created a new environment variable for samples directory, PGMODELER_SAMPLES_DIR. * [New] Source code dialog now optionally appends the SQL of permissions for the current object. * [New] Added an option to the source code privew dialog to include table's children objects' SQL. * [New] Added a field on all object's editing form to expose the object's internal id. * [New] Added an option on the database import process to generate random colors for relationships. * [New] The model objects widget gained a filtering field that is capable to list objects by their name or internal id. * [New] Added support to custom SQL for rules, indexes and triggers. * [New] Added two new sample models. * [Change] Changed the shortcut for "About pgModeler" to F4 key. * [Change] Minor update on shortcuts and tooltips of buttons on bottom control bar at main window. * [Change] Minor improvement on model validation. Now the DDL executed for any object is shown on the output field. * [Change] Minor change on object's id interval generation. * [Change] Minor adjust on model export process to force the code cache invalidation when using the unique name generation option. * [Change] Message box objects are now used on demand and no more as class attributes. * [Change] The software startup was hugely improved by removing singleton dialogs from main window's constructor, now they are used on demand. * [Change] Minor update on sql-highlight.conf file. * [Change] Sample models can be now loaded direclty from the main windows's central widget. * [Change] Enhancement on the messages of model validation output. * [Change] Minor fix on object's schema files to correctly generate the appended/prepended SQL code. * [Change] Major improvement on all core classes (resposible to represent database objects) in order to keep their cache syncronized with the current configuration. * [Change] Object finder now highlights the parent table if the user selects a child object of the first. * [Change] Minor improvement on CLI. Added a routine to change a table structure, moving the tags rule, index and trigger to outside of it. * [Change] Changed the way on how the relationship connection points are determined. Now they depends on how the tables' center points are distant from each other. * [Change] More improvements done on database model objects classes in order to give more speed on the code generation. * [Change] Update for French (fr_FR) translation. * [Chage] Minor improvements on swap objects ids dialog. * [Change] Huge improvement on validation process mainly for reverse engineered models. Now pgModeler honors the imported structure and in a few cases there will be inconsistencies. * [Change] The objects rule, index and trigger will have the SQL/XML code generated outside of table's definition due to validation process that sometimes needs to swap id's of those objects. * [Change] The object selector will trigger the object selection if user click the input field. * [Change] Changed the 'line color' attribute of relationships to 'custom color'. * [Fix] Fixed a crash provoked by the constraint editing form when switching the constraint type on the second time the form is opened. * [Fix] Minor fix on database import process that was wrongly checking all tables as unlogged. * [Fix] Minor fix on sample models pagila.dbm and usda.dbm to remove the unlogged attribute. * [Fix] Minor fix on class CodeCompletionWidget to make it persistent as well to remove duplicate items from listing. * [Fix] Minor fix on message box instances to resize according to the height of the current message. * [Fix] Fixed a crash whenever the user cancelled the changes on settings and tried to connect to a server using the SQL tool. * [Fix] Minor fix on SQLToolWidget to disable controls in some situations. * [Fix] Minor fix on BaseRelationship and Relationship classes to correctly invalidate envolved object's when connecting or disconnecting. * [Fix] Fixed a crash when closing the last model and the object finder was visible with result list filled. * [Fix] Object finder now doesn't show duplicated items. * [Fix] Minor fix on model objects widget when assigning a null model. * [Fix] Fixed the problem with function parameter name not being generated due to cached code. * [Fix] Minor fix on index editing form layout. * [Fix] Fixed the import of rule object on DatabaseImportHelper class. * [Fix] Fixed a bug when displaying the cardinalities for fk relationships. * [Fix] Fixed a bug on the reverse engineering process that was wrongly migrating 'timestamp with time zone' data type as 'timestamp' only. * [Fix] Fixed a bug on the reverse engineering process that was preventing the migration of operator classes / indexes that contains duplicated elements. v0.8.0-alpha ------ Codename: Faithful Elephant
Release date: July 21, 2014
* [New] Added support to using global settings for relationships on the editing form of those objects. * [New] A new section was created on settings dialog to manage global configurations for relationships. * [New] Enabled the movement of schema objects without the need to select their children. This operation does not applies to protected or system schemas like public, pg_catalog. * [New] Created a more elaborated central widget with some basic operations like create, load, load recent models and restore previous session. * [New] Reletionships 1:1, 1:n and fk now supports a new style of link between tables. The foreign key columns will be directly linked to primary key columns. * [New] Created a class called ColorPickerWidget to handle operations where the user need to configure colors for objects. * [New] Relationship objects now supports custom line colors. * [New] Added the static methods setPgSQLVersion and getPgSQLVersion on BaseObject class in order to override the PostgreSQL version used to generate code for all instances of that class. * [New] Introduced a method DatabaseModel::getXMLParser() in order to return the xmlparser of the model to permit user create new objects from xml code within the current database model. * [Change] Minor adjustment on central widget buttons style on MacOS X. * [Change] Disabled the collapsed main menu on MacOS X due to particularities on GUI of this system. * [Change] Minor adjustment on main menu construction on Linux/Windows. * [Change] Major change on main UI style in order to make a cleaner interface and gain more space on canvas to handle models. * [Change] Minor model objects style refreshment. * [Change] Minor optimization on class AppearanceConfigWidget by adding color pickers in order to select color of the elements. * [Change] A significant code optimization was made on TagWidget by changing the tool buttons that was handling color configuration by color pickers. * [Change] Added a color picker on RelationshipWidget to permit the configuration of custom line color. * [Change] Minor layout adjustment on update notifier widget. * [Change] Important change on SchemaParser class which is not a singleton anymore in order to minimize crashes due to race conditions on running threads. * [Change] Important change on XMLParser class which is not a singleton anymore in order to minimize crashes due to race conditions on running threads. * [Fix] Fixed a bug related to partial command execution on SQL tool. * [Fix] Minor fix on model navigation widget when closing a model. * [Fix] Fixed a bug that was crashing pgModeler when switching models with the overview widget opened. * [Fix] Fixed a bug that was eventually making pgModeler enter on a endless looping when calculating the chained operations length. * [Fix] Fixed a regression related to special objects recreation after rename a primary key column. The problem was that the relationship was wrongly storing the old name of the columns at connection time. v0.7.2 ------ Codename: Brave Mastodon
Release date: June 27, 2014
* [New] Added the missing attribute BUFFERING for Gist indexes. * [New] Added an experimental installer for Linux based upon the Qt Installer Framework. * [New] Added an file called RELEASENOTES.md. This file will be read by the update notifier on server in order to return to the GUI the change log and additional release info. * [Change] Minor change on MacOS X deployment script to generate the dmg file with a custom icon. * [Change] Restored the start-pgmodeler.sh file due to difficulties that some users are having when running pgModeler on Linux systems. * [Change] Created the folder "installer" to store all files related to installers of all platforms * [Fix] Fixed a regression related to sequences not being included on database model XML code. * [Fix] Fixed deployment on Linux. Now start-pgmodeler.sh is correclty copied. * [Fix] Fixed the display of relationship actions on NewObjectOverlayWidget v0.7.2-beta1 ------ Codename: Brave Mastodon
Release date: June 21, 2014
* [New] Added support for event trigger objects. The export and import processes were adjusted to handle this kind of object. * [New] Added support for UNLOGGED tables. * [New] Enabled PostgreSQL 9.4 export and import processes. * [New] Enabled the jsonb datatype for PostgreSQL 9.4. * [Change] Rolled back to Qt 5.2.1 the version used by the macdeploy.sh script due to crash reported in issue #494 and #482. * [Change] SQL tool improvement. Added a "drop cascade" action and fixed a bug when refreshing a specific item on database tree. * [Fix] Minor fix on ColumnWidget, disabled the line breaking in the field "Expression". * [Fix] Fixed the model fix dialog on MacOS X and Windows platforms. * [Fix] Schemas names are now correctly striked out on the rectangle when their SQL code is disabled. The system schemas public and pg_catalog will continue not to have their names striked out. * [Fix] Fixed a bug that was preventing default values of domains to be loaded from file. v0.7.2-beta ------ Codename: Brave Mastodon
Release date: June 06, 2014
* [New] Added an option to convert integer type to serial ones on columns which default value is a nextval(seq::regclass) call. * [Change] Changed the MacOS X deployment script to use Qt 5.3. * [Change] Minor size adjustment on the new object overlay. * [Change] The model objects widget now clears the selection when it lost the focus. * [Change] Minor change on new object overlay behavior. The overlay will be hidden when any tool button on it is pressed or the ESC key is pressed. * [Change] The partial database import was improved. Now pgModeler is capable to resolve dependencies of foreign key constraints, creating the needed tables automatically. Additionally, domains are automatically imported when referenced by columns. * [Fix] Fixed compilation process on Windows system. * [Fix] Fixed the crash handler call inside the main program. * [Fix] Minor fix on "object's deps. & refs." dialog that was triggering an error when trying to open a table child object from there. * [Fix] Added a entry on DatabaseModel::getObjectDependecies() to get the sequence that a column depends on. * [Fix] Fixed a bug column editing dialog that was wrongly removing the sequence assigned to a column. * [Fix] Fixed sample plugins compilation when using a LIBDIR value other than the default. * [Fix] Fixed the build number generation at compilation time. * [Fix] Minor fix on TableTitleView class to correctly strikeout the schema name only when the schema rectangle is not visible. * [Fix] Minor adjustment on databaseimportform.ui size. * [Fix] Fixed the custom page size bug due to patches provided by Qt 5.3. A conditional compilation statement was added on portions where the custom page size is used. This way the code can be build on any Qt version but the fix will available only on 5.3. * [Fix] Minor fix on the Linux deployment script. v0.7.2-alpha1 ------ Codename: Brave Mastodon
Release date: May 30, 2014
* [New] Introduced a "new object" overlay widget which gives user a quick access to actions that create objects. * [New] Added a step to fix indexes with old tag on command line interface. * [New] Added support to item interaction on "object's dependencies and references" dialog. * [New] Added support to generate temporary names for database, roles and tablespaces when running validation process. This will avoid errors if the original database and the other objects already exists on the server. * [New] Updated the CLI to include the option to generate temporary object's names. * [New] Added suppport to save and restore the last position and zoom on the canvas. This behavior can be deactivated on general settings. * [New] Added support to prepend SQL commands on object's definition. * [New] Added zoom info popup that appears whenever the user changes the current zoom factor. * [Change] Renamed the methods setCheckExpression and getCheckExpression methods to setExpression and getExpression because the expression is used either for check and exclude constraints. * [Change] Renamed the attribute "condition" to "predicate" on index class. * [Change] Improved the way SQL code is disabled/enabled on editing forms. User now is asked to apply the same disabling/enabling status to object's refereces. * [Change] Minor size adjustment on SQL append dialog. * [Change] Changed the order of the tabs on user-defined type editing form. * [Change] Minor appearance improvement on textbox editing form. * [Fix] Made visible the field related to predicate expression on exclude constraint editing form. * [Fix] Added reference checking between an exclude constraint and operators. * [Fix] Minor fix on copy operation that was not resetting the copied objects list if the user clicked several times the "copy" command without paste. * [Fix] Minor fix on the model object widget when disabling the controls. * [Fix] Minor fix on ModelWidget::createSequenceForColumn() operation. The generated sequence is now correctly assigned to the column. * [Fix] Minor fix on pgModeler command line interface menu text. * [Fix] Minor fix on permission.dtd file. Attribute "index" was incorreclty marked as required when its optinal. * [Fix] Minor fix on semantics of one-to-one relationship. When one of the tables are of mandatory participation the foreign key columns must not accept null values. * [Fix] Minor fix on Windows and Linux deployment scripts. v0.7.2-alpha ------ Codename: Brave Mastodon
Release date: May 06, 2014
* [New] Added a basic routine to check if there is some new version available on pgModeler site. * [Change] Custom indexes for columns and constraints added by relationships are now stored on tables. In previous version the relationship was the responsible for that but this approach was provoking the bug related on issue 449. * [Change] Remove unused parser attributes and commented old code. * [Change] Removed attributes and methods from relationship which were responsible to control columns, attributes and constraints indexes. * [Fix] Fixed a bug that was changing the columns positions whenever a relationship was edited on the model. * [Fix] Minor fix when generate the string that denotes the assigned constraints to a column. * [Fix] Minor fix on function editing form when handling the result table columns. The variadic field is disabled on the parameter form. * [Fix] Fixed a crash when removing a view linked to tables. * [Fix] Minor fix on view reference code generation. * [Fix] Minor editing form size adjustments. * [Fix] Minor compilation fix on Windows system. v0.7.1 ------ Codename: Brave Mastodon
Release date: April 15, 2014
* [New] Added option to invert panning mode and range selection triggers. * [New] Added support to use relationship attributes as special primary keys. * [Change] Improvement on unique name generation for columns and constraints when connecting relatioships. * [Change] Improvement on copy / paste operations. * [Change] Minor workaround in order to try to fix the crash due to thread conflict mainly on Windows system. * [Fix] Minor fix on custom columns positioning. * [Fix] Input and output files are now correctly escaped on the model fix form and the process works fine. v0.7.1-beta1 ------ Codename: Brave Mastodon
Release date: April 8, 2014
* [Change] Minor change on project's description text on about dialog. * [Fix] Workaround for the slow editing of function's definition. Disabled the automatic syntax highlighting. * [Fix] Minor fix on reverse engineering process. In some cases the process was aborted due to duplication of relationships caused by an incorreclty name generation for this kind of object. * [Fix] Minor fix on model objects widget when changing the visible object types. * [Fix] Fixed the conflict with panning mode and graphical object addition operation. * [Fix] Fixed a regression introduced by 0.7.1-beta on model fix process. v0.7.1-beta ------ Codename: Brave Mastodon
Release date: April 6, 2014
* [New] Created a small interface to pgmodeler-cli that enables the user to fix a broken model inside pgModeler GUI. * [New] Added support to assign a sequence as default value of a column. The sequence will be converted to "nextval('seqname'::regclass) and the validation process will check if the sequence is correctly referenced by the table that owns the column. * [Change] Changed the default behavior of left click on blank areas of canvas. Instead of create a range selection the user will move the viewport (panning mode). To enable range selection user must press SHIFT and click/move to draw the selection rectangle. * [Fix] Minor fix on connection class in order to accept empty passwords as well passwords that contains spaces. * [Fix] Fixed the column listing on constraint editing form after remove one or more columns. * [Fix] Fix a crash when canceling the model saving dialog on Windows. * [Fix] Minor patch on the model fix process. * [Fix] Fixed wrong default values for relationship added columns. * [Fix] Fixed a bug related to file paths with ampersand on config files. * [Fix] Fix the broken sql for inheritance when a child table don't have columns but only constraints. v0.7.1-alpha1 ------ Codename: Brave Mastodon
Release date: March 29, 2014
* [Change] Major model validation improvement. Now special objects are correctly validated. * [Fix] Fixed a crash when closing a model that contains a view that references columns added by relationships. * [Fix] Fixed wrong working directory handling on CLI. * [Fix] Fixed a bug on file loading process that could left behind some objects depending on size and arrange of the loaded model. * [Fix] Fixed the undesired behavior when moving a table to another schema. v0.7.1-alpha ------ Codename: Brave Mastodon
Release date: March 21, 2014
* [Fix] Fixed connection config. Empty passwords are now accepted. * [Fix] Fixed schema object code generation. * [Fix] Fixed the usage of PGMODELER_SCHEMAS_DIR environment variable on import process. * [Fix] Fixed "ALTER ... SET OWNER" DDL for materialized views. * [Fix] Fixed duplicated semicolon at end of permissions defintion. v0.7.0 ------ Codename: Brave Mastodon
Release date: February 25, 2014
* [New] Addded a catalog attribute "hide-postgres-db" in order to avoid listing "postgres" maintainance DB on import operations. * [New] Added options to hide system/extension objects on SQL tool improving the object listing performance. * [New] Added support to custom compilation output directory through qmake variables BINDIR, LIBDIR and RESDIR. * [New] Added support to deferrable unique, exclude and primary key constraints. * [New] Added support to custom colors on tables and views through tag objects. * [New] Added support to export models to png image page by page. * [New] Canvas can now be moved using Control + Arrow keys. If the shift is pressed the movement factor is increased. * [New] Introduced the SQL tool that permits the execution of arbitrary SQL commands direclty on a server. * [New] Added methods getType, getTypeId to BaseType and getSQLTypeName to PgSQLType as an alternative to call operators ~, ! and *. * [New] Added a commented DROP command at start of each object definition (CREATE or ALTER TABLE ADD) * [New] Added a "Code Preview" tab on permissions dialog. * [New] Enabled SQL code visualization for FK relationships. * [New] Added a build number on about dialog. This number is the compilation date in format yyyymmdd. * [New] Added support for materialized and recursive views (PostgreSQL 9.3 feature). * [New] Added pgModeler version information on generated sql scripts as well .dbm files for debugging purpose. * [New] Added support to custom delete/update actions for relationship generated foreign keys. * [New] Added support to move the canvas by positioning the mouse over corners. * [New] Added a configuration parameter to control font style for any source code highlight field. * [New] Added additional PostGiS types: geomval, addbandarg, rastbandarg, raster, reclassarg, unionarg, TopoGeometry, getfaceedges_returntype, validatetopology_returntype. * [Change] Added support to on-demand updates on sql tool object's tree. * [Change] Improved the tab navigation experience on editing forms. * [Change] Minor change on SQL tool to ommit binary data values. * [Change] Dropped the navigation through object using Alt + due to the difficulty to understand the order in which objects are highlighted. * [Change] Minor change when generate .stacktrace file for crash handler to include pgModeler build number. * [Change] Minor adjustments on DatabaseImportForm's import execution progress. * [Change] Minor enhancements on operation list when removing last operations. * [Change] Minor enhancements on table and relationship dialogs on error control flow. * [Change] Changed Z-value for relationship labels in order to avoid that name labels don't overlaps the cardinality labels. * [Change] Removed the translation installing from within plugin loading method at PluginsConfigWidget. * [Change] The Application class constructor now loads at once all translation files available for the current language including language file for plugins. * [Change] Minor changes on deploy scripts on all platforms. The parameter '-with-build-num' was introduced in order to generate a package with build number. * [Change] Relationship dialog enhanced. Now participant tables are described in what role they make part. * [Change] Minor improvement on model export process. * [Change] Minor improvement on model validation widget. * [Change] Minor improvement on crash handler report generation message. Full path to crash file is now shown. * [Change] Improved the message displayed when user try to save an invalidated model. * [Change] Minor adjustment on model export dialog size. * [Change] Minor improvement on model overview widget. * [Change] Minor adjustments on window title buttons for model export and database import forms. * [Change] Improvement on connection config form. pgModeler now ask to save/update unsaved connection if the user forgot to. * [Change] Minor update sql syntax highlighting configuration file. * [Fix] Fixed bug that was permitting paste already formatted text (html) on source code input fields. * [Fix] Fix broken range type generation. * [Fix] The DELETE privilege is now correclty saved on model. * [Fix] Fixed drop object command on SQL tool. * [Fix] Fixed bug that was crashing pgModeler when a error was raised on view edit form. * [Fix] Fixed a bug that was crashing the application when deleting relationship attributes or constraints. * [Fix] Fixed bug related to the range selection weird behavior when finishing creating a object. * [Fix] Minor fix on OperationList undo/redo methods to update types names on tables that references a modified type. * [Fix] Minor fix on View assignment operator to correctly rename the type associated with "this" object. * [Fix] Minor fix on DatabaseModel to correctly return the references to a view type. * [Fix] Fixed bug that was causing indexes/triggers that references columns added by relationship have the sql code generated twice. * [Fix] Minor fix on ResultSet class to identify bytea columns. * [Fix] Minor fix on CLI menu to add new export modes. * [Fix] Fixed a crash dealing with duplicated columns on a table. * [Fix] Fixed bug when deleting tables and fk relationships together. * [Fix] Fix bug related to geometry type. * [Fix] Minor fix on logical expressions evaluation on SchemaParser. * [Fix] Minor fix on model export when showing the name of objects being exported. * [Fix] Minor fix on list/view advanced objects of a relationship. * [Fix] Minor fix on form resizing when showing the protected object alert. * [Fix] Fixed a minor bug that was crashing pgModeler when visualizing many-to-many relationships. * [Fix] Fixed some warnings triggered by clang compiler. * [Fix] Fixed a crash when loading plugins on MacOSX. * [Fix] Fixed the issue related to import roles from database. pgModeler will not query pg_shadow anymore since this view is a very restricted object. Now role passwords will be imported as ***** (according to docs). * [Fix] Fixed the object name validation. pgModeler now accepts spaces within names. * [Fix] Fixed the function editing form resizing. * [Fix] Fixed a bug that was not loading "sql disabled" state for relationships. * [Fix] Fixed incorrect behavior of "Zoom In" action on MacOSX. * [Fix] Trying to fix the infinite loop of the Validation confirm dialog on Windows (more tests needed). v0.6.2 ------ Codename: Daring Mammoth
Release date: December 20, 2013 * [Change] Update Qt version to 5.2.0 on build scripts (Windows only). * [Change] Linux binaries are now bundled with all needed Qt libs. * [Change] Important change on the way that special primary keys are created for generalization/copy relationships. Now there is the need to create the relationship first, close the dialog and open it again in order to generate the columns that will be used on the primary key. * [Fix] Fixed a bug on model loading and relationship validation that was causing pgModeler to ignore some special objects (constraints referencing columns generated by relationships). * [Fix] Workaround done on the sql append widget when handle a lot of code avoiding slowdowns on the syntax highlighting. * [Fix] Fixed the incorrect creation of foreign keys on many-to-many relationships. * [Fix] Fixed the conversion of self many-to-many relationships. * [Fix] Fixed a bug that was causing some constraints to be destroyed when the relationship was connected to the table that owned the constraint. * [Fix] Comments that contains apostrophes now are correctly escaped in order to avoid SQL related errors. * [Fix] Fixed the incorrect generation of SQL code of check constraint associated to many-to-many relationshps. * [Fix] Minor fix on crash handler when trying to read an stack trace file that doesn't exists. * [Fix] Minor typos fixes on CLI menu. * [Fix] Minor fix on the about form positioning. v0.6.2-beta ------ Codename: Daring Mammoth
Release date: November 29, 2013 * [New] Added an option to drop database before a export process. * [New] Disabling SQL code now disables the code of all referrer and child objects (experimental!). * [New] Added support for columns to reference "table types". * [Change] Object names are trimmed on editing forms to avoid unnecessary error triggering. * [Change] Minor improvement on crash handler form. * [Change] Minor change on SQL validation message. * [Change] Minor improvement on operation list. * [Fix] Fixed a crash when adding foreign keys to a new table. * [Fix] Fixed the import of foreign key constraints from PostgreSQL 9.3. * [Fix] Fixed the creation of fk relationships when the involved tables has too long names. pgModeler no more complains about "already existent object". * [Fix] Minor fix when showing self fk relationships. * [Fix] Minor fix on pgmodeler-cli: working directory is now set correctly. * [Fix] Minor fix when retrieving advanced (generated) objects from relationships. * [Fix] Fixed a bug that was not properly removing table objects when the user was canceling the table's editing. v0.6.1 ------ Codename: Daring Mammoth
Release date: November 3, 2013 * [New] PostgreSQL version 9.3 activated on code base. Now import and export operations works with this new version. * [Change] Changed the way inheritance is created. Now the INHERIT command is appended in the table's definition. * [Change] Update on model validation. Generalization and copy relationships have the participant tables' id's validated in order to check reference breaking. * [Change] Version info upgraded on MacOSX app bundle configuration file (Info.plist). * [Change] Minor change on "pgmodeler.vars". Included environment variables for custom Qt installation. * [Fix] Fixed a bug related to INSTEAD OF/ON UPDATE triggers on views. * [Fix] Fixed a bug related to incorrectly error raised when setting a owner table in the same schema as the sequece. * [Fix] Fixed a bug related to importing sequences which name has uppercase characters. * [Fix] Fixed misspelled "Connetion" word on configuration form. * [Fix] Typos correction on model validation message box. * [Fix] Fixed incorrect objects removal after cancel the edition. * [Fix] Minor fix on disconnection of generalization relationships. * [Fix] Minor fix on updating table's graphical representation when importing primary keys. * [Fix] Minor change when displaying the columns' types on table/relationship editing form. * [Fix] Fixed the compilation process on MacOSX 10.9 (Mavericks). * [Fix] Minor change on macdeploy.sh to use Qt5.2-beta by default. v0.6.0 ------ Codename: Daring Mammoth
Release date: September 30, 2013 * [New] Added a validation when removing protected FK relationships. * [New] Added a progress info (at bottom widgets bar) for temporary model saving. * [New] User can now restore the last session via File > Restore Session. Sessions will not be restored at startup anymore. * [New] Added a "zoom" option when exporting to PNG image. * [Change] Disabled the model loading via command line on MacOSX due to bundle particularities. * [Change] Remove option "Save session" from general config widget. * [Change] Improved the way schema's children objects are selected/unselected. * [Change] Improved the printing operation. Now custom paper size has a separated field to assign it's coordinates. * [Change] The import errors now are written on a log file when "ignore import errors" is checked. * [Fix] Fixed an inconsistence when removing a table before the fk relationship linked to it. From now on (to avoid crashes) user must remove the relationship first and then remove the table. * [Fix] Fixed a minor bug on column's graphical representation that was incorrectly configuring the column descriptor for self-relationship fk's. * [Fix] Minor fix on model overview widget when showing large models. * [Fix] Fixed bug on pgmodeler-cli that was generating errors when running it outside the executable's directory. * [Fix] Fixed the calculation of pages to be printed. * [Fix] Fixed the type enumeration validation to accept space on the names. * [Fix] Minor fix for GiS types. Spatial auxiliary type name can null. * [Fix] Minor pgmodeler-cli typos corrections. * [Fix] Fixed a bug related to XMLParser and threads that was crashing pgModeler on Windows. * [Fix] Fixes on DatabaseImportHelper to correctly handle extension created types. * [Fix] Minor fix on PgSQLType::parseString() when creating datatypes from strings. v0.6.0-beta ------ Codename: Daring Mammoth
Release date: September 16, 2013 * [New] Added experimental reverse engineering support. * [New] Added an experimental option --fix-model to pgmodeler-cli to permit the user to fix the structure of an older model (generated in pgModeler < 0.6.0) or a corrupted file. * [New] Added an option to debug the import process printing any generated code to stdout. * [New] Added support for bidirectinal FK relationships. * [New] Added a statement "SET search_path [schemas]" on database model SQL code. * [New] Added missing PostgreSQL built-in types. * [New] Configured connections now can be duplicated in order to reuse it's attributes. * [Change] Minor change on main compilation script. The subproject "tests" are included only when compiling in debug mode. * [Change] Major change on validation widget. Fixes are now applied using a thread and can be aborted any time user want. * [Change] Change on model saving process. pgModeler will not deny to save invalidated anymore. Now it will ask the user to validate the model or save an invalidate one anyway. * [Change] Changed the behavior of the operation list. In the first exception the entire list are emptied. * [Change] Changed the way foreign keys are generated. They always will be generated at end of database definition to avoid reference breaking. * [Change] Minor improvements on model code generation and copy operations. * [Change] Removed deprecated "rtree" indexing type. * [Fix] Minor fixes on PgSQLType class. User types aren`t removed instead they are deactivated to avoid reference breaking. * [Fix] Minor fix on selecting the children objects of a schema. * [Fix] Minor fixes on scene and relationship avoiding crashes when destroying the whole graphical scene. * [Fix] Fixed bug on deleting self relationships. * [Fix] Minor fix on model export process. The last line of the SQL code now is correctly extracted and executed. * [Fix] Minor fix on sequence class to accept owner. * [Fix] Minor fixes on the splash screen control code. * [Fix] Fixed a bug that was crashing pgModeler at startup. * [Fix] Fixed a bug that was causing pgModeler to crash when loading operators which name contained '&' char. * [Fix] Fixed bug related to sequence values assignment. * [Fix] Fixed "Operation with not allocated object" error on applying validation fixes. * [Fix] Fixed relationship label position saving. * [Fix] Minor fix on main window. pgModeler now is not closed while the validation is running. v0.6.0-alpha1 ------ Codename: Daring Mammoth
Release date: August 05, 2013 * [New] Added catalog query for triggers. * [New] Added catalog query for rules. * [New] Added indexing method to exclude constraint. * [New] Added catalog query for constraints. * [New] Added catalog queries for tables and columns * [New] Added catalog queries for view, domain, sequence and user defined types. * [New] Added catalog query for collation. * [New] Added catalog query for operator family. * [New] Added catalog query for operator class. * [New] Object dependencies form now can list indirect dependencies. * [New] Added an environment variable to set a different location for crash handler executable. * [New] Objects that has SQL disabled now is shown with name striked out. * [Change] Minor change on MainWindow::closeEvent() * [Change] Moved app_style variable to GlobalAttributes::DEFAULT_QT_STYLE. * [Change] Minor improvement on Exception::getExceptionsText method. * [Change] Improvements on copy/paste operations. * [Change] Removed unused linker parameters. * [Change] Crash handler executable renamed to "pgmodeler-ch". * [Fix] Fixed possible leak when destroying a ModelWidget instance. Objects from scene were not being deleted correclty. Fix tests in progress. * [Fix] Fixed the "Save current session" option on GeneralConfigWidget that wasn't doing it's job correctly. * [Fix] Fixed a bug that was crashing pgModeler at startup when restoring previous sessions or temporary models. * [Fix] Minor fix on trigger code generation. * [Fix] Fixed incorrect loading of multiple triggers/rules on views. * [Fix] Minor fix on model validation. Operator classes are now checked during the validation process. * [Fix] Fixed generation of constraints in form of ALTER command. In some cases the constraint code wasn't appended to table's definition. * [Fix] Minor fixes on cast object. * [Fix] Minor fixes on databasemodel on retrieving dependencies/references for objects. * [Fix] Fixed crash handler path variable on MacOSX. v0.6.0-alpha ------ Codename: Daring Mammoth
Release date: July 19, 2013 * [New] Added the widget to swap objects IDs on model validation form. * [New] Added indexing type "spgist" to IndexingType class. * [New] Model validation and export now works with threads. * [New] Functions now have a "leak proof" attribute. * [New] VARIADIC key attribute added to function parameters. * [New] User now can completely disabled UI stylesheets by calling executable with param "-no-stylesheet". * [New] Added the class Catalog to handle the basis of reverse engineering by reading the pgcatalog/information_schema. * [New] System tablespaces pg_global and pg_default are now automatically created as new models are added. * [Change] Minor change on schema area selection. The entire schema area and children can be selected (and moved) by using "Select children" action or SHIFT + left-click. * [Change] Improved the transition between opened models. The problem was solved putting the temporary models saving in a separated thread. * [Change] Minor improvement on model restoration operation. Models that fails to be restored can be kept so the user can try to fix them manually (until pgModeler is closed). * [Change] Minor adjustments on model loading progress. * [Change] Minor chages on model export form. Export to DBMS is the default option. * [Change] Minor improvements on pgmodeler-cli. Added "--simulate" option to export dbms. * [Change] Disabled notice output to console for Connection class. User can re-enable it by calling Connection::setNoticeEnabled() [recompile source needed]. * [Change] Minor changes on PgSQL base types. "[NO] LEAKPROOF" removed from FunctionType class. * [Change] Minor improvements on SchemaParser, now its possible to make parser ignore empty attributes. * [Change] libdbconnect renamed to libpgconnector for semantics reasons. * [Change] Minor improvements on CrashHandler. Added buttons to load report and save embedded model when in analysis mode. * [Fix] Minor fix on linuxdeploy.sh script related to grep command execution. * [Fix] Fixed some leaks when destroying objects that are registered as PgSQLType (table, sequence, extension, domain, view, type). Now these type are correctly remove from user type listing. * [Fix] Fixed bad sql code generation when disabling sql of columns/constraints. * [Fix] Fixed dependency retrieving for operator classes. * [Fix] Fixed incorrect reference to "replicate" option on Roles. * [Fix] Fixed the "ignore duplicity" bug for columns when exporting model. * [Fix] Fixed library build order now libpgmodeler is built before libpgconnector. * [Fix] Minor fix on UI stylesheet related tooltips when using Fusion theme. * [Fix] Fixed the assignment of LC_COLLATE, LC_CTYPE and template db to database instance on DatabaseWidget. v0.5.2 ------ Codename: Lovely Duda
Release date: June 27, 2013 * [New] User now can append free SQL commands to database objects via "Append SQL" command. * [New] Introduced an experimental code completion on fields that permits code input. * [New] User can create default sequences from serial columns. This feature does not apply to columns generated by relationships. * [New] Introduced a feature to break relationship lines in straight angles and to remove all user added points. * [New] Added support to change font size on textboxes. * [Change] Removed the code "OIDs=FALSE" from table's SQL. * [Fix] Minor fix on Mac OSX deployment script. v0.5.1_r1 --------- Codename: Lovely Duda
Release date: June 13, 2013 * [New] Added deployment scripts on all platforms to compile and pack pgModeler. Note: On Windows the script must run on GNU environment port like Cygwin or MingW. * [New] Added an special field to columns to easily identify which relationship generated it. (only for columns added by relationship) * [Change] Model overview widget is now shown always stay on top. * [Change] Minor improvements on syntax highlighter. * [Change] Improvements on model validation widget. Output panel now shows the currently validated object (SQL validation). * [Fix] Removed from user defined type DTD the mandatory use of collation object. * [Fix] Collation's SQL generation corrected. Encoding is appended to LOCALE keyword. * [Fix] Corrected the wrongly used COLLATION keyword on user defined type. * [Fix] Corrected a bug that was crashing pgModeler when selecting relationship created objects on object finder result list. * [Fix] Extension object naming corrected. * [Fix] Extension object removal corrected. * [Fix] Corrected a bug on CLI that was not finding dependencies paths correctly. * [Fix] Minor fix on task progress widget on MacOSX. * [Fix] Splash screen corrected on MacOSX * [Fix] Corrected a bug on relationships that was crashing pgModeler when specifying column name pattern. v0.5.1 ------ Codename: Lovely Duda
Release date: June 1, 2013 * [New] Code base ported to C++11 and Qt5. * [New] MacOSX compilation now generates an application bundle: pgmodeler.app * [New] pgModeler is now capable of associate dbm files to its executable being possible opening a model from file manager by clicking it (except for MacOSX, see MacOSX notes). * [New] Added support for loading models by calling pgModeler gui executable from terminal (e.g. pgmodeler model1.dbm model2.dbm) * [New] pgModeler logo redesign. * [New] Added special primary keys support to one-to-one and one-to-many relationships. * [New] Relationships now supports patterns to define generated objects names. The manual suffix and auto-suffix generation are deprecated. * [New] Columns/constraints generated by relationship can have position changed on parent table. * [New] Added smallserial built-in datatype. * [Change] Improvements on model validation tool. pgModeler will not save the model while isn't completely validated. * [Fix] minor fix on point insertion on relationships. * [Fix] Corrected the wrongly displayed interval fields. * [Fix] Corrected self relationship validation. * [Fix] Corrected a bug on editing numeric data types. * [Fix] Minor fixes on build scripts (All platforms). * [Fix] Added the missing directive CONFIG+=console to main-cli.pro * [Fix] Minor fixes on task progress exhibition on quick tasks. * [Fix] pgmodeler-cli output fixed on Windows system. * [Fix] Table inheritance now copies columns with NOT NULL attribute correclty configured. * [Fix] Plugin build scripts fixed. Now generated libraries are correctly copied to build directory. * [Fix] Editing a column with 'numeric' datatype does not generate errors anymore. v0.5.0 ------ Release date: May 17, 2013 * [New] Complete main window restyling. * [New] Added a model validation tool to prevent reference break and name conflicts. * [New] Added an object navigation using keyboard on model widget. Pressing Alt + [left|right] keys will switch between graphical objects. * [New] Introduced the pgmodeler-cli. A command line tool to handle model export without loading the graphical interface. * [New] Added an option to list available configured connections on pgmodeler-cli. * [New] pgModeler now alerts the user when he try to save an invalidated model. * [New] pgModeler now aborts app closing when the user wants to do a last saving on modified models. * [New] Added support to hide relationship labels and table extended attributes on configuration dialog. * [New] Added "Recent Models" menu. * [New] Introduced the Xml2Object plugin to help on develpment testings. * [New] Added partial support to PostgreSQL Extensions objects. * [New] Added JSON datatype. * [New] Added support for rules and trigger on views. * [New] Added support for user defined range types. * [New] Added support for collations on composite types (user defined). * [New] Added built-in range types. * [New] Added support to INCLUDING/EXCLUDING options when dealing with copy relationships. * [New] Added support for EXCLUDE constraint support * [New] Added NO INHERIT option to check constraints. * [New] Added REPLICATION option to roles. * [New] Added FOR ORDER BY option and removed Recheck from OperatorClassElement. * [New] Added collation support for index elements. * [New] Added [NOT] LEAKPROOF key word to functions. * [New] Added collation attribute to domains. * [New] Required fields are now highlighted on editing forms. * [New] pgModeler creates system objects (e.g, public schema and SQL, C, plpgsql languages) when adding a new model. * [Change] Minor improvements on when showing Views. * [Change] Relationship points are moved when the parent relationship is being moved together with other objects. * [Change] Simplified the model loading operation. pgModeler will not try to recreate objects with unsatisfied dependencies instead errors will be raised. * [Change] Minor changes on FK relationship creation. * [Change] User-added foreign-keys had code generation changed. * [Change] Minor improvements on PgModelerPlugin structure. * [Change] DummyPlugin renamed to Dummy. * [Change] Improvements on building process for all supported systems. * [Change] Removed "Save widget positions" from configuration form. * [Change] Removed fullscreen mode from main window. * [Change] Removed unused/deprecated error messages. * [Change] Removed deprecated files COMPILING.md and PLUGINS.md. * [Change] Subproject libutil was renamed to libutils due to some conflicts on Linux systems. * [Change] Startup scripts removed. Since the environment variables are set by the installer on Windows and for Unix the variables are set using the new pgmodeler.sh script. * [Change] "Disable SQL code" option added for all types of objects. Except for textboxes and base relationships (view-table relatioships and fk relationships). * [Change] Fixed permissions for views. * [Change] PostgreSQL 8.x support completely removed. * [Change] Schema files (for SQL code) aren't organized in folders anymore. All code (for different PostgreSQL versions) will be in the same .sch file for each object. * [Change] Spatial types had SRID digit count upgraded to 5. * [Change] One-to-one relationships now generates unique names for UNIQUE constraints. * [Change] Several class improvements, performance tunings and forms readjustments. * [Fix] Minor fixes on connection configuration form. * [Fix] Corrected a bug that was crashing pgModeler when adding new schemas. * [Fix] Corrected a bug that was crashing pgModeler when validation model. * [Fix] Corrected a bug that was preventing the popup menu to be configured correctly on model widget. * [Fix] Menu bar style correctly applied on Windows system. * [Fix] Now relationship labels' position are restored when loading the model file. * [Fix] Minor fixes on database model code generation. * [Fix] Corrected the glicthy wheel scroll/zoom on model widget. * [Fix] Corrected the visual update of schema's rectangle when adding a column on a child table. * [Fix] Corrected a bug that was preventing a new model to be saved correctly. * [Fix] Minor fixes on model widget copy/paste operations. * [Fix] Models now are correclty auto saved when modified. * [Fix] Corrected operator's signature generation. * [Fix] Corrected a bug on textbox with unicode texts. * [Fix] Index and Rule editing forms now handles correctly unicode expressions. * [Fix] Corrected a bug that was avoiding the name "remembering" during relationship loading. v0.4.1_r1 --------- Release date: March 19, 2013 * [Change] user can now prepend a CTE (commom table expression, a.k.a "with queries") on view's definition. * [Change] user can now create a single reference containing a expression that defines the entire view. * [Change] improvements on permissions, user now can control GRANTs and REVOKEs via permission editing form. * [Fix] fixed invalid UTF-8 chars on function definition. * [Fix] fixed unavailable "nocreatedb" role option. v0.4.1 ------ Release date: March 16, 2013 * [New] introduced the "Disable SQL code" option for roles/tablespaces. * [New] user now can add objects by right-clicking group items on "Model Objects" dockwidget tree. * [New] added the abbreviation for time and timesptamp data types both with timezone: timetz and timestamptz. * [New] introduced a object highlight action on "model objects" dockwidget. * [Change] major changes on SQL code generation/export. Introduced a token to help export process to identify the end of each DDL command. * [Change] minor improvements on role editing form. * [Change] when generationg XML code empty tags that stores pure texts are now created with a tag in order to avoid malformed xml code. * [Change] index FASTUPDATE and FILLFACTOR params is now activated according the indexing type. * [Change] index fill factor now is optional. * [Change] chinese, portuguese and french translations update. * [Fix] pgModeler no longer crash when in error state (showing an exception) and try to auto save the models. * [Fix] minor size adjustments on forms. * [Fix] corrected a bug related to one-to-many relationship validation (endless looping) when changing to automatic suffix generation. * [Fix] corrected the "apply button disabled" bug on constraint edit form. * [Fix] IN/OUT keywords now appears on functions signature. * [Fix] corrected translation bypassing on index edit form. * [Fix] pgModeler no longer crash when triggering the print action. * [Fix] triggers no longer complains about assigning a function without parameters. * [Fix] corrected the loading process for indexes. * [Fix] corrected some bugs related to GiST and index sorting. * [Fix] minor fix on quick rename action when renaming a column with primary key. * [Fix] corrected a bug that was causing pgModeler to complain about duplicated elements when loading indexes. * [Fix] corrected a bug related to main window title when save a model with a different filename. * [Fix] fixed a bug related reload a model file after editing a foreign key. * [Fix] corrected a bug related to invalid chars at task progress. v0.4.0_r1 --------- Release date: March 04, 2013 * [New] introducing the "pgModeler Wiki" as the main project's support resource. * [Fix] when main windows is closed the overview widget is closed too. * [Fix] corrected a bug on operation list widget that was converting an item name to UTF-8 twice. v0.4.0 ------ Release date: February 27, 2013 * [New] introduce a "New object" submenu when activating the schema context menu (right-click) * [New] tables and view are now graphically separated by colored rectangles representing its schemas. * [New] compiling pgModeler now works perfectly on Mac OSX system. * [New] introduced the 'Quick actions' menu that permits: rename, move to another schema, change onwer and edit permissions. * [New] the relationship editing form gained an "advanced" tab which shows the objects generated and/or represents the relatioship itself. * [New] the user now can add relationships only creating foreign keys on tables (fk relationships). * [New] added a french UI translation (provided by [toorpy](https://github.com/toorpy)). * [Change] all relationships type are now grouped together on "Model objects" widget. * [Change] chinese UI translation updated (provided by: [Bumanji](https://github.com/Bumanji)). * [Change] user now can remove fk relationships directly without needing to remove the related foreign keys. * [Change] field semantics adjustments on relationship editing form. * [Change] graphical object can be now selected and have the context menu activated only with a single right-click. * [Change] minor improvements on plugin base class: PgModelerPlugin. * [Change] widget size adjustments to better showing on Mac OSX system. * [Change] crashhandler now shows the compiled and running versions of Qt. * [Change] french UI translation reviewed and updated (provided by [babs](https://github.com/babs)). * [Change] 'Objects of Model' when used as object picker now expand all the nodes by default. * [Change] 'Objects of Model' now memorizes the tree state when update an object and / or opening another model. * [Change] PostGiS 'geometry' type can have a free assigned SRID value. * [Change] editing forms when shown set the focus on the first field, generally, the object name. * [Change] 'Objects of Model' widget displays the nodes in alphabetical order. * [Change] the printing options for the model were moved to the general configuration form. * [Change] relationship validation method now removes fk relationships when the foreign keys that gerenates is no longer exists. * [Change] copy/cut/delete commands does not manipulates system objects like schema public and languages C, SQL and plpgsql. * [Change] pgModeler startup scripts are now path location free meaning that software can be installed where the user desires. * [Fix] corrected a bug related constraint name on domain XML code generation. * [Fix] corrected a bug that was causing crash when click "Apply" on Type editing form with fields not filled. * [Fix] corrected the "invalid constraint name" error on domain editing form. * [Fix] corrected the empty DEFAULT clause for columns, types and domains. * [Fix] corrected a bug related to incorrectly initialized OID attribute when creating tables. * [Fix] corrected a bug when creating a view with WHERE statement. * [Fix] corrected a bug related to one-to-many relationships semantics. * [Fix] corrected some bugs that was causing crash when removing all operations from operation list. * [Fix] minor bug fixes related to object selection over the model. * [Fix] corrected a bug on load model dialog filter (chinese UI only). * [Fix] pgModeler no longer crash when editing objects style. * [Fix] corrected bug that was deleting two sequeces at once. * [Fix] pgModeler no longer crash when removing (disconnecting) relationship that has special primary keys. * [Fix] minor fixes on the startup scripts on all platforms. * [Fix] corrected an incorrect reference to output stream on Windows system. * [Fix] shortcuts and popup menu now works correctly when selection an object on 'Objects of Model' tree. * [Fix] the pgsql base types (represented by tables, sequences, user defined types and domains) are now updated correctly when the related schema is renamed. * [Fix] corrected some weird SRID value on non spatial types. * [Fix] corrected bug on objects table when move rows to last / first. * [Fix] typos corrections on some error messages and dialog titles. * [Fix] 'referenced columns' combobox on constraint editing form are filled correctly when the dialog is shown in a second time. * [Fix] pgModeler no longer crash when creating many-to-many relationships. * [Fix] pgModeler no longer crash when the user activates the print dialog. * [Fix] corrected bug that was removing fk relationships when pasting objects. * [Fix] corrected SQL syntax error of 'timestamp with time zone'. * [Fix] corrected constraint type showing on editing form. * [Fix] corrected bug on cyrillic typed enums and check constraints expressions. * [Fix] corrected bug on enumeration type editing form. * [Fix] corrected bug on 'truncate' table privilege code generation. * [Fix] corrected column default value code generation. * [Fix] dummyplugin build process corrected on Windows. * [Fix] corrected bug on column comment code generation. * [Fix] corrected bug that was deleting two tables at once. v0.3.4 ------ Release date: October 17, 2012 * [New] added chinese UI translation (provided by [gjunming](https://github.com/gjunming)). * [New] added basic support for PostGiS 2.0 only data types: box2d, box3d, geometry and geography (suggested by [george-silva](https://github.com/george-silva) on [issue#28](https://github.com/pgmodeler/pgmodeler/issues/28))(EXPERIMENTAL). Note: when using these data types make sure that PostGiS extension is installed on database cluster since pgModeler WILL NOT install it automatically or generate the command to do it! * [New] added a model restoration feature to reopen models after unexpected quit (crash). * [New] added a crash handler to pgModeler. Now signal SIGSEGV is trapped (in most cases) and the crash handler pops up permiting the user to generate an error report. (EXPERIMENTAL) * [New] to facilitate the error reporting exceptions stack now can be showed in text format. Users can post the complete error stack when creating an issue. * [New] icon added to pgModeler executable (Windows only) * [Change] update on pt_BR translation file. * [Change] removed "pgmodeler" prefix from translation files. * [Change] added the field "Underline" on textbox editing form. * [Fix] corrected the "AlwayOnTop" bug on model overview widget. ([issue#30](https://github.com/pgmodeler/pgmodeler/issues/30)) * [Fix] little fix on startup scripts. Corrected de PGMODELER_ROOT on both Linux and Windows systems. ([issue#29](https://github.com/pgmodeler/pgmodeler/issues/29)) * [Fix] corrected the referece to environment variables PGMODELER_*. Now pgModeler search for necessary paths on current directory if some of these variables are not set. * [Fix] corrected the validation of UTF-8 names that have 3 bytes length. * [Fix] corrected the sources path reference on project (.pro) files. Now lupdate command do not generates empty TS files. * [Fix] corrected a bug that was causing crash where user try to edit protected objects. * [Fix] corrected the exhibition of UTF-8 messages on ```throw``` statements. v0.3.3 ------ Release date: October 09, 2012 * [Change] pgModeler license were update to GPLv3. * [Change] Error massages and entire UI were translated to en_US. Now people can contribute more easily with translation files. [(issue#8)](https://github.com/pgmodeler/pgmodeler/issues/8) * [Change] The left side image were removed form all forms giving more space to show widgets. * [Change] pgModeler now shows a messagebox at startup if any critical error is raised instead to show them on stdin. * [Fix] Translation files now are correctly loaded depending on system language. [(issue#23)](https://github.com/pgmodeler/pgmodeler/issues/23) * [Fix] Compilation process and execution is working correctly on Windows system. [(issue#11)](https://github.com/pgmodeler/pgmodeler/issues/11) * [Fix] No more crashes when dealing with relationships that have special triggers/indexes/columns. [(issue#8)](https://github.com/pgmodeler/pgmodeler/issues/8) [(issue#24)](https://github.com/pgmodeler/pgmodeler/issues/24) v0.3.2 ------ Release date: September 27, 2012 * [Change] The default extension for the models now stands for ".dbm" [(issue#9)](https://github.com/pgmodeler/pgmodeler/issues/9) * [Change] Tables and sequences now can be used as function return type as well parameter type. This is valid for other objects that make use of base types (except for table columns). * [Change] The relationship conversion command now need to be confirmed by the user. * [Fix] Compilation process now works correctly on Windows system. * [Fix] Adjusted the size of some forms to show their fields properly. * [Fix] The "make distclean" command now make the correct cleanup on build/ directory. * [Fix] Startup scripts "start-pgmodeler.(sh|bat)" where adjusted. To prevent errors pgModeler need to be started through these scripts. * [Fix] Corrected the reference to the plugins directory. [(issue#7)](https://github.com/pgmodeler/pgmodeler/issues/7) * [Fix] The action "New Object -> Tablespace" now is displayed properly. v0.3.1 ------ Release date: September 18, 2012 * [New] Relationships generates column suffixes automaticaly. This behavior can be changed on the relationship editing form. * [New] Added two samples to pgModeler. * [Change] Tables are now created with "With OIDs" attribute by default. * [Change] The graphical update method on overview widget has improved preventing unecessary processing. * [Fix] Class CenaObjetos now doesn't delete objects twice. * [Fix] Eliminated bug that caused crashing on pgModeler when closing a model. v0.3.0 ------ Release date: September 12, 2012 * [New] Added a model overview widget. * [New] Added export feature that generates PNG image of the models. * [Fix] Corrected the naming of columns generated by many-to-many relationships. * [Fix] Corrected generation of XML/SQL code by the model. v0.2.0 ------ Release date: August 31, 2012 * [New] Added an interface to implement third party plugins. Check [PLUGINS.md] (https://github.com/pgmodeler/pgmodeler/blob/master/PLUGINS.md) for details. * [New] Added a short cut to easily control the zoom on the model. Use Crtl + Mouse wheel up (zoom up) or Crtl + Mouse wheel down (zoom down). * [Change] Due to the plugin interface the compilation method changed back to the form of shared libraries + executable. * [Fix] No more crashes when removing an primary-key of a table which has relationship with other tables. [(issue#2)](https://github.com/pgmodeler/pgmodeler/issues/2) * [Fix] Adjusted the semantics of one-to-one relationships. v0.1.2 ------ Release date: August 24, 2012 * [New] Added a functionality to save modified models before closing the software. * [Change] Updated the en_US dictionary with the texts of the above functionality. * [Fix] Dockwidgets no longer disappear unexpectedly when the main window is minimized. * [Fix] Operations performed before creating a table object (column, constraint, trigger, index, rule) are no longer removed when any exception is thrown in the creation of these object. * [Fix] Fixed bug that caused user-defined types had wrong SQL/XML code generated by the model. * [Fix] Functions and Types received an own range of id in order to create these objects in a correct way. * [Fix] Eliminated segmentation faults caused by the destruction of relationships which possessed attributes/constraints. * [Fix] Adjusted the translation to SQL code of one-to-one relationships. * [Fix] Eliminated segmentation fault when editing relationships and/or undoing an operation involving a relationship. * [Fix] Identifiers relationships now correctly display the thick line beside the weak entity. v0.1.1 ------ Release date: August 14, 2012 * [Fix] Correction of the actions for inserting graphic objects (table, text box, vision and relationship) in Windows environment. * [Fix] Correction on the display of the maximize button in the window decoration in Windows environment. * [Fix] Adjust on the position and spacing of widgets in editing forms. * [Fix] The XML parser can now correctly read DTD files in Windows environment. * [Fix] The compilation method is no longer in the form of shared libraries + executable and passed to be as standalone executable only. v0.1.0 ------ Release date: August 9, 2012 * First pgModeler release. pgmodeler-0.9.2/LICENSE000066400000000000000000001044671360462764600145370ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 3., or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . pgmodeler-0.9.2/README.md000066400000000000000000000130541360462764600150000ustar00rootroot00000000000000[![](https://img.shields.io/github/license/pgmodeler/pgmodeler.svg)](https://github.com/pgmodeler/pgmodeler/blob/master/LICENSE) [![](https://img.shields.io/github/issues-raw/pgmodeler/pgmodeler.svg)](https://github.com/pgmodeler/pgmodeler/issues) [![](https://img.shields.io/github/issues-closed-raw/pgmodeler/pgmodeler.svg)](https://github.com/pgmodeler/pgmodeler/issues?q=is%3Aissue+is%3Aclosed)
![](https://img.shields.io/github/languages/code-size/pgmodeler/pgmodeler.svg) [![](https://img.shields.io/github/tag-date/pgmodeler/pgmodeler.svg)](https://github.com/pgmodeler/pgmodeler/tags) [![](https://img.shields.io/github/last-commit/pgmodeler/pgmodeler/master.svg)](https://github.com/pgmodeler/pgmodeler/commits/master) Introduction ------------ pgModeler - PostgreSQL Database Modeler - is an open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards. Please, let me know how the pgModeler is working on your system! Help to improve this project, give your feedback about the software or report any bug at [Issues](https://github.com/pgmodeler/pgmodeler/issues) page. Additionaly, follow the pgModeler profile on [Facebook](https://www.facebook.com/pgmodeler) or [Twitter](https://twitter.com/pgmodeler) and be up-to-date with new features, fixes and releases. Licensing --------- This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See [LICENSE](https://github.com/pgmodeler/pgmodeler/blob/master/LICENSE) for details. Donate to pgModeler ------------------- Much effort, coffee, chocolate, time and knowledge is being devoted to this project so that a reliable and constantly improved product can be delivered to the community. If you liked pgModeler and think it deserves a contribution please donate any amount (via PayPal) at [project's official site](https://pgmodeler.io). Developers and Reviewers wanted! -------------------------------- pgModeler grown bigger and reached a state where its lonely developer cannot handle all the modifications and new features requests. So if you know C++ and Qt framework programming and wants to contribute with coding let me know! I'll be grateful for any help to the project! Compiling/Installation ---------------------- For details about installation process from source code visit the [Installation](https://www.pgmodeler.io/support/installation) section. If you don't want to compile pgModeler there are binaries available for purchase at [official site](http://www.pgmodeler.io/purchase). Known Issues ----------- * pgModeler can't handle correctly the importing of complex CSV files (multilined cell values) in data manipulation form or pasting CSV content of that complexity on that dialog. * Due to the CVS importing limitations any value copied or exported from pgModeler in CSV format will be automatically formatted in the proper way that the tool can handle (by escaping any special caracter like line breaks and tabulations). If you intend to use CSV files generated by the tool in other software you have to revert back that characters escaping so the file can be read properly by third party softwares. * Due to the usage of Qt's raster engine to draw objects, the process of handling objects on the canvas tends to get slower as lots of objects are created causing constant CPU usage. A heavy performance degradation can be noticed when dealing with models with ~500+ tables and/or relationships. There're plans to improve the speed of drawing operations for large models for future releases. * The diff process still presents false-positive results due its limitations. Sometimes, there is the need to run the process twice to get the full changes. * pgModeler does not fully supports the [quoted identifier notation](http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS). When using quoted identifiers only the following characters are accepted in the middle of names: a-z A-Z 0-9 _ . @ $ - / \ space. * pgModeler is unusable in sandboxed Mac OS X installations. To workaround this issue you'll need to deactivate sandbox usage to run pgModeler properly. There is no planning to adapt this tool for sandbox feature in Mac OS X. * pgModeler can't be compiled in Microsoft Visual Studio due to use of some gcc/clang extensions. * Compiling the source using '-Wconversion' (disabled by Qt in its defaults) generates a lot of warnings. These warnings are harmless in 99% of times but we can't just ignore them but I don't plan to fix them in a near future. * pgModeler sometimes can crash during the export, import or validation process due to some threaded operations that, depending on size and arrange of the model, causes race conditions. * Due to particularities on executing bundles on MacOSX the file association does not work correctly on this system. So it's not possible to open a model file by clicking it on Finder. Change Log ---------- The detailed log of changes can be seen on [CHANGELOG.md](https://github.com/pgmodeler/pgmodeler/blob/master/CHANGELOG.md) file. Older Releases/Code ------------------- Older releases of pgModeler can be found at [Sourceforge.net](http://sourceforge.net/projects/pgmodeler) pgmodeler-0.9.2/RELEASENOTES.md000066400000000000000000000055231360462764600157360ustar00rootroot00000000000000v0.9.2 ------ Release date: December 26, 2019
Changes since: v0.9.2-beta2
Summary: this is the end of a long development cycle that started still in May, 2018 when the stable 0.9.1 was released. This one is composed by 84 new features, 134 fixes and 146 changes in total.
This release was intended to be just a fine tuning of what was constructed in alpha and beta versions and it only includes new relavant feature included specifically to generate data dictionaries in HTML format from database models.
This was a request from many users that needed an extra form of documenting their databases. Data dictionary generation feature is still considered experimental despite of being a relatively simple functionality. So, there's always room for improvements.
Finally, the changes of this version are detailed below. For the complete list of changes/fixes, please, read the CHANGELOG.md.
* [New] Add support to data dictionaries generation in HTML format in ModelExportForm. * [New] Added options to control data dictionary generation in CLI. * [New] Plugins now can optionally be associated to a menu action or not. Generally, an plugin not associated to a menu action is automatilly executed during the startup (see PgModelerPlugin::initPlugin). * [New] Added a missing model fix step on CLI that removes the IN keyword from functions signatures. * [Change] Making BaseRelationship::getReferenceForeignKey() public. * [Change] Isolated duplicated code in MainWindow::isToolButtonsChecked that checks if any tool button of the bottom or right widget bars is checked. * [Change] Removing the plugins from core code. * [Change] Modified pgmodeler.pro to include plugins folder when present in the source root (either in debug or release mode). * [Change] Ignoring plugins folder in the core code. * [Change] Minor improvement on ModelWidget::rearrangeSchemasInGrid in order to consider the amount of tables to determine the minimum grid size used to rearrange table. * [Change] Minor text adjustments in CLI. * [Change] Added an additional checking during relationship creation in order to avoid the creation of 1-* or n-n relationships involving partition tables. * [Change] Removing the restriction to create 1-1, 1-n and n-n relationships in which the involved tables are partitioned ones. * [Change] Disabling the SQL statment ALTER...OWNER TO in the object's SQL when the owner role has its SQL disabled but the object itself not. This will avoid reference errors when validating/exporting code. * [Fix] Fixed the "Save" action enabled state according to the current model's modified state. * [Fix] Fixed a crash when the user tried to edit connections in ModelDatabaseDiffForm and right after select a connection in the "Compare to" field. * [Fix] Fixed the generation of escaped comments for columns. pgmodeler-0.9.2/conf/000077500000000000000000000000001360462764600144435ustar00rootroot00000000000000pgmodeler-0.9.2/conf/connections.conf000066400000000000000000000006751360462764600176440ustar00rootroot00000000000000 pgmodeler-0.9.2/conf/defaults/000077500000000000000000000000001360462764600162525ustar00rootroot00000000000000pgmodeler-0.9.2/conf/defaults/connections.conf000066400000000000000000000007221360462764600214440ustar00rootroot00000000000000 pgmodeler-0.9.2/conf/defaults/diff-presets.conf000066400000000000000000000015701360462764600215170ustar00rootroot00000000000000 pgmodeler-0.9.2/conf/defaults/example.dbm000066400000000000000000000173161360462764600204010ustar00rootroot00000000000000

Waiting process to start...

 ModelFixForm<html><head/><body><p>[pgmodeler-cli not found error]</p></body></html>G

[pgmodeler-cli not found error]

 ModelFixForm@Rechercher l'outil pgmodeler-cliBrowse for pgmodeler-cli tool ModelFixFormImpossible de localiser l'outil <strong>%1</strong> sur <strong>%2</strong>. Le processus de rparation ne peut continuer ! Vrifiez votre installation de pgModeler ou spcifiez manuellement la commande ci-dessous.Could not locate %1 tool on %2. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below. ModelFixForm"Rparer un modleFix model file ModelFixFormTentatives : Fix tries: ModelFixFormDans certains cas, le processus de rparation peut chouer restaurer et rcuprer tous les objets du modle, ce qui peut rclamer des modifications manuelles dans le fichier partir d'un diteur de texte. <strong>REMARQUE :</strong> les associations peuvent perdre leur configuration graphique tels que des points placs manuellement par l'utilisateur ou la couleur.In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. NOTE: relationships may lost their graphical configuration like custom points and line color. ModelFixForm Fichier source : Input file: ModelFixFormlCharger le modle rpar une fois l'opration termineLoad fixed model when finish ModelFixForm2Rparer un fichier modleModel file fix ModelFixFormFichier cible : Output file: ModelFixForm@Slectionner le modle rparerSelect input file ModelFixFormBSlectionner un fichier de sortieSelect output file ModelFixFormCe fichier n'est pas l'outil en ligne de commande de pgModeler (pgmodeler-cli).JThe specified file is not the pgModeler command line tool (pgmodeler-cli). ModelFixFormHProcessus en attente de lancement...Waiting process to start... ModelFixFormXOutil en ligne de commande de pgModeler (%1) pgModeler command line tool (%1) ModelFixFormpgmodeler-cli :pgmodeler-cli: ModelFixForm<(modle pas encore enregistr)(model not saved yet)ModelNavigationWidget......ModelNavigationWidgetAlt+CModelNavigationWidget Fermer Close modelModelNavigationWidgetCtrl+Gauche Ctrl+LeftModelNavigationWidgetCtrl+Droite Ctrl+RightModelNavigationWidgetFormulaireFormModelNavigationWidgetModle suivant Next modelModelNavigationWidget Modle prcdentPrevious modelModelNavigationWidget......ModelObjectsWidget11ModelObjectsWidgetPar identifiantBy IDModelObjectsWidgetAnnulerCancelModelObjectsWidgetTout effacer Clear AllModelObjectsWidget2Replier tous les lmentsCollapses all itemsModelObjectsWidget chapEscModelObjectsWidget8Dvelopper tous les lmentsExpands all itemsModelObjectsWidgetFiltrer :Filter:ModelObjectsWidget Cacher ce widgetHide this widgetModelObjectsWidgetIdentifiantIDModelObjectsWidgetVue en liste List viewModelObjectsWidget Objets du modle Model ObjectsModelObjectsWidget Objets de modle Model objectsModelObjectsWidgetNouveauNewModelObjectsWidget ObjetObjectModelObjectsWidget<Filtres d'affichage des objetsObjects view configurationModelObjectsWidgetObjet parent Parent ObjectModelObjectsWidgetType parent Parent TypeModelObjectsWidget RetourReturnModelObjectsWidgetSlectionnerSelectModelObjectsWidget"Tout slectionner Select AllModelObjectsWidgetVue en arbre Tree viewModelObjectsWidgetTypeTypeModelObjectsWidget.Types d'objets visiblesVisible object typesModelObjectsWidget Impossible de gnrer l'aperu de l'image. La taille demande%1 x%2 tait trop grande et il n'y avait pas assez de mmoire allouer !zFailed to generate the overview image. The requested size %1 x %2 was too big and there was not enough memory to allocate!ModelOverviewWidget,Vue gnrale du modleModel overviewModelOverviewWidgetA&nnuler&CancelModelRestorationForm&Restaurer&RestoreModelRestorationFormBase de donnesDatabaseModelRestorationFormFichierFileModelRestorationFormConserver les modles temporaires en cas d'chec de la restauration4Keep temporary models in case of restoration failureModelRestorationForm,Restauration de modleModel restorationModelRestorationFormModifiModifiedModelRestorationForm TailleSizeModelRestorationFormpgModeler n'a pas t ferm correctement lors d'une prcdente excution et certains modles taient encore en cours d'dition. Cliquez sur <strong>Restaurer</strong> pour rouvrir les modles ou sur <strong>Annuler</strong> pour abandonner la restauration.pgModeler was not closed properly in a previous execution and some models were still being edited. Click Restore to reopen the models or Cancel to abort the restoration.ModelRestorationFormpgModeler va essayer de rcuprer les modles slectionns mais ne les dtruira pas en cas d'chec de chargement. Cette option sert de dernier recours pour essayer de rcuprer le modle de base de donnes. Les modles temporaires resteront jusqu' ce que l'application soit ferme. L'utilisateur doit donc essayer de rcuprer manuellement les fichiers avant de quitter pgModeler.?pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler.ModelRestorationFormHOpration annule par l'utilisateur.Operation canceled by the user.ModelValidationHelperIl y a des erreurs en attente ! La validation SQL ne sera pas excute.>There are pending errors! SQL validation will not be executed.ModelValidationHelper......ModelValidationWidget00ModelValidationWidget(<em>L'objet ci-dessus a t cr par une relation. Changer le motif du nom sur sa relation de gnrateur. La correction ne sera pas applique !</Em>The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!ModelValidationWidget<strong>CONSEIL :</strong> essayer d'changer la relation par une autre qui est lie celle-ci via des colonnes gnres ou des contraintes pour rsoudre ce problme. Noter que d'autres objets peuvent tre perdus dans le processus d'change.HINT: try to swap the relationship by another ones that somehow are linked to it through generated columns or constraints to solve this issue. Note that other objects may be lost in the swap process.ModelValidationWidgetAuto dtection AutodetectModelValidationWidgetAnnulerCancelModelValidationWidget`Annuler le processus de validation SQL en cours.&Cancel the SQL validation in progress.ModelValidationWidgetModifie l'ordre de cration de deux objets en changeant leurs numros d'identification?Change the creation order for two objects by swapping their idsModelValidationWidgetEffacerClearModelValidationWidgetHEffacer le rsultat de la validationClear validation resultsModelValidationWidgetjObjet en conflit : <strong>%1</strong> <em>(%2)</em>.6Conflicting object: %1 (%2).ModelValidationWidgetVConnexion utiliser dans la validation SQL+Connection to be used in the SQL validationModelValidationWidget Ctrl+SCtrl+SModelValidationWidgetZModle de base de donnes valid avec succs.&Database model successfully validated.ModelValidationWidgetActive la validation du code SQL dans la SGBD. Ce processus ncessite l'utilisation d'une connexion pr-configure. La validation SQL ne se produira qu' la dernire tape (lorsque tous les objets ont t valids) ou lorsqu'il n'y a pas d'avertissement.Enables the validation of SQL code in DBMS. This process requires the use of a pre-configured connection. SQL validation will occur only in the last step (when all objects were validated) or when there are no warnings.ModelValidationWidgetErreurs : le modle ne peut tre sauvegard tant que des erreurs de validation subsistent.BErrors: model will not be saved while there are validation errors.ModelValidationWidget chapEscModelValidationWidgetFormulaireFormModelValidationWidget Fermer ce widgetHide this widgetModelValidationWidgetOptionsOptionsModelValidationWidget*Version de PostgreSQLPostgreSQL versionModelValidationWidget4Traitement de l'objet : %1Processing object: %1ModelValidationWidgetxObjet rferent : <strong>%1</strong> <em>(%2)</em> [id: %3].%1 (%2) [id: %3].ModelValidationWidgetRRelation : <strong>%1</strong> [id : %2].+Relationship: %1 [id: %2].ModelValidationWidgetZExcution des commandes SQL sur le serveur...!Running SQL commands on server...ModelValidationWidget Validation SQL :SQL Validation:ModelValidationWidgetLa validation SQL a chou en raison des erreurs ci-dessous. <strong>REMARQUE :</strong><em> Ces erreurs n'invalident pas le modle mais peuvent affecter des oprations telles que <strong>l'export</strong> et <strong>la comparaison</strong>. </em>SQL validation failed due to error(s) below. NOTE: These errors does not invalidates the model but may affect operations like export and diff.ModelValidationWidgetLa validation SQL n'est pas excute ! Aucune connexion dfinie.3SQL validation not executed! No connection defined.ModelValidationWidget*changer identifiantsSwap idsModelValidationWidgetL'objet <strong>%1</strong> <em>(%2)</em> [id: %3] est rfrenc par <strong>%4</strong> objet(s) avant sa cration.The object %1 (%2) [id: %3] is being referenced by %4 object(s) before its creation.ModelValidationWidget*L'objet <strong>%1</strong> <em>(%2)</em> [id : %3]%4 rfrence des colonnes cres par <strong>%5</strong> association(s) mais a t cr avant eux.The object %1 (%2) [id: %3]%4 is referencing columns created by %5 relationship(s) but is created before them.ModelValidationWidgetLe nom de l'objet <strong>%1</strong> <em>(%2)</em> entre en conflit avec celui de l'objet<strong>%3</strong>.qThe object %1 (%2) has a name that conflicts with %3 object's name(s).ModelValidationWidgetLa relation <strong>%1</strong> [id : %2] est dans un tat d'invalidation permanent et a besoin d'tre dplac.mThe relationship %1 [id: %2] is in a permanent invalidation state and needs to be relocated.ModelValidationWidgetvEssayer d'appliquer le correctif sur l lment slectionn.3Try to apply a fix on the selected validation info.ModelValidationWidgetZEssayer de rsoudre les problmes rencontrs.#Try to resolve the reported issues.ModelValidationWidgetUtiliser des noms temporaires uniques pour les objets de niveau cluster4Use unique temporary names for cluster level objectsModelValidationWidgetVa&lider Va&lidateModelValidationWidgetxAvertissements : n'empche de pouvoir sauvegarder le modle..Warnings: does not prevents model to be saved.ModelValidationWidgetpgModeler gnrera des noms uniques et temporaires pour les objets base de donnes, rle et espace de stockage. Cette option vite les erreurs de duplication d'objet lors de l'excution de la validation SQL.pgModeler will generate unique and temporary names for database, role and tablespace objects. This option avoids object duplication errors when running the SQL validation.ModelValidationWidget(aucun objet) (no objects) ModelWidget90° (horizontal) ModelWidget90° (vertical) ModelWidget90° + 90° (horizontal) ModelWidget90° + 90° (vertical) ModelWidget<strong>ATTENTION :</strong> Le modle de base de donnes est protg ! Les oprations qui pourraient le modifier sont dsactives !jATTENTION: The database model is protected! Operations that could modify it are disabled! ModelWidget<strong>ATTENTION :</strong> Supprimer une relation peut entraner des invalidations irrversibles d'autres objets dans le modle, entranant galement la suppression de ces objets invalides. Voulez-vous vraiment poursuivre ?CAUTION: Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? ModelWidget<strong>ATTENTION :</strong> Supprimer plusieurs objets la fois peut entraner des invalidations irrversibles sur d'autres objets du modle, entranant galement la suppression de ces objets invalides. Voulez-vous vraiment poursuivre ?CAUTION: Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? ModelWidget<strong>ATTENTION :</strong> Vous tes sur le point de supprimer des objets en mode cascade, ce qui signifie que des objets non slectionns seront galement supprims. Voulez-vous vraiment poursuivre ?CAUTION: You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed? ModelWidgetLAjouter un nouvel objet dans le modleAdd a new object in the model ModelWidgetTous les objets All objects ModelWidget8Copier galement les dpendences des objets slectionns ? Cela minimise la casse des rfrences lorsque les objets copis sont colls dans un autre modle.Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. ModelWidgetAlt+Q ModelWidgetAlt+S ModelWidget(Ligne d'interruption Break line ModelWidget.Changer le propritaire Change owner ModelWidgetContraintes Constraints ModelWidgetConvertirConvert ModelWidget*Convertir en squenceConvert to sequence ModelWidget$Convertir en srieConvert to serial ModelWidget CopierCopy ModelWidgetCtrl+A ModelWidgetCtrl+C ModelWidgetCtrl+D ModelWidgetCtrl+E ModelWidgetCtrl+V ModelWidgetCtrl+X ModelWidget*Code SQL personnalis Custom SQL ModelWidget CouperCut ModelWidget SupprDel ModelWidget(Supprimer en cascade Del. cascade ModelWidgetEffacerDelete ModelWidget2Dpendances && RfrencesDeps && Referrers ModelWidget,Dsactiver le code SQL Disable SQL ModelWidgetVoulez-vous vraiment convertir les relations en une table intermdiaire ?JDo you really want to convert the relationship into an intermediate table? ModelWidgetnSouhaitez-vous rellement effacer l'objet slectionn ?1Do you really want to delete the selected object? ModelWidgetpVoulez-vous %1 les enfants du schma slctionn aussi ?5Do you want to %1 the selected schema's children too? ModelWidgetDupliquer Duplicate ModelWidget Modifier donnes Edit data ModelWidget0Modifier les permissionsEdit permissions ModelWidgetDModifier les proprits de l'objetEdit the object properties ModelWidgetModifier l'ordre de cration des objets en changeant leurs identifiants5Edit the objects creation order by swapping their ids ModelWidget&Activer le code SQL Enable SQL ModelWidget"Attributs tendusExtended attributes ModelWidgetF2 ModelWidgetAccentuerFade in ModelWidgetEffets de fondu Fade in/out ModelWidgetEstomperFade out ModelWidgetNGnration du code XML pour : `%1' (%2)Generating XML for: `%1' (%2) ModelWidgetMasquerHide ModelWidgetHritage Inheritance ModelWidget"Sauter la table Jump to table ModelWidgetLOuverture du modle de base de donnesLoading database model ModelWidget6Plusieurs plusieurs (n-n)Many to Many (n-n) ModelWidget.Dplacer vers le schemaMove to schema ModelWidgetNouveauNew ModelWidgetDTous les objets n'ont pas t colls dans le modle car des erreurs ont t retournes durant le processus ! Se rfrer la pile d'erreurs pour plus de dtails !zNot all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! ModelWidget(Un plusieurs (1-n)One to Many (1-n) ModelWidgetUn un (1-1)One to One (1-1) ModelWidget(Ouvrir les relationsOpen relationship ModelWidget CollerPaste ModelWidget<Collage de l'objet : `%1' (%2)Pasting object: `%1' (%2) ModelWidget*Collage des objets...Pasting objects... ModelWidgetProprits Properties ModelWidgetVrrouillerProtect ModelWidgetREmpcher la modification du ou des objets%Protects object(s) from modifications ModelWidgetActions rapidesQuick ModelWidgetLAction rapide pour l'objet slectionn$Quick action for the selected object ModelWidget6Renommage rapide de l'objetQuick rename the object ModelWidgetAssociations Relationships ModelWidget(Supprimer des points Remove points ModelWidgetRenommerRename ModelWidgetVEnregistrement du modle de base de donnesSaving database model ModelWidgetSchmasSchemas ModelWidget*Rectangles de schmasSchemas rectangles ModelWidgetSlectionnerSelect ModelWidget"Tout slectionner Select all ModelWidget0Slectionner les enfantsSelect children ModelWidget"Slction balise Select tagged ModelWidgetbSlectionner tous les objets graphiques du modle.Selects all the graphical objects in the model ModelWidget&Affecter une baliseSet tag ModelWidgetShift+Suppr Shift+Del ModelWidgetAfficherShow ModelWidgetDAfficher le code source de l'objetShow object source code ModelWidgetSource ModelWidgetCode source Source code ModelWidget EspaceSpace ModelWidget*changer identifiantsSwap ids ModelWidgetTables ModelWidget Boites de textes Textboxes ModelWidgetLa suppression en cascade a rencontr des problmes lors de son excution ! Certains objets n'ont pas pu tre supprims ou enregistrs dans l'historique des oprations ! Veuillez vous reporter la pile d'erreurs pour plus de dtails.The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details. ModelWidgetDverrouiller Unprotect ModelWidgetBValidation de l'objet : `%1' (%2)Validating object: `%1' (%2) ModelWidgetVuesViews ModelWidgetZoom : %1% Zoom: %1% ModelWidgetprotgerprotect ModelWidgetdprotger unprotect ModelWidgetpAucune diffrence entre le modle et la base de donnes..No differences between the model and database.ModelsDiffHelperJPrparation du code de comparaison...Preparing diff code...ModelsDiffHelperfTraitement de l'info `%1' pour l'objet `%2' (%3)...,Processing `%1' info for object `%2' (%3)...ModelsDiffHelper>Comparaison des informations...Processing diff infos...ModelsDiffHelperDTraitement de l'objet `%1' (%2)...Processing object `%1' (%2)...ModelsDiffHelper@Omission de l'objet `%1' (%2)...Skipping object `%1' (%2)...ModelsDiffHelper0NewObjectOverlayWidget1NewObjectOverlayWidget2NewObjectOverlayWidget3NewObjectOverlayWidget4NewObjectOverlayWidget5NewObjectOverlayWidget8NewObjectOverlayWidget9NewObjectOverlayWidgetANewObjectOverlayWidgetAgrgat AggregateNewObjectOverlayWidgetBNewObjectOverlayWidgetCNewObjectOverlayWidget$Conversion de typeCastNewObjectOverlayWidget CollationNewObjectOverlayWidgetColonneColumnNewObjectOverlayWidgetContrainte ConstraintNewObjectOverlayWidgetConversion ConversionNewObjectOverlayWidget CopieCopyNewObjectOverlayWidgetDNewObjectOverlayWidgetDomaineDomainNewObjectOverlayWidgetENewObjectOverlayWidget2Dclencheur sur vnement Event TriggerNewObjectOverlayWidget ExtensionNewObjectOverlayWidgetFNewObjectOverlayWidgetFormulaireFormNewObjectOverlayWidgetFonctionFunctionNewObjectOverlayWidgetGNewObjectOverlayWidgetSQL gnrique Generic SQLNewObjectOverlayWidgetHNewObjectOverlayWidgetINewObjectOverlayWidgetIndexNewObjectOverlayWidgetHritage InheritanceNewObjectOverlayWidgetJNewObjectOverlayWidgetKNewObjectOverlayWidgetLNewObjectOverlayWidgetLangageLanguageNewObjectOverlayWidgetMNewObjectOverlayWidget*Plusieurs--plusieurs Many-to-manyNewObjectOverlayWidgetONewObjectOverlayWidgetUn--plusieurs One-to-manyNewObjectOverlayWidgetUn--un One-to-oneNewObjectOverlayWidgetClasse d'op. Op. ClassNewObjectOverlayWidgetFamille d'op. Op. FamilyNewObjectOverlayWidgetOprateurOperatorNewObjectOverlayWidgetPNewObjectOverlayWidget PermissionsNewObjectOverlayWidgetPolitiquePolicyNewObjectOverlayWidgetQNewObjectOverlayWidgetRNewObjectOverlayWidgetRleRoleNewObjectOverlayWidget RgleRuleNewObjectOverlayWidgetSNewObjectOverlayWidget SchmaSchemaNewObjectOverlayWidgetSquenceSequenceNewObjectOverlayWidgetTNewObjectOverlayWidgetTableNewObjectOverlayWidget$Espace de stockage TablespaceNewObjectOverlayWidgetTagTagNewObjectOverlayWidgetZone de texteTextboxNewObjectOverlayWidgetDclencheurTriggerNewObjectOverlayWidgetTypeNewObjectOverlayWidgetUNewObjectOverlayWidgetVNewObjectOverlayWidgetVueViewNewObjectOverlayWidgetWNewObjectOverlayWidgetXNewObjectOverlayWidgetYNewObjectOverlayWidgetZNewObjectOverlayWidgetNettoyerClearNumberedTextEditorDImpossible de dmarrer l'application de l'diteur de code source `%1' ! Assurez-vous que le chemin de l'diteur source dfini dans les paramtres gnraux pointe vers un excutable valide et que l'utilisateur actuel a l'autorisation d'excuter l'application. Message d'erreur renvoy : `%2'Could not start the source code editor application `%1'! Make to sure that the source editor path defined in the general settings points to a valid executable and the current user has permission to run the application. Error message returned: `%2'NumberedTextEditorModifierEditNumberedTextEditor`Modifier le code source avec son diteur prfr5Edit the source code in the preferred external editorNumberedTextEditorIdent gauche Ident leftNumberedTextEditorIdent droit Ident rightNumberedTextEditorChargerLoadNumberedTextEditor$Charger un fichier Load fileNumberedTextEditorvCharger le code source de l'objet depuis un fichier externe3Load the object's source code from an external fileNumberedTextEditorMinuscule Lower caseNumberedTextEditorXFichier SQL (*.sql);;Tous les fichiers (*.*)!SQL file (*.sql);;All files (*.*)NumberedTextEditordL'diteur de source `%1' s'excute sur pid : `%2'./The source editor `%1' is running on `pid: %2'.NumberedTextEditorMajuscule Upper caseNumberedTextEditorDpendances DependenciesObjectDepsRefsWidgetDExclure les dpendances indirectesExclude indirect dependenciesObjectDepsRefsWidgetIDIDObjectDepsRefsWidgetBInclure les rfrences indirectesInclude indirect referencesObjectDepsRefsWidget ObjetObjectObjectDepsRefsWidgetHDpendances et rfrences d'un objet"Object's dependencies & referencesObjectDepsRefsWidgetObjet parent Parent ObjectObjectDepsRefsWidgetType parent Parent TypeObjectDepsRefsWidgetRfrences ReferencesObjectDepsRefsWidgetCet objet n'existe plus. L'affichage de ses dpendances et rfrences est dsactiv.ZThis object does not exists anymore. The dependencies and references listing are disabled.ObjectDepsRefsWidgetTypeTypeObjectDepsRefsWidget......ObjectFinderWidget&Sensible la casseCase SensitiveObjectFinderWidgetEffacerClearObjectFinderWidgetTout effacer Clear AllObjectFinderWidget*Effacer les rsultatsClears the search resultsObjectFinderWidget:Dfini le filtre de rechercheDefines the search filterObjectFinderWidget*Correspondance exacte Exact MatchObjectFinderWidgetEstomperFade outObjectFinderWidgetFiltrerFilterObjectFinderWidgetChercherFindObjectFinderWidgetFormulaireFormObjectFinderWidgetN<strong>%1</strong> objet(s) trouv(s).$Found %1 object(s).ObjectFinderWidget Cacher ce widgetHide this widgetObjectFinderWidgetIdentifiantIDObjectFinderWidget&Aucun objet trouv.No objects found.ObjectFinderWidget ObjetObjectObjectFinderWidgetObjet parent Parent ObjectObjectFinderWidgetType parent Parent TypeObjectFinderWidgetMotif :Pattern:ObjectFinderWidget*Expression rguliresRegular ExpressionObjectFinderWidgetSlectionnerSelectObjectFinderWidget"Tout slectionner Select AllObjectFinderWidgetTypeTypeObjectFinderWidget........ObjectRenameWidgetAnnulerCancelObjectRenameWidgetFormulaireFormObjectRenameWidgetRenommerRenameObjectRenameWidgeten :to:ObjectRenameWidget Effacer le champ Clear fieldObjectSelectorWidgetFormulaireFormObjectSelectorWidgetSlectionner %1 Select %1ObjectSelectorWidget*Slectionner un objet Select ObjectObjectSelectorWidget$Ajouter un lmentAdd ItemObjectsTableWidgetAlt+RObjectsTableWidget ConfirmationObjectsTableWidgetCtrl+DObjectsTableWidgetCtrl+Bas Ctrl+DownObjectsTableWidget Ctrl+Fin, Ctrl+SCtrl+End, Ctrl+SObjectsTableWidgetCtrl+dbut Ctrl+HomeObjectsTableWidgetCtrl+HautCtrl+UpObjectsTableWidget SupprDelObjectsTableWidgetnSouhaitez-vous rellement supprimer tous les lments ?+Do you really want to remove all the items?ObjectsTableWidgetvSouhaitez-vous rellement supprimer l'lment slectionn ?/Do you really want to remove the selected item?ObjectsTableWidget&Dupliquer l'lmentDuplicate itemObjectsTableWidget$Modifier l'lment Edit ItemObjectsTableWidgetFormulaireFormObjectsTableWidgetInsrerInsObjectsTableWidget(Dplacer vers le bas Move DownObjectsTableWidget*Dplacer vers le hautMove UpObjectsTableWidget"Dplacer la fin Move to endObjectsTableWidget"Dplacer au dbut Move to startObjectsTableWidgetTout supprimer Remove AllObjectsTableWidget(Supprimer un lment Remove ItemObjectsTableWidgetMaj+Suppr. Shift+DelObjectsTableWidget EspaceSpaceObjectsTableWidget(Actualiser l'lment Update ItemObjectsTableWidget (objet invalide)(invalid object) OperationList......OperationListWidget00OperationListWidget11OperationListWidgetJSupprimer l'historique des oprationsDelete operation historyOperationListWidgetEffacer l'historique des oprations excutes est une action irrversible, souhaitez-vous continuer ?ZDelete the executed operations history is an irreversible action, do you want to continue?OperationListWidget(Oprations excutesExecuted OperationsOperationListWidget Cacher ce widgetHide this widgetOperationListWidgetNom : %1Name: %1OperationListWidgetObjet : %1 Object: %1OperationListWidgetFExclure l'historique des oprationsOperation history exclusionOperationListWidgetOpration : %1 Operation: %1OperationListWidgetOprations : Operations:OperationListWidgetPosition : Position:OperationListWidgetRtablirRedoOperationListWidgetAnnulerUndoOperationListWidgetcrcreatedOperationListWidgetmodifimodifiedOperationListWidgetdplacmovedOperationListWidgetsupprimremovedOperationListWidget&Classe par dfaut :Default Class:OperatorClassWidget Type d'lment : Element Type:OperatorClassWidgetlmentsElementsOperatorClassWidgetFonctionFunctionOperatorClassWidgetFonction : Function:OperatorClassWidgetIndexation : Indexing:OperatorClassWidget ObjetObjectOperatorClassWidget,Famille d'oprateurs : Op. Family:OperatorClassWidgetOprateurOperatorOperatorClassWidget(Famille d'oprateursOperator FamilyOperatorClassWidgetOprateur : Operator:OperatorClassWidgetStockageStorageOperatorClassWidget Type de Stockage Storage TypeOperatorClassWidget"Support/StratgieSupport/StrategyOperatorClassWidget&Support/Stratgie :Support/Strategy:OperatorClassWidgetTypeOperatorClassWidgetIndexation : Indexing:OperatorFamilyWidget AvancAdvancedOperatorWidgetArguments ArgumentsOperatorWidgetCommutateur : Commutator:OperatorWidget HASHESHASHESOperatorWidgetJointure :Join:OperatorWidget,Type d'argument gaucheLeft Argument TypeOperatorWidget MERGESMERGESOperatorWidgetNgateur :Negator:OperatorWidget2Fonction de l'oprateur :Operator Func.:OperatorWidgetOptions :Options:OperatorWidgetRestriction : Restrict:OperatorWidget&Type argument droitRight Argument TypeOperatorWidgetDPour crer un oprateur unitaire, il est ncessaire de spcifier <strong><em>'any'</em></strong> comme l'un de ses arguments. De plus, la fonction qui dfinit l'oprateur doit avoir seulement un paramtre et celui-ci doit avoir le mme type de donne que l'argument de l'oprateur unitaire.To create a unary operator it is necessary to specify as 'any' one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator.OperatorWidget&Valeur par dfaut :Default Value:ParameterWidgetININParameterWidget Mode :Mode:ParameterWidgetOUTOUTParameterWidgetVARIADICVARIADICParameterWidgetAcco&rder&GrantPermissionWidgetZ-- Aucune permission dfinie pour cet objet !3-- No permissions defined for the specified object!PermissionWidget/* Impossible de gnrer la prvisualisation du code SQL pour les permissions !;/* Could not generate the SQL code preview for permissions!PermissionWidget$Ajouter permissionAdd PermissionPermissionWidget&Annuler l'oprationCancel OperationPermissionWidgetCascadeCascadePermissionWidget0Prvisualisation du code Code PreviewPermissionWidget,Dsactiver le code SQLDisable SQL codePermissionWidget0Modifier les permissionsEdit permissionsPermissionWidgetGRANT OPTION GRANT OPTIONPermissionWidgetIdentifiant :ID:PermissionWidgetIdPermissionWidgetLaissez la grille <em><strong>Rles</strong></em> vide afin de crer un %1 applicable <strong><em>PUBLIC</em></strong>.|Leave the Roles grid empty in order to create a %1 applicable to PUBLIC.PermissionWidgetNomNamePermissionWidgetPermissions PermissionsPermissionWidgetPrivilge PrivilegePermissionWidgetPrivilges PrivilegesPermissionWidgetR&voquerRe&vokePermissionWidget RlesRolesPermissionWidget*Actualiser permissionUpdate PermissionPermissionWidgetT ** Ces objets ne peuvent tre corrigs : # ** Object(s) that couldn't fixed:  PgModelerCLI> %1, %2=[CODES] Ignore les erreurs supplmentaires par leurs codes. Une liste de codes alphanumriques spars par des virgules doit tre fournie. {1,?} {2 ?}{ %1, %2 [CODES] Ignores additional errors by their codes. A comma-separated list of alphanumeric codes should be provided. PgModelerCLI@ interface en ligne de commande. command line interface. PgModelerCLIImpossible d'effacer le fichier %1 ! Vrifiez si l'utilisateur actuel dispose des autorisations pour le supprimer et si le fichier existe.gCan't erase the file %1! Check if the current user has permissions to delete it and if the file exists. PgModelerCLIVOptions d'export directe dans un serveur : DBMS export options:  PgModelerCLILes fichiers de modle de bases de donnes (.dbm) sont dj associs pgModeler !@Database model files (.dbm) are already associated to pgModeler! PgModelerCLI8Extraction des objets XML...Extracting objects' XML... PgModelerCLI(Options gnrales : General options:  PgModelerCLI`Les informations de connexion sont incompltes !"Incomplete connection information! PgModelerCLIxLe fichier source doit tre diffrent du fichier de sortie !)Input file must be different from output! PgModelerCLIxAction spcifie invalide pour mettre jour l'option mime !/Invalid action specified to update mime option! PgModelerCLIFichier d'entre invalide ! Il semble que ce ne soit pas un modle gnr par pgModeler ou que le fichier soit corrompu !^Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted! PgModelerCLI0Zoom spcifi invalide !Invalid zoom specified! PgModelerCLILOpration de base de donnes mime : %1Mime database operation: %1 PgModelerCLI&Options diverses : Miscellaneous options:  PgModelerCLI2Modle fix avec succs !Model successfully fixed! PgModelerCLILL'option '%1' n'accepte pas de valeur.#Option '%1' does not accept values. PgModelerCLIBOptions d'export en PNG et SVG : PNG and SVG export options:  PgModelerCLI0Recration des objets...Recreating objects... PgModelerCLI`Excution de la commande update-mime-database...'Running update-mime-database command... PgModelerCLILLancement de la mise jour du mime...Starting mime update... PgModelerCLI<Dbut de l'export du modle...Starting model export... PgModelerCLIJLancement de la fixation du modle...Starting model fixing... PgModelerCLIJIl n'y a aucune connexion configure.$There are no connections configured. PgModelerCLIIl n'y a pas d'association entre pgModeler et .les fichiers dbm !AThere is no file association related to pgModeler and .dbm files! PgModelerCLI2Option '%1' non reconnue.Unrecognized option '%1'. PgModelerCLIJUtilisation : pgmodeler-cli [OPTIONS]Usage: pgmodeler-cli [OPTIONS] PgModelerCLIHValeur pour l'option '%1' manquante.$Value not specified for option '%1'. PgModelerCLIAVERTISSEMENT : Certains objets ne peuvent peut-tre pas tre corrigs. Nouvel essai... (%1/%2)SWARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2) PgModelerCLIAuteur : %1 Author: %1PgModelerPlugin.Information d'extensionPlugin InformationPgModelerPluginVersion : %1 Version: %1PgModelerPluginbSouhaitez-vous appliquer <strong>statut SQL %1 </strong> aux rfrences de l'objet galement ? Cela permet d'viter des problmes lors de l'export ou de la validation du modle.Do you want to apply the SQL %1 status to the object's references too? This will avoid problems when exporting or validating the model. PgModelerUiNSdsactivation disabling PgModelerUiNSactivationenabling PgModelerUiNSType de donne Data TypePgSQLTypeWidgetDimension DimensionPgSQLTypeWidgetFormulaireFormPgSQLTypeWidgetFormat :Format:PgSQLTypeWidgetIntervalle : Interval:PgSQLTypeWidgetL :L:PgSQLTypeWidgetLongueurLengthPgSQLTypeWidgetMMPgSQLTypeWidget AUCUNNONEPgSQLTypeWidgetP :P:PgSQLTypeWidgetPrcision PrecisionPgSQLTypeWidget SRID :SRID:PgSQLTypeWidgetSpatial :Spatial:PgSQLTypeWidget Fuseau horaire : Timezone:PgSQLTypeWidget Type :Type:PgSQLTypeWidgetVariation : Variation:PgSQLTypeWidgetZZPgSQLTypeWidget [ ] :[ ]:PgSQLTypeWidgetFormulaireFormPluginsConfigWidgetBibliothqueLibraryPluginsConfigWidget&Extensions chargesLoaded plug-insPluginsConfigWidgetLOuvrir dans le gestionnaire de fichierOpen in file managerPluginsConfigWidgetDRpertoire racine des extensions :Plug-ins root directory:PluginsConfigWidgetExtensionPluginPluginsConfigWidgetVersionPluginsConfigWidgetNotions de baseBasics PolicyWidgetVRIFIER :CHECK: PolicyWidgetCommande :Command: PolicyWidget Expressions PolicyWidgetLaissez la grille <em><strong>Rles</strong></em> vide afin de crer un %1 applicable <strong><em>PUBLIC</em></strong>.|Leave the Roles grid empty in order to create a %1 applicable to PUBLIC. PolicyWidgetNomName PolicyWidgetPermissif Permissive PolicyWidget RlesRoles PolicyWidgetUTILISANT :USING: PolicyWidget%1 (ligne : %2) %1 (line: %2)QObject0nouvelle_base_de_donnes new_databaseQObject$Colonne (Source) :Column (Source):RelationshipConfigWidget"Colonne (Cible) :Column (Target):RelationshipConfigWidgetxRelier les colonnes associant cls trangres/cls primairesConnect FK to PK columnsRelationshipConfigWidgetlRelier les associations aux tables en un point centralConnect tables' center pointsRelationshipConfigWidget<Connecter les bords des tablesConnect tables' edgesRelationshipConfigWidgetAffichageConnection ModeRelationshipConfigWidget CopieCopyRelationshipConfigWidget4Affichage en pied d'oiseauCrow's foot notationRelationshipConfigWidget DfautDefaultRelationshipConfigWidgetReportable : Deferrable:RelationshipConfigWidgetReport : Deferral:RelationshipConfigWidget4Cls trangres && nommageFK Settings && PatternsRelationshipConfigWidget0Cl trangre (Source) :Foreign Key (Source):RelationshipConfigWidget.Cl trangre (Cible) :Foreign Key (Target):RelationshipConfigWidgetCls trangresForeign key settingsRelationshipConfigWidgetFormulaireFormRelationshipConfigWidgetGnralisationGeneralizationRelationshipConfigWidget8Plusieurs plusieurs (n :n)Many to many (n:n)RelationshipConfigWidget"Rgles de nommage Name patternsRelationshipConfigWidgetON DELETE : ON DELETE:RelationshipConfigWidgetON UPDATE : ON UPDATE:RelationshipConfigWidget*Un plusieurs (1 :n)One to many (1:n)RelationshipConfigWidgetUn un (1 :1)One to one (1:1)RelationshipConfigWidgetHMotif pour les noms de colonnes gnres qui sont bases sur la cl primaire d'une table rfrence (1 :1 et 1 :n) ou sur la cl primaire de la table source (n :n).rPattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipConfigWidgetMotif pour les noms de colonnes gnres qui sont bases sur la cl primaire de la table cible (n :n).APattern for columns generated based upon target table's pk (n-n).RelationshipConfigWidgetVMotif pour les noms de cls trangres gnres qui sont bases sur la cl primaire d'une table rfrence (1 :1 et 1 :n) ou sur la cl primaire de la table source (n :n).vPattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipConfigWidgetMotif pour les noms de cls trangres gnres qui sont bases sur une cl primaire de la table cible (n :n).EPattern for foreign key generated based upon target table's pk (n-n).RelationshipConfigWidgetMotif pour les noms de cls primaires qui sont gnres par une association.=Pattern for primary key generated by identifier relationship.RelationshipConfigWidgetMotif pour les noms de cls uniques qui sont gnres par une association.5Pattern for unique key generated by the relationship.RelationshipConfigWidget4Nom colonne cl primaire :Primary Key Column:RelationshipConfigWidget:Nom contrainte cl primaire :Primary Key Name:RelationshipConfigWidget(Type d'association :Relationship type:RelationshipConfigWidgethCe mode dtermine le point optimal o la relation est connecte sur les bords des tables en tenant compte de leur position. Cela implique l'utilisation de la notation ER classique.This mode determines the optimal point where the relationship is connected on the tables' edges taking their position into account. It implies the usage of the classical ER notation.RelationshipConfigWidgetCe mode d'affichage est disponible uniquement pour les associations de type <strong>un--un</strong>, <strong>un--plusieurs</strong> et <strong>les associations aux cls trangres</strong> mais fournit une meilleure smantique lors de l'association de tables en plaant les lignes sur le point exact o l'association se produit. Cela implique l'utilisation de la notation ER classique.-This mode is available only for one-to-one, one-to-many and fk relationships but provides a better semantics when linking tables by placing the lines on the exact point where the relationship occurs. It implies the usage of the classical ER notation.RelationshipConfigWidget(Ce mode est le classique. Il relie les associations de tables depuis leurs points centraux. Cela implique l'utilisation de la notation ER classique.This mode is the classical one. It connects the relationship to tables through their central points. It implies the usage of the classical ER notation.RelationshipConfigWidgetCe mode affiche les associations en pied d'oiseau ce qui amliore le smantique et la lisibilit. Il dtermine galement le point optimal o la relation est connecte sur les bords des tables en tenant compte de leur position.This mode renders the relationships in crow's foot notation which has a better semantics and readability. It also determines the optimal point where the relationship is connected on the tables' edges taking their position into account.RelationshipConfigWidget.Nom contrainte unique :Unique Key Name:RelationshipConfigWidget est requis is requiredRelationshipWidget&1-1RelationshipWidget&genRelationshipWidget1-n1-nRelationshipWidgetTOUTALLRelationshipWidget AvancAdvancedRelationshipWidgetAttribut AttributeRelationshipWidgetAttributs AttributesRelationshipWidgettFormes disponibles pour dfinir les modles de noms : <br/> <strong>%1</strong> = Nom de la colonne de cl primaire de rfrence (source). <em>(Ignor sur les modles de contrainte)</em><br/> <strong>%2</strong> = Nom de la table de rfrence (source).<br/> <strong>%3</strong> = Nom de la table rfrence (ou de dstination). <br/> <strong>%4</strong> = Nom de la table gnre. <em>(Seulement pour les relations n:n)</em>|Available tokens to define name patterns:
%1 = Reference (source) primary key column name. (Ignored on constraint patterns)
%2 = Reference (source) table name.
%3 = Receiver (destination) table name.
%4 = Generated table name. (Only for n:n relationships)RelationshipWidgetCOMMENTAIRESCOMMENTSRelationshipWidgetCONTRAINTES CONSTRAINTSRelationshipWidgetCardinalit : Cardinality:RelationshipWidget$Colonne (Source) :Column (Source):RelationshipWidget"Colonne (Cible) :Column (Target):RelationshipWidgetContrainte ConstraintRelationshipWidgetContraintes ConstraintsRelationshipWidget Options de copie Copy OptionsRelationshipWidget.Couleur personnalise : Custom Color:RelationshipWidgetDEFAUTSDEFAULTSRelationshipWidget DfautDefaultRelationshipWidgetReportable : Deferrable:RelationshipWidgetReport : Deferral:RelationshipWidget<Relation de dpendance / copieDependency / Copy relationshipRelationshipWidgetE&XCLUSION E&XCLUDINGRelationshipWidget0Cl trangre (Source) :Foreign Key (Source):RelationshipWidget.Cl trangre (Cible) :Foreign Key (Target):RelationshipWidgetRProprits par dfaut des cls trangresForeign key SettingsRelationshipWidget(Nom nouvelle table :Gen. Table Name:RelationshipWidgetGnralGeneralRelationshipWidgetPAssociation de gnralisation (hritage))Generalization relationship (inheritance)RelationshipWidgetINCLURE INCLUDINGRelationshipWidget INDEXINDEXESRelationshipWidgetIdentifiant IdentifierRelationshipWidgetPDans les relations plusieurs--plusieurs, les deux tables sont utilises comme rfrence pour gnrer la table qui reprsente la liaison. Les colonnes des deux tables sont copies dans la table rsultante et deux cls trangres sont galement cres afin de rfrencer chaque table participante.In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table.RelationshipWidget@Au lieu de crer une cl primaire valeurs multiples avec les colonnes de cls trangres gnres, une seule colonne est cre et utilise comme cl primaire.Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key.RelationshipWidgetBAssociation plusieurs plusieursMany to many relationshipRelationshipWidgetNomNameRelationshipWidget"Rgles de nommage Name PatternsRelationshipWidget|Nom de la table gnre par une relation plusieurs plusieurs:Name of the table generated from many to many relationshipRelationshipWidgetON DELETE : ON DELETE:RelationshipWidgetON UPDATE : ON UPDATE:RelationshipWidget4Association un plusieursOne to many relationshipRelationshipWidget&Association un unOne to one relationshipRelationshipWidgetHMotif pour les noms de colonnes gnres qui sont bases sur la cl primaire d'une table rfrence (1 :1 et 1 :n) ou sur la cl primaire de la table source (n :n).rPattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipWidgetMotif pour les noms de colonnes gnres qui sont bases sur la cl primaire de la table cible (n :n).APattern for columns generated based upon target table's pk (n-n).RelationshipWidgetVMotif pour les noms de cls trangres gnres qui sont bases sur la cl primaire d'une table rfrence (1 :1 et 1 :n) ou sur la cl primaire de la table source (n :n).vPattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipWidgetMotif pour les noms de cls trangres gnres qui sont bases sur une cl primaire de la table cible (n :n).EPattern for foreign key generated based upon target table's pk (n-n).RelationshipWidgetMotif pour les noms de cls primaires qui sont gnres par une association.=Pattern for primary key generated by identifier relationship.RelationshipWidgetMotif pour les noms de cls uniques qui sont gnres par une association.5Pattern for unique key generated by the relationship.RelationshipWidget*Nom de cl primaire :Primary Key Name:RelationshipWidgetCl primaire Primary keyRelationshipWidget2Colonne de cl primaire :Primay Key Column:RelationshipWidget$La table rfrente recevra les colonnes gnres et la cl trangre afin de reprsenter la liaison entre elles. C'est le ct (n) de la relation.Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship.RelationshipWidget,Table de destination :Receiver Table:RelationshipWidget"Table rfrente :Reference Table:RelationshipWidgetPLa table de rfrence a les colonnes de sa cl primaire copies dans la table de rception afin de reprsenter la liaison entre elles. C'est le ct (1) de la relation.Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship.RelationshipWidget$Table rfrence :Referenced Table:RelationshipWidgetLa table rfrence a ses colonnes rfrences par la cl trangre d'une table. C'est le ct (1) de la relation.kReferenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship.RelationshipWidgetLa table rfrence a ses colonnes rfrences par une vue afin de construire les colonnes de cette dernire.gReferenced table has its columns referenced by a view in order to construct the columns of this latter.RelationshipWidget"Table rfrente :Referer Table:RelationshipWidgetVue rfrente : Referer View:RelationshipWidgetLa table rfrente rfrence une ou plusieurs colonnes d'une table via des cls trangres. C'est le ct (n) de la relation.sReferer table references one or more columns of a table through foreign keys. This is the (n) side of relationship.RelationshipWidgetLa vue rfrente rfrence une ou plusieurs colonnes d'une table pour construire ses propres colonnes.UReferer view references one or more columns of a table to construct it's own columns.RelationshipWidget$Type de relation : Rel. Type:RelationshipWidgetLRelation gnre par une cl trangre&Relationship generated via foreign keyRelationshipWidgetSTOCKAGESTORAGERelationshipWidget6Colonne cl primaire simpleSingle PK columnRelationshipWidgetTable n1 :Table 1:RelationshipWidgetTable n2 :Table 2:RelationshipWidgetLa cl primaire du destinataire sera compose des colonnes de cl trangre gnres.QThe receiver's primary key will be composed by the generated foreign key columns.RelationshipWidgetTCet onglet avanc montre les objets (colonnes ou tables) gnrs automatiquement par la relation ainsi que les cls trangres qui forment le(s) lien(s) entre les tables.This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables.RelationshipWidgetTypeRelationshipWidget Nom cl unique :Unique Key Name:RelationshipWidget@Utiliser les valeurs par dfauts Use defaultsRelationshipWidgetXUtiliser les paramtres globaux de pgModeler$Use global settings for these fieldsRelationshipWidgetUtilisez la cl primaire spciale si vous souhaitez inclure une cl primaire contenant des colonnes gnres dans la table de destination. <strong>Important :</strong> s'il s'agit d'une nouvelle relation, il est ncessaire de terminer sa cration et de rouvrir cette bote de dialogue pour crer la cl primaire spciale.Use the special primary key if you want to include a primary key containing generated columns to the receiver table. Important: if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key.RelationshipWidget~Utiliser les paramtres de pgModeler pour les champs ci-dessous?Use the values defined on settings dialogs for the fields belowRelationshipWidget [DST] est requis[DST] is requiredRelationshipWidget [SRC] est requis[SRC] is requiredRelationshipWidgetdepdepRelationshipWidgetfkfkRelationshipWidgetn-nn-nRelationshipWidget$[donnes binaires] [binary data]ResultSetModelL'affectation de <strong><em>-1</em></strong> <strong><em>Connexions</em></strong> cre un rle sans limite de connexion.<br/> Dcocher <strong><em>Validit</em></strong> cre un rle qui n'expire jamais.Assigning -1 to Connections creates a role without connection limit.
Unchecking Validity creates an role that never expires. RoleWidgetAttributs Attributes RoleWidget"Contournement RLS Bypass RLS RoleWidget>Peut crer des bases de donnesCan create database RoleWidget(Peut crer des rlesCan create role RoleWidgetPeut se loguer Can login RoleWidget8Peut utiliser la rplicationCan use replication RoleWidgetConnexions : Connections: RoleWidgetEncrypt Encrypted RoleWidget.Hriter des permissionsInherit permissions RoleWidgetMembre de Member of RoleWidgetMembresMembers RoleWidget Membres (Admin.)Members (Admin.) RoleWidgetMot de passe : Password: RoleWidgetRleRole RoleWidget"Super utilisateur Superuser RoleWidgetValiditValidity RoleWidget,aaaa-MMM-jj hh :mm :ssyyyy-MMM-dd hh:mm:ss RoleWidgetCommandesCommands RuleWidget,Expr. conditionnelle :Conditional Expr.: RuleWidgetvnement :Event: RuleWidget$Type d'excution :Execution Type: RuleWidgetCommandes SQL : SQL Command: RuleWidgetCommande SQL SQL command RuleWidgetPour crer une rgle qui n'xcute aucune action (<strong>DO NOTHING</strong>), ne spcifiez aucune commandes dans le champs des commandes SQL.To create a rule that does not perform any action (DO NOTHING) simply do not specify commands in the SQL commands table. RuleWidgetS&ortie&OutputSQLExecutionWidget&ScriptSQLExecutionWidget (non enregistr) (not saved)SQLExecutionWidget......SQLExecutionWidget Alt+FAlt+FSQLExecutionWidget Alt+OAlt+OSQLExecutionWidgetAlt+TSQLExecutionWidgetAlt+XSQLExecutionWidgetFormat CVS CVS formatSQLExecutionWidgetEffacer Clear AllSQLExecutionWidget*Nettoyer l'historique Clear historySQLExecutionWidgetXEffacer le code SQL et la grille de rsultat!Clear sql input field and resultsSQLExecutionWidget6Fermer le script SQL actuelClose the current SQL scriptSQLExecutionWidgetFichiers CSV avec champs spars par des virgules (*.csv);;Tous les fichiers (*.*)4Comma-separated values file (*.csv);;All files (*.*)SQLExecutionWidget&Copier la slectionCopy selectionSQLExecutionWidgetFBase de donnes de travail actuelleCurrent working databaseSQLExecutionWidgetE&xporterE&xportSQLExecutionWidgetTExporter les rsultats dans un fichier CSVExport results to a CSV fileSQLExecutionWidgetF6F6SQLExecutionWidget&RechercherFi&ndSQLExecutionWidget8Rechercher dans l'historiqueFind in historySQLExecutionWidgetFormulaireFormSQLExecutionWidget6Grer le script SQL externeHandle external SQL scriptSQLExecutionWidget8Masquer l'outil de rechercheHide find toolSQLExecutionWidgetHistoriqueHistorySQLExecutionWidgetChargerLoadSQLExecutionWidget*Charger commandes SQLLoad SQL commandsSQLExecutionWidgetMessagesSQLExecutionWidget Messages (%1)SQLExecutionWidgetAucun rsultat n'a t rcupr ou des modifications ont t effectues en raison de l'erreur ci-dessus.Excuter la commande SQL entreRun the specified SQL commandSQLExecutionWidgetXFichier SQL (*.sql);;Tous les fichiers (*.*)!SQL file (*.sql);;All files (*.*)SQLExecutionWidget8Script SQL actuellement grSQL script currently handledSQLExecutionWidgetEnregistrerSaveSQLExecutionWidget.Sauvegarder fichier CSV Save CSV fileSQLExecutionWidget2Sauvegarder commandes SQLSave SQL commandsSQLExecutionWidget Enregistrer sousSave asSQLExecutionWidget0Enregistrer l'historique Save historySQLExecutionWidget6Rechercher dans le code SQLSearch in SQL codeSQLExecutionWidgetExtrai&ts Snippe&tsSQLExecutionWidgetLe champ d'entre SQL ainsi que la grille des rsultats vont tre purgs ! Voulez-vous poursuivre ?JThe SQL input field and the results grid will be cleared! Want to proceed?SQLExecutionWidgetCette action effacera tout l'historique des commandes SQL pour toutes les connexions ! Voulez-vous vraiment poursuivre ?jThis action will wipe out all the SQL commands history for all connections! Do you really want to proceed?SQLExecutionWidgetCette action effacera tout l'historique des commandes SQL pour la connexion en cours ! Voulez-vous vraiment poursuivre ?qThis action will wipe out all the SQL commands history for the current connection! Do you really want to proceed?SQLExecutionWidget<(Ds)active le volet de sortieToggles the output paneSQLExecutionWidget$[donnes binaires] [binary data]SQLExecutionWidget...... SQLToolWidget0<strong>ATTENTION :</strong> Se dconnecter de toutes les bases de donnes fermera tout onglet ouvert dans cette vue ! Voulez-vous vraiment poursuivre ?ATTENTION: Disconnect from all databases will close any opened tab in this view! Do you really want to proceed? SQLToolWidget Alt+RAlt+R SQLToolWidgetAttributs Attributes SQLToolWidget>Explorateur de bases de donnesDatabase explorer SQLToolWidgetZSe dconnecter de toutes les bases de donnesDisconnect from all databases SQLToolWidgetFormulaireForm SQLToolWidget*Excuteur de code SQL SQL execution SQLToolWidgetCode source Source code SQLToolWidget^(Ds)active l'affichage du volet du code source&Toggle the display of source code pane SQLToolWidget\(Ds)active la grille des attributs de l'objet#Toggle the object's attributes grid SQLToolWidgetVMettre jour la liste des bases de donnesUpdate the database list SQLToolWidgetAvertissementWarning SQLToolWidget-SceneInfoWidget\Position actuelle de la souris dans le canevas+Current position of the mouse in the canvasSceneInfoWidget,Facteur de zoom actuelCurrent zoom factorSceneInfoWidgetHObjet(s) actuellement slectionn(s)Currently selected object(s)SceneInfoWidgetTDimensions de(s) l'objet(s) slectionn(s)$Dimensions of the selected object(s)SceneInfoWidgetFormulaireFormSceneInfoWidgetInconnuN/ASceneInfoWidget Aucune slction No selectionSceneInfoWidget&Objets select. : %1Sel. objects: %1SceneInfoWidget0Couleur de remplissage : Fill color: SchemaWidget*Afficher le rectangleShow rectangle SchemaWidgetCache :Cache:SequenceWidgetCyclique :Cyclic:SequenceWidgetIncrment : Increment:SequenceWidgetMaximum :Maximum:SequenceWidgetMinimum :Minimum:SequenceWidgetProprio. Col. : Owner Col.:SequenceWidgetDbut :Start:SequenceWidgetl/* Erreur lors de l'analyse de l'extrait '%1': %2 */*/* Error parsing the snippet '%1': %2 */SnippetsConfigWidgetAjouterAddSnippetsConfigWidget"Tous les extraits All snippetsSnippetsConfigWidgetS'applique : Applies to:SnippetsConfigWidget"Annuler l'ditionCancel editionSnippetsConfigWidget8Crer une nouvelle connexionCreate new connectionSnippetsConfigWidgetFSupprimer la connexion slectionneDelete selected connectionSnippetsConfigWidgetdVoulez-vous vraiment supprimer tous les extraits ?*Do you really want to remove all snippets?SnippetsConfigWidgetIdentifiant <strong>%1</strong> d'extrait dupliqu dtct. Merci d'en choisir un autre !TDuplicated snippet id %1 detected. Please, specify a different one!SnippetsConfigWidgetDModifier la connexion slectionneEdit selected connectionSnippetsConfigWidgetCode vide pour l'extrait <strong>%1</strong>. Merci de lui spcifier une valeur !KEmpty code for snippet %1. Please, specify a value for it!SnippetsConfigWidgetLabel vide pour l'extrait <strong>%1</strong>. Merci de lui spcifier une valeur !LEmpty label for snippet %1. Please, specify a value for it!SnippetsConfigWidgetFiltrer :Filter:SnippetsConfigWidgetFormulaireFormSnippetsConfigWidgetGnralGeneralSnippetsConfigWidgetUsage gnralGeneral purposeSnippetsConfigWidgetIdentifiant :ID:SnippetsConfigWidgetZMotif d'identification <strong>%1</strong> incorrect dtect. Celui-ci doit commencer par au moins une lettre et tre compos de lettres, de chiffres et/ou de tirets bas _ !Invalid ID pattern detected %1. This one must start with at leat one letter and be composed by letters, numbers and/or underscore!SnippetsConfigWidgettiquette :Label:SnippetsConfigWidgetbAucune erreur de syntax retrouve dans l'extrait.&No syntax errors found in the snippet.SnippetsConfigWidgetAnalysableParsableSnippetsConfigWidgetBLes extraits de code analysables ou dynamiques sont crits dans la syntaxe <strong>schema micro language</strong>. Lorsque vous utilisez un extrait de code analys, les attributs entours par des <strong>{}</strong> seront remplacs par les attributs correspondants de l'objet slectionn.Parsable or dynamic snippets are written in the schema micro language syntax. When using a parsable snippet the attributes surrounded in {} will be replaced by the selected object's matching attributes.SnippetsConfigWidgetAnalyserParseSnippetsConfigWidgetAnalyser l'extrait de code afin de vrifier s'il existe des erreurs de syntaxe.?Parse the snippet in order to check if there are syntax errors.SnippetsConfigWidget.lment de substitution PlaceholdersSnippetsConfigWidgetTout supprimer Remove AllSnippetsConfigWidgetMaj+Suppr Shift+DelSnippetsConfigWidgetExtraits : Snippets:SnippetsConfigWidgetL'extrait dynamique contient des erreurs de syntax. Plus d'informations : <br/><em>%1</em>OThe dynamic snippet contains syntax error(s). Additional info:
%1SnippetsConfigWidgetMettre jourUpdateSnippetsConfigWidgetLors de la manipulation d'extraits de code analysables, les attributs vides seront remplacs par une valeur au format <strong>{attribut}</strong>. Noter que cette option peut affecter la smantique de l'extrait rsultant.When handling parsable snippets empty attributes will be replaced by a value in the format {attribute}. Note that this option can affect the semantics of the resulting snippet.SnippetsConfigWidget -- Le code SQL est volontairement tronqu ce stade dans la version dmo !@ -- SQL code purposely truncated at this point in demo version!SourceCodeWidget<-- NOTE: le code ci-dessous contient le code SQL de l'objet slectionn -- ainsi que de ses dpendances et enfants (le cas chant). -- -- Cette fonctionnalit n'est qu'une commodit vous permettant de tester -- la dfinition SQL de l'objet entier. -- -- Lors de l'export ou de la gnration du code SQL pour l'ensemble du modle de base de donnes, -- tous les objets seront placs leurs positions d'origine. |-- NOTE: the code below contains the SQL for the selected object -- as well for its dependencies and children (if applicable). -- -- This feature is only a convinience in order to permit you to test -- the whole object's SQL definition at once. -- -- When exporting or generating the SQL for the whole database model -- all objects will be placed at their original positions. SourceCodeWidgetf-- Code SQL non disponible pour ce type d'objet. --2-- SQL code unavailable for this type of object --SourceCodeWidget< !-- Aperu du code XML dsactiv dans la version de dmonstration -->;SourceCodeWidgeth<strong>Original :</strong> affiche uniquement le code SQL de l'objet d'origine.<br/><br/> <strong>Dpendances :</strong> affiche le code d'origine ainsi que toutes les dpendances ncessaires pour crer correctement l'objet slectionn.<br/><br/> <strong>Enfants :</strong> affiche le code original ainsi que le code SQL de tous les enfants. Cette option est utilise uniquement par les schmas, les tables et les vues.Original: displays only the original object's SQL code.

Dependencies: displays the original code including all dependencies needed to properly create the selected object.

Children: displays the original code including all object's children SQL code. This option is used only by schemas, tables and views.SourceCodeWidget&Affichage du code : Code display:SourceCodeWidget8Gnration du code source...Generating source code...SourceCodeWidgetOriginalSourceCodeWidget2Original + enfants de SQLOriginal + children's SQLSourceCodeWidget:Original + dpendances de SQLOriginal + depedencies' SQLSourceCodeWidgetPostgreSQL PostgreSQLSourceCodeWidgetSQLSQLSourceCodeWidgetRCode SQL (*.sql);;Tous les fichiers (*.*)!SQL code (*.sql);;All files (*.*)SourceCodeWidget.Enregistrer le code SQLSave SQLSourceCodeWidget>Enregistrer le code SQL sous...Save SQL code as...SourceCodeWidgetPEnregistrer le code SQL dans un fichier.Save the SQL code to a file.SourceCodeWidget8Visualisation du code sourceSource code visualizationSourceCodeWidgetVersion :Version:SourceCodeWidgetXMLXMLSourceCodeWidget icne iconecodigoSourceCodeWidgetAvant :Before:SwapObjectsIdsWidgetLChanger l'ordre de cration des objetsChange objects creation orderSwapObjectsIdsWidgetModifier l'ordre de cration des objets est une opration irrversible qui entrane l'effacement automatique de l'historique des oprations. Noter que l'ordre de cration configur dans ce formulaire n'est pas dfinitif et peut changer aprs la validation d'un modle.Change the objects creation order is an irreversible operation and cause the operations history to be automatically erased. Note that the creation order configured in this form is not definitive and may change after a model validation.SwapObjectsIdsWidgetCrer :Create:SwapObjectsIdsWidgetFiltrer :Filter:SwapObjectsIdsWidgetIdentifiantIDSwapObjectsIdsWidgetIdentifiant :ID:SwapObjectsIdsWidget ObjetObjectSwapObjectsIdsWidgetObjet parent Parent ObjectSwapObjectsIdsWidgetType parent Parent TypeSwapObjectsIdsWidget*changer identifiantsSwap idsSwapObjectsIdsWidgetModifie l'ordre de cration de deux objets en changeant leurs numros d'identification1Swap the object ids changing their creation orderSwapObjectsIdsWidget&Procde l'changeSwap the values of the fieldsSwapObjectsIdsWidgetchanger Swap valuesSwapObjectsIdsWidgetTypeSwapObjectsIdsWidgetrDans la version de dmonstration, les tables ne peuvent contenir que `%1' instance(s) de chaque type d'objet enfant ou table anctre ! Vous avez atteint cette limite pour le type : `%2'In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2'Tablenouvelle_table new_tableTable<html><head/><body><p>Les valeurs vides sont supposes tre <span style="font-weight :600;">DEFAULT</span>. Pour utiliser des valeurs spciales comme <span style="font-weight :600;">NULL</span>, un appel de fonction comme <span style="font-weight :600;">now()</span> ou un chappement des donnes spcifiques, entourer les valeurs de deux barres obliques, par exemple <span style="font-weight :600;">/valeur/</span>. Pour utiliser une barre oblique dans le cadre de la valeur, ajouter le caractre barre oblique inverse, par exemple <span style="font-weight :600;">/</span>.</p></body></html>

Empty values are assumed as DEFAULT. To use special values like NULL, a function call like now() or a specific data escaping, enclose values in two slashes, e.g., /value/. To use a slash as part of the value prepend the backslash character, e.g., \/.

TableDataWidget0Ajouter une colonne videAdd an empty columnTableDataWidget0Ajouter des lignes videsAdd empty rowsTableDataWidget@Modification de donnes en masseBulk data editTableDataWidgetModifier d'un coup les valeurs de toutes les cellules slectionnes/Change the values of all selected cells at onceTableDataWidgetBCopier les lments sur la grilleCopy items on the gridTableDataWidgetCtrl+DTableDataWidget Ctrl+ECtrl+ETableDataWidgetCtrl+Maj+SupprCtrl+Shift+DelTableDataWidget SupprDelTableDataWidgetEffacer des colonnes est une action irrversible ! Voulez-vous vraiment poursuivre ?HDelete columns is an irreversible action! Do you really want to proceed?TableDataWidgetHSupprimer les colonnes slectionnesDelete the selected columnsTableDataWidgetDSupprimer les lignes slectionnesDelete the selected rowsTableDataWidgetDDupliquer les lignes slectionnesDuplicate the selected rowsTableDataWidget"Colonne dupliqueDuplicated columnTableDataWidget@Modifier les donnes de la tableEdit table dataTableDataWidgetZRemplit la grille en utilisant un fichier CSVFills the grid using a CSV fileTableDataWidgetInsrerInsTableDataWidget CollerPasteTableDataWidgetBCopier les lments sur la grillePaste items on the gridTableDataWidgetlSupprimer toutes les colonnes (et lignes) de la grille+Remove all columns (and rows) from the gridTableDataWidgetSupprimer toutes les colonnes est une action irrversible ! Voulez-vous vraiment poursuivre ?LRemove all columns is an irreversible action! Do you really want to proceed?TableDataWidgetSupprimer toutes les lignes des colonnes de prservation de la grille0Remove all rows from the grid preserving columnsTableDataWidgetSupprimer toutes les lignes est une action irrversible ! Voulez-vous vraiment poursuivre ?IRemove all rows is an irreversible action! Do you really want to proceed?TableDataWidgetMaj+Suppr Shift+DelTableDataWidget Colonne inconnueUnknown columnTableDataWidget Relations : %1 Relationship: %1TableObjectView&Colonnes&Columns TableWidget &Index&Indexes TableWidget&Politiques &Policies TableWidget&Rgles&Rules TableWidget&Tables&Tables TableWidgetAttribut(s) Attribute(s) TableWidgetCo&ntraintes Co&nstraints TableWidgetCommandeCommand TableWidget CopieCopy TableWidget"Valeur par dfaut Default Value TableWidgetRDfinir les donnes initiales de la table!Define initial data for the table TableWidget Modifier donnes Edit data TableWidgetRActiver la scurit au niveau de la ligneEnable row level security TableWidgetEvnementEvent TableWidgetEvnementsEvents TableWidgetExcution Execution TableWidgetDclencheurFiring TableWidget>Forcer RLS pour le propritaireForce RLS for owner TableWidgetXUtiliser ALTER pour les colonnes/contraintes&Generate ALTER for columns/constraints TableWidgetIndexationIndexing TableWidgetIl n'est pas possible de marquer une colonne comme cl primaire quand la table a dj une cl primaire qui a t cre par une relation ! Cette action doit tre effectue dans la section <strong>Cl primaire</strong> du formulaire d'dition de la relation.It is not possible to mark a column as primary key when the table already has a primary key which was created by a relationship! This action should be done in the section Primary key of the relationship's editing form. TableWidgetIl n'est pas possible de marquer une colonne cre par une relation comme cl primaire ! Cette action doit tre effectue dans la section <strong>Cl primaire</strong> du formulaire d'dition de la relation.It is not possible to mark a column created by a relationship as primary key! This action should be done in the section Primary key of the relationship's editing form. TableWidgetNomName TableWidgetNonNo TableWidget la suppression ON DELETE TableWidget la mise jour ON UPDATE TableWidgetOptionsOptions TableWidgetCPPK TableWidgetParent TableWidgetPermissif Permissive TableWidgetTable de rfr. Refer. Table TableWidget RlesRoles TableWidget SchmaSchema TableWidgetBalise :Tag: TableWidgetDcl&encheurs Tri&ggers TableWidgetType TableWidgetUnloggedUnlogged TableWidgetAvec OIDWith OID TableWidgetOuiYes TableWidgetDossier : Directory:TablespaceWidgetFormulaireFormTablespaceWidgetCorps :Body: TagWidgetCouleursColors TagWidgetCorps tendu :Extended body: TagWidgetNom du schma : Schema name: TagWidget"Nom de la table : Table name: TagWidgetTitre :Title: TagWidget(Excution des tchesExecuting tasksTaskProgressWidgetNEn attente du dmarrage de la tche ...Waiting task to start...TaskProgressWidgetGrasBold TextboxWidgetCouleur :Color: TextboxWidgetPolice :Font: TextboxWidgetItaliqueItalic TextboxWidget@Slection de la couleur du texteSelect text color TextboxWidget TexteText TextboxWidgetSoulign Underline TextboxWidgetptpt TextboxWidgetArgument : Argument: TriggerWidgetArguments Arguments TriggerWidgetColonneColumn TriggerWidgetColonne :Column: TriggerWidgetColonnesColumns TriggerWidgetCondition : Condition: TriggerWidgetContrainte Constraint TriggerWidget DELETEDELETE TriggerWidgetReportable : Deferrable: TriggerWidgetvnement :Event: TriggerWidgetExcution : Excution: TriggerWidget"Pour chaque ligne FOR EACH ROW TriggerWidgetFonction : Function: TriggerWidget INSERTINSERT TriggerWidgetOptions :Options: TriggerWidgetTable rfr. : Refer. Table: TriggerWidgetTRUNCATETRUNCATE TriggerWidgetType TriggerWidget UPDATEUPDATE TriggerWidgetANALYZE :ANALYZE: TypeWidgetAlignement : Alignment: TypeWidgetAttributs Attributes TypeWidgetType de base Base Type TypeWidgetPar valeurBy value TypeWidget(Fonction canonique :Canonical Func.: TypeWidgetCatgorie : Category: TypeWidgetCo&mposite Co&mposite TypeWidgetAssemblable Collatable TypeWidget Collation TypeWidgetCollation : Collation: TypeWidgetConfiguration :Configuration: TypeWidget&Valeur par dfaut :Default Value: TypeWidgetDlimiteur : Delimiter: TypeWidgetType d'lement Element Type TypeWidgetnumration Enumeration TypeWidgetnumration : Enumeration: TypeWidgetnumrations Enumerations TypeWidgetFonctions Functions TypeWidgetINPUT :INPUT: TypeWidgetLong. interne :Internal Length: TypeWidgetType de Like Like Type TypeWidgetNomName TypeWidget Nom :Name: TypeWidgetOUTPUT :OUTPUT: TypeWidget*Classe d'oprateurs :Operator Class: TypeWidgetOptions :Options: TypeWidgetPrfr Preferred TypeWidget RECV :RECV: TypeWidgetIntervalleRange TypeWidget SEND :SEND: TypeWidgetStockage :Storage: TypeWidgetSous-typeSubtype TypeWidgetJFonction de diffrence du sous-type :Subtype Diff Func.: TypeWidgetTPMOD_IN : TPMOD_IN: TypeWidgetTPMOD_OUT : TPMOD_OUT: TypeWidgetLes fonction assignables au type plage (RANGE) doivent avoir la signature suivante :<br/><br/><strong>Canonical:</strong> <em>any function(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision function(subtype, subtype)</em>The functions to be assigned to a range type should have the following signatures:

Canonical: any function(any)
Subtype Diff: double precision function(subtype, subtype) TypeWidgetLes fonctions assignes un type devraient tre crites en langage C et possder, les signatures suivantes :<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table>The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:
INPUT: any function(cstring, oid, integer) OUTPUT: cstring function(any)
SEND: byta function(any) RECV: any function(internal, oid, integer)
TPMOD_IN: integer function(cstring[]) TPMOD_OUT: cstring function(integer)
ANALYZE: boolean function(internal)
 TypeWidgetType TypeWidgetcharchar TypeWidget double prcisiondouble precision TypeWidgetintegerinteger TypeWidgetsmallintsmallint TypeWidget......UpdateNotifierWidget 0.0.00.0.0UpdateNotifierWidget2Journal des modifications ChangelogUpdateNotifierWidgetbImpossible de vrifier la prsence de mise jourFailed to check updatesUpdateNotifierWidgetDTlcharger l'application compileGet binary packageUpdateNotifierWidget4Tlcharger le code sourceGet source codeUpdateNotifierWidget Cacher ce widgetHide this widgetUpdateNotifierWidget$Nouvelle version : New version:UpdateNotifierWidget4Aucune mise jour trouveNo updates foundUpdateNotifierWidgetTRedirige vers la page web du dpt GitHub.&Redirects to GitHub source repository.UpdateNotifierWidgetNRedirige vers la page web pour acheter.Redirects to purchase page.UpdateNotifierWidget Date de sortie : Released in:UpdateNotifierWidgetLe vrificateur de mise jour n'a pas pu vrifier la prsence de nouvelles versions ! Code retour HTTP reu : <strong>%1</strong>jThe update notifier failed to check for new versions! A HTTP status code was returned: %1UpdateNotifierWidgetLe notificateur de mise jour n'a pas pu vrifier les nouvelles versions ! Merci de vrifier votre connexion internet et de ressayer ! Erreur de connexion renvoye : <em>%1</em> - <strong>%2</strong>.The update notifier failed to check for new versions! Please, verify your internet connectivity and try again! Connection error returned: %1 - %2.UpdateNotifierWidget6Vrificateur de mise jourUpdate NotifierUpdateNotifierWidget*Mise jour trouve ! Update found!UpdateNotifierWidgetVous utilisez dj la version de pgModeler la plus rcente ! Aucune mise jour requise.DYou are running the most recent pgModeler version! No update needed.UpdateNotifierWidgetjj mmm aaaa mmm dd, yyyyUpdateNotifierWidget&Matrialiser &Materialized ViewWidget/* Le code SQL ne peut tre gnr. Vrifiez que les champs sont correctement remplis ! S/* Could not generate the SQL code. Make sure all attributes are correctly filled!  ViewWidgetAlias ViewWidgetAlias col. Alias Col. ViewWidget0Prvisualisation du code Code Preview ViewWidget Col./Expr. ViewWidgetColonneColumn ViewWidgetAlias colonne : Column Alias: ViewWidgetColonne :Column: ViewWidget"Expression finaleEnd expression ViewWidgetEvnementEvent ViewWidgetEvnementsEvents ViewWidgetExcution Execution ViewWidgetExpression Expression ViewWidget$Alias expression :Expression Alias: ViewWidgetExpression : Expression: ViewWidgetFROM ... ViewWidgetDclencheFiring ViewWidget0Marques : SF FW AW EX VDFlags: SF FW AW EX VD ViewWidgetIndexes ViewWidgetIndexationIndexing ViewWidget Mode :Mode: ViewWidgetNomName ViewWidgetOptionsOptions ViewWidgetOrdinaireOrdinary ViewWidgetRcursi&f Recursi&ve ViewWidgetTable de rfr. Refer. Table ViewWidget&Type de rfrence :Reference Type: ViewWidgetRfrences References ViewWidget RglesRules ViewWidget SELECT ... ViewWidgetAlias table : Table Alias: ViewWidgetCTETable Expression ViewWidgetTable :Table: ViewWidgetBalise :Tag: ViewWidgetL'lment est utilis dans la partie FROM de la commande afin de rfrencer des tables ou de construire des instructions JOIN.pThe element is used in the FROM portion of the command in order to reference tables or construct JOIN statements ViewWidgetL'lment sera ajout la fin de la dfinition de la vue. Ceci est utile lors de l'utilisation des instructions GROUP BY/HAVING.{The element will be appended to the very end of the view's definition. This is useful when using GROUP BY/HAVING statements ViewWidget$L'lment sera utilis dans le cadre de l'instruction SELECT pour extraire des colonnes ou des expressions qui composeront les colonnes de la vue.The element will be used as part of the SELECT statement to retrieve columns or expressions that will compose the view's columns ViewWidgetL'lment sera utilis dans le cadre de la clause WHERE sous forme d'expression conditionnelle.VThe element will be used as part of the WHERE clause in form of conditional expression ViewWidgetL'expression de l'lment est utilise exclusivement comme dfinition de la vue.EThe element's expression is used exclusively as the view's definition ViewWidgetFPour rfrencer toutes les colonnes d'une table (*), ne pas remplir le champ <strong>Colonne</strong> revient crire <em><strong>[schema].[table].*</Strong></em>To reference all columns in a table (*) just do not fill the field Column, this is the same as write [schema].[table].* ViewWidgetDclencheurTriggers ViewWidgetUtilis dans :Used in: ViewWidget(Dfinition de la vueView Definition ViewWidget WHERE ... ViewWidgetSans donnes With no data ViewWidgetFormulaireForm WelcomeWidget Dernire session Last session WelcomeWidgetNouveau modle New model WelcomeWidgetOuvrir modle Open model WelcomeWidgetModles rcents Recent models WelcomeWidgetModles de dmo Sample models WelcomeWidgetpgmodeler-0.9.2/lang/fr_FR.ts000066400000000000000000025746151360462764600160310ustar00rootroot00000000000000 AboutWidget About pgModeler À propos de pgModeler 0.0.0 0.0.0 build: PostgreSQL Database Modeler Modeleur de base de données PostgreSQL Open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand, let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards. Outil open source de modélisation de bases de données PostgreSQL. Plus aucun ordre LDD à saisir à la main, laissez pgModeler le faire pour vous ! Ce logiciel fusionne le concept de modélisation entité-association et toutes les fonctionnalités étendues que propose PostgreSQL en plus des standards SQL. <html><head/><body><p>Copyright 2006-2018 - Raphael Araújo e Silva &lt;<a href="mailto:raphael@pgmodeler.com.br"><span style=" text-decoration: underline; color:#0057ae;">raphael@pgmodeler.io</span></a>&gt;</p></body></html> pgModeler is proudly a brazilian software! pgModeler est un logiciel brésilien et fier de l'être ! <html><head/><body><p><a href="http://pgmodeler.com.br"><span style=" text-decoration: underline; color:#2980b9;">https://pgmodeler.io</span></a></p></body></html> ... ... (BUILD_NUM) License Hide this widget Cacher ce widget AggregateWidget Final Function: Fonction finale : Sort Operator: Opérateur de tri : Initial Condition: Condition initiale : Funtion Inputs Entrées de la fonction Function State État de la fonction Transition Func.: Fonction de transition : Input Data Type Type de donnée en entrée State Data Type Type de donnée d'état An aggregate function that accepts the types <em><strong>typeA</strong></em> and <em><strong>typeB</strong></em> as input types and which type of state is <em><strong>state_type</strong></em>, must obey the following rules: <br/><br/> <strong> &nbsp;&nbsp;&nbsp;• Final Function:</strong> <em>void final_function(<strong>state_type</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp;• Transition Function:</strong> <em><strong>state_type</strong> transition_function(<strong>state_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em> Une fonction d'agrégat qui accepte les types <em><strong>typeA</strong></em> et <em><strong>typeB</strong></em> en types d'entrée et dont le type d'état est <em><strong>state_type</strong></em>, vous devez respecter les règles suivantes : <br/> <strong>&nbsp;&nbsp;&nbsp;• Fonction finale : </strong><em>void final_function (<strong>state_type</strong>)</em><br/> <strong>&nbsp;&nbsp;&nbsp;• Fonction de transition: </strong><em><strong>state_type</strong> transition_function(<strong>state_type</strong>,<strong>typeA</strong>, <strong>typeB</strong>)</em> AppearanceConfigWidget Form Formulaire Element: Élément : Global: Font style Global : Style de police Global: Constraints descriptor Global : Marqueurs de contraintes Global: Object selection Global : Sélection d'objet Global: Position hint text Global : Texte de la boite de coordonnées Global: Position hint box Global : Fond de la boite de coordonnées Global: Objects type Global : Type de colonne Global: Lock arc Global : Cadenas (objet verrouillé, couleur de l'arceau) Global: Lock body Global : Cadenas (objet verrouillé, couleur du corps) Table: Schema name Table : Nom du schéma Table: Table name Table : Nom de la table Table: Columns box Table : Zone des colonnes Table: Extended attributes box Table : Zone d'attributs étendus Table: Title box Table : Zone de titre Rule: Name Règle : Nom Rule: Descriptor Règle : Couleur de l'icône Index: Name Index : Nom Index: Descriptor Index : Couleur de l'icône Trigger: Name Déclencheur : Nom Trigger: Descriptor Déclencheur : Couleur de l'icône View: Schema name Vue : Nom du schéma View: View name Vue : Nom de la vue View: References box Vue : Couleur d'arrière plan View: Extended attributes box Vue : Dialogue des attributs étendus View: Title box Vue : Couleur d'arrière plan de la barre de titre View: Table / columns alias Vue : Alias de table / colonne View: Referenced column Vue : Colonne référencée View: Referenced table Vue : Table référencée View: Reference descriptor Vue : Couleur de l'icône des références Textbox: Body Zone de texte : Corps Column: Column name Colonne : Nom de la colonne Column: Descriptor Colonne : Couleur de l'icône Column: Included / Inherited by relationship Colonne : Incluses / Héritées par associations Column: Protected Colonne : Protégée Column (pk): Column name Colonne (pk) : Nom de la colonne Column (pk): Descriptor Colonne (pk) : Couleur de l'icône Column (fk): Column name Colonne (fk) : Nom de la colonne Column (fk): Descriptor Colonne (fk) : Couleur de l'icône Column (uq): Column name Colonne (uq) : Nom de la colonne Column (uq): Descriptor Colonne (uq) : Couleur de l'icône Column (nn): Column name Colonne (nn) : Nom de la colonne Column (nn): Descriptor Colonne (nn) : Couleur de l'icône Relationship: Descriptor Associations : Couleur de l'icône Relationship: Label text Associations : Texte de l'étiquette Relationship: Label box Relations : Arrière plan de l'étiquette Relationship: Attribute text Relations : Texte des attributs Relationship: Attribute descriptor Relations : Couleur de l'icône des attributs Tag: Name Nom Tag: Body Corps Font: Police : pt pt Bold Gras Italic Italique Colors: Couleur : Underline Souligné Placeholder: Body Placeholder : Corps Constraint: Name Contrainte : Nom Constraint: Descriptor Contrainte : Descripteur Application Unknown exception caught! Exception inconnue générée ! Failed to create initial configuration in `%1'! Check if the current user has write permission over that path and at least read permission over `%2'. Impossible de créer les fichiers de configuration initiaux dans `%1' ! Vérifiez que le dossier existe que vous avez la permission d'écriture dans `%2'. BaseConfigWidget A backup of the previous settings was saved into <strong>%1</strong>! Une sauvegarde des paramètres précédents a été enregistrée dans <strong>%1</strong> ! BaseForm Dialog Dialogue &Apply &Appliquer &Ok &Ok &Cancel A&nnuler %1 properties %1 propriétés BaseObject Column Colonne Constraint Contrainte Function Fonction Trigger Déclencheur Index Index Rule Règle Table Table View Vue Domain Domaine Schema Schéma Aggregate Fonction d'agrégat Operator Opérateur Sequence Séquence Role Rôle Conversion Convertion Cast Convertion de type Language Langage Type Type Operator Family Famille d'opérateurs Operator Class Classe d'opérateurs Database Base de données Extension Extension Relationship Relation Collation Collation Textbox Boite de texte Event Trigger Déclencheur sur évènement Policy Politique Permission Permission Parameter Paramètre Type Attribute Attribut de type Basic Relationship Relation simple Tag Balise Generic SQL SQL générique new_object nouvel_objet nouveaux_objets Tablespace Espace de stockage BaseObjectView SQL off SQL désactivé BaseObjectWidget Name: Nom : ID: Identifiant : icone icône Comment: Commentaire : Tablespace: Espace de stockage : Edit object's permissions Modifier les permissions de l'objet Disables the generated SQL code using comment tokens (--). This will disable the code of all child and referrer objects. Désactivez le code SQL généré en utilisant les marqueurs de commentaire (--). Ceci désactivera également le code SQL pour ses objets enfants. Append or prepend a set of SQL commands to the object's definition. Ajouter des commandes SQL avant ou après la définition de cet objet. Custom SQL Code SQL Libre Owner: Propriétaire : Schema: Schéma : Disable SQL code Désactiver le code SQL Collation: Collation : Edit permissions Modifier les permissions This object is protected thus no change in form will be applied to it. L'objet est verrouillé, par conséquent aucun changement dans le formulaire ne lui sera appliqué. Required field. Leaving this empty will raise errors! Champ requis. Laisser ce champ vide génèrera une erreur ! Value(s) Valeur(s) Version The <em style='color: %1'><strong>highlighted</strong></em> fields in the form or one of their values are available only on specific PostgreSQL versions. Generating SQL code for versions other than those specified in the fields' tooltips may create incompatible code. Les champs <em style='color:%1'><strong>en surbrillance</strong></em> dans le formulaire ou de l'une des valeurs ne sont disponibles que sur des versions spécifiques de PostgreSQL. La génération de code SQL pour des versions autres que celles spécifiées dans les info-bulles des champs peut créer un code incompatible. BaseRelationship rel_%1_%2 rel_%1_%2 BaseTableView Toggles the extended attributes display (Dés)activer l'affichage des attributs étendus Connected rels: %1 Rels connectés : %1 BugReportForm Bug Report Signaler un bug Bug report Signaler un bug Create Créer &Cancel A&nnuler Use the form below to generate a complete bug report. Please, try to be as clear as possible when describing the actions that can reproduce the bug. Additionally, it's important to attach a sample database model so that the bug can be quickly discovered and fixed! Utilisez le formulaire ci-dessous pour générer un rapport d'erreur complet. Merci d'être le plus clair possible dans la description de vos actions afin que le bug puisse être reproduit. De plus, il est important de joindre un modèle de base dans lequel le bug puisse être rapidement découvert, et par la même occasion rapidement corrigé ! Report Rapport Issue details Détails du problème Output: Sortie : Select the report's output folder Sélectionnez un dossier de sortie pour écrire le rapport d'erreur ... ... <html><head/><body><p>If you prefer it's possible to report this issue anytime on pgModeler's project repository at <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html> <html><head/><body><p>Il vous est également possible de signaler un bug à tout moment via le dépôt du projet pgModeler sur <a href="http ://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration : underline; color :#0057ae;">GitHub</span></a>. </p></body></html> Database Model Modèle de base Attach the below database model file to be debugged. Joindre le fichier modèle ci-dessous pour débogage. Attach a different database model Joindre un autre modèle de base Bug report successfuly generated! Please, send the file <strong>%1</strong> to <em>%2</em> in order be analyzed. Thank you for the collaboration! Le rapport de bug a été généré avec succès ! S'il vous plait, veuillez envoyer le fichier <strong>%1</strong> à <em>%2</em> pour expertise. Merci de votre collaboration ! Load model Charger un modèle Database model (*.dbm);;All files (*.*) Modèle de base de données (*.dbm);; Tous les fichiers (*.*) Select report output folder Sélectionner le dossier de sortie du rapport BulkDataEditWidget Bulk data edit Modification de données en masse CastWidget Conversion Func.: Fonction de conversion : Cast Type: Conversion de type : Assignment Affectation Input / Output Entrée / Sortie Source data type Type de donnée source Target data type Type de donnée cible The function to be assigned to a cast from <em><strong>typeA</strong></em> to <em><strong>typeB</strong></em> must have the following signature: <em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>. La fonction convertissant de <em><strong>typeA</strong></em> vers <em><strong>typeB</strong></em> doit avoir la signature suivante : <em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>. I&mplicit I&mplicite E&xplicit E&xplicite CodeCompletionWidget Make &persistent Rendre &persistant Makes the widget closable only by ESC key or mouse click on other controls. Rendre ce widget refermable uniquement par la touche Échap ou par un clic sur les autres contrôles. SQL Keyword Mot-clé SQL (no items found.) (aucun élément trouvé.) CollationWidget Locale: Locale : Encoding: Encodage : LC_COLLATE: LC_COLLATE : LC_CTYPE: LC_CTYPE : The fields <strong><em>Collation</em></strong>, <strong><em>Locale</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> are mutually exclusive, so you have to set only one of them in order to properly handle a collation. Les champs <strong><em>Collation</em></strong>, <strong><em>Locale</em></strong> et <strong><em>LC_COLLATE & LC_CTYPE</em></strong> sont mutuellement exclusifs, vous ne devez en définir qu'un seul de manière à gérer correctement la collation. Not defined Non défini ColorPickerWidget Form Formulaire Generate random color(s) Génération aléatoire de couleur(s) Alt+R Alt+R Select color Sélectionner une couleur ColumnWidget Default Value: Valeur par défaut : E&xpression: E&xpression : &NOT NULL &NON NULL Se&quence: Sé&quence : Edit the underlying sequence's attributes Edit sequence Identity: Identité : ConfigurationForm pgModeler Configuration Paramètres de pgModeler Relationships Associations Appearance Apparence Connections Connexions Snippets Extraits de code &Apply &Appliquer &Cancel A&nnuler Defaults Défauts General Général Plug-ins Extensions In some cases restore the default settings related to it may solve the problem. Would like to do that? Dans certains cas, restaurer les paramètres liés par défaut peut résoudre le problème. Voulez-vous le faire ? Restore Restaurer Any modification made until now in the current section will be lost! Do you really want to restore default settings? Toutes les modifications réalisées jusqu'à maintenant dans la section actuelle seront perdues ! Souhaitez-vous réellement restaurer les paramètres par défaut ? ConnectionsConfigWidget Connections: Connexions : Create new connection Créer une nouvelle connexion Cancel edition Annuler l'édition Duplicate the selected connection Dupliquer la connexion sélectionnée Edit selected connection Modifier la connexion sélectionnée Delete selected connection Supprimer la connexion sélectionnée Connection Alias: Alias de la connexion : Connection DB: Nom de la base : Host/Port: Hôte/Port : User: Utilisateur : Password: Mot de passe : Timeout: Délai d'expiration : second(s) seconde(s) SSL Mode: Mode SSL : Disable Désactivé Allow Autorisé Require Requis AC verification Vérification des AC Full verification Vérification complète Client Certificate: Certificat client : ~/.postgresql/postgresql.crt ~/.postgresql/postgresql.crt Automatically browses the named database when using this connection to manage databases on <strong>Manage</strong> view. Parcourt automatiquement la base de données nommée lors de l'utilisation de cette connexion pour gérer les bases de données dans la vue <strong>Gérer</strong>. Auto browse Toujours montrer Client Key: Clé client : ~/.postgresql/postgresql.key ~/.postgresql/postgresql.key Root Certificate: Certificat racine : ~/.postgresql/root.crt ~/.postgresql/root.crt Revoked Certs.: Liste de révocations : ~/.postgresql/root.crl ~/.postgresql/root.crl Force GSSAPI Forcer GSSAPI Add Ajouter Update Mettre à jour Test Tester Success Succès Edit database connections Modifier les connexions de la base de données General Général Other params: Autres paramètres : Specify additional connection parameters in the form [param]=[value]. These parameters are described in the <strong>libpq</strong> chapter at PostgreSQL docs. Spécifier des paramètres de connexion supplémentaires sous la forme [param]=[valeur]. Ces paramètres sont décrits dans le chapitre <strong>libpq</strong> de la doc de PostgreSQL. Default for: Par défaut pour : Diff Différencier Export Exporter Import Importer Validation Validation Security Sécurité Kerberos Server: Serveur Kerberos : Indicates in which operations (diff, export, import or validation) the connection is used if none is explicitly specified by the user. Indique dans quelles opérations (differencier, exporter, importer ou validation) la connexion est utilisée si aucune n'est explicitement spécifiée par l'utilisateur. Connection successfully established! Server details: PID: `%1' Protocol: `%2' Version: `%3' Connexion établie avec succès ! Détails du serveur : PID : `%1' Protocole : `%2' Version : `%3' There is a connection being created or edited! Do you want to save it? Une connexion est en cours de création ou d'édition ! Voulez-vous la sauvegarder ? Found %1 connection(s) %1 connexion(s) trouvée(s) No connections found Aucune connexion trouvée Edit connections Modifier les connexions ConstraintWidget Constraint Type: Type de contrainte : Fill Factor: Taux de remplissage : Match: Comparaison : This attribute cannot be changed once the object is created. Cet attribut ne peut pas être modifié une fois l'objet créé. Expression: Expression : Deferrable: Reportable : Deferral: Report : ON DELETE: ON DELETE : ON UPDATE: ON UPDATE : Columns Colonnes Column: Colonne : Referenced Columns Colonnes référencées Table: Table : Indexing: Indexation : Exclude Elements Éléments exclus No inherit: Pas d'héritage : Column Colonne Type Type Columns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form. Les colonnes inclues dans la relation ne peuvent être ajoutées/retirées manuellement de la clé primaire sous peine d’erreur. Pour créer une clé primaire utilisant des colonnes contenues dans une relation, veuillez utiliser une des options suivantes: champ identifiant, l'onglet attributs et contraintes ou l'onglet clé primaire du formulaire de la relation. ConversionWidget Source Encoding: Encodage de la source : Target Encoding: Encodage de la destination : Conversion Func.: Fonction de conversion : Default Conversion: Conversion par défaut : The function to be assigned to an encoding conversion must have the following signature: <em>void function(integer, integer, cstring, internal, integer)</em>. La fonction de convertion d'encodage doit avoir la signature suivante : <em>void function(integer, integer, cstring, internal, integer)</em>. CrashHandlerForm Crash Handler Gestionnaire d'incident Stack trace Pile d'exécution Input: Entrée : Load report file for analysis Charger un rapport d'erreur pour analyse Save the attached model file on the filesystem Enregistrer le modèle joint sur le système de fichiers pgModeler bug report (*.bug);;All files (*.*) Rapport de bug pgModeler (*.bug);;Tous les fichiers (*.*) Load report Charger un rapport Save model Enregistrer le modèle Database model (*.dbm);;All files (*.*) Modèle de base de données (*.dbm);; Tous les fichiers (*.*) Crash handler Gestionnaire d'incident Bug report analysis mode activated. Mode d'analyse de rapport d'erreur activé. Oops! pgModeler just crashed! Oups ! pgModeler a planté ! We apologize for what happened! It is clear that a nasty bug caused that. Please fill out the form below describing your actions before pgModeler quit unexpectedly. This will help on bug extermination and improve the software. Veuillez nous excuser pour ce qui vient de se passer ! Il est clair qu'un vilain bug est à l'origine de tout cela. Veuillez renseigner le formulaire ci-dessous en décrivant les actions que vous avez faites avant que pgModeler ne sombre de manière inopinée. Cela nous aidera à exterminer ce bug et ainsi, à améliorer le logiciel. CsvLoadWidget Form Formulaire Load CSV Charger un fichier CSV CSV File: Fichier CSV : Select output file Sélectionner un fichier de sortie ... Separator: Séparateur : Use the first row as column names in the CSV file. By unchecking this option the first row is used as data. Utiliser la 1ère ligne comme noms de colonne pour le fichier CSV. En décochant cette option, la 1ère ligne est utilisée comme données. Columns in the first row Colonnes dans la 1ère ligne Load Charger Semicolon (;) Point virgule (;) Comma (,) Virgule (,) Space Espace Tabulation Other Autre ; Text delimiter: Délimiteur : " Load CSV file Charger un fichier CSV Comma-separted values (*.csv);;All files (*.*) Valeurs séparées par une virgule (*.csv);;Tous les fichiers (*.*) CustomSQLWidget SQL code Code SQL Puts an SELECT command template at current cursor position. Insère une commande SELECT à la position courante du curseur. &SELECT &SELECT Puts an INSERT command template at current cursor position. Insère une commande INSERT à la position courante du curseur. &INSERT &INSERT Puts an UPDATE command template at current cursor position. Insère une commande UPDATE à la position courante du curseur. Puts an DELETE command template at current cursor position. Insère une commande DELETE à la position courante du curseur. &DELETE &DELETE &Clear E&ffacer Append SQL Code SQL suffixé Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command. Ajouter le code SQL à la toute fin de la définition du modèle Sinon (décoché) pgModeler ajoutera ce code après la commande SQL CREATE DATABASE. Append at end of model definition. Suffixer à la fin de la définition du modèle. Prepend SQL Code SQL préfixé Prepend at beginning of model definition. Préfixer au tout début de la définition du modèle. <html><head/><body><p>Use custom commands with extreme caution because you can change the semantics of the entire model when running SQL validation or export processes. Additionally, depending on the amount of commands, those processes can have their performance sensibly degradated.</p></body></html> <html><head/><body><p>Utilisez cet espace pour y inscrire vos commandes SQL personnalisées avec précaution. Vous pourriez créer des incohérences qui peuvent interférer avec les fonctionnalités de validation et d'export du modèle. De plus, selon la nature des commandes entrées ces fonctionnalités peuvent être ralenties.</p></body></html> Generic INSERT INSERT générique Include serial columns Inclure les colonnes en série Exclude serial columns Exclure les colonnes en série Generic SELECT Faut-il le traduire ? Table SELECT Faut-il le traduire ? Generic UPDATE Faut-il le traduire ? Table UPDATE Faut-il le traduire ? Generic DELETE Faut-il le traduire ? Table DELETE Faut-il le traduire ? &UPDATE Faut-il le traduire ? Add custom SQL code Ajouter un code SQL personnalisé DataManipulationForm Data Manipulation Édition des données &Close &Fermer Refresh listing Actualiser la liste F5 F5 Save changes Enregistrer les changements Ctrl+S Ctrl+S Export results to CSV file Exporter les résultats vers un fichier CSV Ctrl+X Ctrl+X Undo modifications Annuler les modifications Ctrl+Z Ctrl+Z Ins Ins Mark the selected rows to be deleted Marquer les lignes sélectionner pour suppression Del Suppr Filter the result set Filtrer les résultats Table: Table : Schema: Schéma : in dans Hide views Masquer les vues Filter expression Expression pour filtrer Order && Limit Ordre && Limite Column: Colonne : Limit in: Limite : Add Item Ajouter un élément Remove Item Supprimer un élément Clear the order by columns list Effacer la liste Move selected item up Déplacer vers le haut Move selected item down Déplacer vers le bas Copy as CSV Copier en CSV Copy as text Copier en texte Copy items Copier les éléments Pase items Coller les éléments Browse tables Navigateur de tables Duplicate row(s) Dupliquer ligne(s) Delete row(s) Effacer ligne(s) Edit cell(s) Modifier cellule(s) <em>(Limit: <strong>%1</strong>)</em> <em>(Limite : <strong>%1</strong>)</em> Column Colonne No objects found Aucun objet trouvé Found %1 object(s) %1 objet(s) trouvé(s) Views can't have their data handled through this grid, this way, all operations are disabled. Les données des vues ne sont pas modifiables via cette grille, de ce fait, toutes les opérations sont bloquées. The selected table doesn't owns a primary key! Updates and deletes will be performed by considering all columns as primary key. <strong>WARNING:</strong> those operations can affect more than one row. La table sélectionnée n'a pas sa propre clé primaire ! Les mises à jour et les suppressions seront réalisées en considérant que l'ensemble des colonnes constitue une clé primaire. <strong>ATTENTION :</strong> ces opérations peuvent affecter plus d'une ligne. Referenced tables Tables référencées (none) (aucun) Referrer tables Tables de référence This row is marked to be %1 Cette ligne est marquée pour être %1 deleted supprimé updated mise à jour inserted inséré [binary data] [données binaires] <strong>WARNING:</strong> Once commited its not possible to undo the changes! Proceed with saving? <strong>ATTENTION :</strong> Une fois validés, il ne sera plus possible d'annuler les changements ! Sauvegarder les changements ? delete effacer update mettre à jour insert inserer ASC ASC DESC DESC Add empty rows Ajouter des lignes vides Duplicate the selected rows Dupliquer les lignes sélectionnées Ctrl+D Ctrl+D results (Use <strong>0</strong> for no limit) résultats (Utiliser <strong>0</strong> pour ne pas limiter) <strong>WARNING: </strong> There are some changed rows waiting the commit! Do you really want to discard them and retrieve the data now? <strong>ALERTE :</strong> Des lignes modifiées attendent d'être soumises ! Voulez-vous vraiment les jeter et récupérer les données maintenant ? Rows returned: <strong>%1</strong>&nbsp;&nbsp;&nbsp; Lignes retournées : <strong>%1</strong>&nbsp;&nbsp;&nbsp; none aucun <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> <html><head/><body><p>Les valeurs vides sont supposées être <span style="font-weight :600;">DEFAULT</span>. Pour utiliser des valeurs spéciales comme <span style="font-weight :600;">NULL</span>, un appel de fonction comme <span style="font-weight :600;">now()</span> ou un échappement des données spécifiques, entourer les valeurs de deux barres obliques, par exemple <span style="font-weight :600;">/valeur/</span>. Pour utiliser une barre oblique dans le cadre de la valeur, ajouter le caractère barre oblique inverse, par exemple <span style="font-weight :600;">/</span>.</p></body></html> Copy items on the grid Copier les éléments sur la grille Paste items on the grid Copier les éléments sur la grille Ctrl+V Browse referenced tables Parcourir les tables référencées Add new rows from a CSV file Ajouter de nouvelles lignes depuis un fichier CSV Change the values of all selected cells at once Modifier d'un coup les valeurs de toutes les cellules sélectionnées Ctrl+E Ctrl+E DatabaseExplorerWidget Form Formulaire Data &Grid &Grille des données Alt+G Alt+G ... ... Expands all items Ouvre tous les nœuds de l'arborescence Collapses all items Ferme tous les nœuds de l'arborescence Filter: Filtrer : By OID Par OID Attribute Attribut Value Valeur (not found, OID: %1) (OID: %1 non trouvé) By value Par valeur Collatable Assemblable Constraint Contrainte Default Défaut Definition Définition Element Élément Encrypted Chiffré Enumerations Énumérations Function Fonction Language Langage Length Longueur Library Bibliothèque Materialized Matérialisée Name Nom Precision Précision Preferred Préféré Schema Schéma Storage Stockage Superuser Super utilisateur Tablespace Espace de stockage Unlogged Déconnecté Validity Validité Subtype Sous-type Columns Colonnes Event Évènement Client encoding Codage du client Configuration file Fichier de configuration Data directory Dossier de données Dynamic library path Chemin de la bibliothèque dynamique Dynamic shared memory Mémoire partagée dynamique Hba file Fichier hba Listen addresses Écouter des adresses Max. connections Connexions max. Listen port Écouter port Server encoding Encodage serveur SSL ca file Fichier ca SSL SSL cert file Fichier cert SSL SSL crl file Fichier crl SSL SSL key file Fichier clé SSL Server version Version serveur Ident file Fichier d'identité Password encryption Mot de passe de chiffrement Connection ID ID connexion Server PID PID serveur Server protocol Protocole serveur Identity Identité Command Commande Roles Rôles Show objects filter Afficher les objets filtrés Show system objects Afficher les objets système Show extension objects Afficher les objets d'extension Snippets Bouts de code Drop object Supprimer l'objet Drop cascade Supprimer en cascade Truncate Tronquer Trunc. cascade Tronquer en cascade Show data Afficher les données Reload properties Recharger les propriétés Update Mettre à jour -- Source code unavailable for this kind of object -- -- Code source indisponible pour ce type d'objet -- Do you really want to drop the object <strong>%1</strong> <em>(%2)</em>? Voulez-vous vraiment supprimer l'objet <strong>%1</strong> <em>(%2)</em> ? Do you really want to truncate the table <strong>%1</strong>? Voulez-vous vraiment tronquer la table <strong>%1</strong> ? Do you really want to <strong>cascade</strong> truncate the table <strong>%1</strong>? This action will truncate all the tables that depends on it? Voulez-vous vraiment tronquer en <strong>cascade</strong> la table <strong>%1</strong> ? Cette action tronquera toutes les tables qui en dépendent ! Admin. roles Rôles admin. Alignment Alignement Analyze func. Fonc. d'analyse Arg. count Nombre d'arg. Arg. default count Nombre d'arg. par défaut Arg. defaults Arg. par défaut Arg. modes Modes des arg. Arg. names Noms des arg. Arg. types Types des arg. Behavior type Type de comportement Cast type Type de conversion Category Catégorie Comment Commentaire Commutator Op. Commutateur Op. Collation Conn. limit Limite conn. Configuration Create DB Créer DB Create role Créer rôle Curr. version Version courante Default value Valeur par défaut Delimiter Délimiteur Dest. type Type de dest. Dimension Directory Répertoire Dest. encoding Encodage de dest. Encoding Encodage Exec. cost Exec. du coût Op. family Famille d'op. Expression Final func. Fonc. finale Func. type Type de fonc. Handler func. Gestionnaire de fonc. Handles type Type de poignées Hashes Index type Type d'index Inherit Hérité Ini. condition Condition ini. Inline func. Func. en ligne Input func. Fonc. d'entrée Internal length Longueur interne Interval type Type d'interval I/O cast Conversion E/S Join func. Fonc. de jointure LC COLLATE Faut-il le traduire ? LC CTYPE Faut-il le traduire ? Leak proof Étanche Left type Type gauche Can login Peut se connecter Member roles Rôles des membres Merges Fusionne Negator op. Négateur op. Not null Non nul Object type Type d'objet With OIDs Avec OIDs Old version Ancienne version OID Faut-il le traduire ? Operator Opérateur Operator func. Fonc. de l'opérateur Output func. Func. de sortie Owner Propriétaire Owner column Colonne propriétaire Parents Password Mot de passe Permissions Range attributes Attributs de plage Receive func. Fonc. de réception Ref. roles Rôles de ref. Replication Reproduction Restriction func. Fonc. de restriction Return type Type de retour Returns SETOF Retours SETOF Right type Type droit Rows amount Montant des lignes Security type Type de sécurité Send func. Fonc. d'envoi Sort op. Op. de tri Source type Type de source Src. encoding Encodage de la src. State type Type d'état Type mod. in func. Type de mod. dans la fonc. Type mod. out func. Type de mod. hors fonc. Transition func. Fonc. de transition Trusted Fiable Type attribute Attribut de type Type Types Validator func. Fonc. de validateur Windows func. Fonc. de fenêtre false faux true vrai Cache value Valeur du cache Increment Incrément Cycle Max. value Valeur max Min. value Valeur min Start value Valeur de départ Last value Dernière valeure Op. class Classe d'op. Canonical func. Fonc. de Canonical Subtype diff func. Fonc de comparaison de sous-type Deferrable Reportable For each row Pour chaque ligne Firing Déclencheur On insert À l'insertion On delete À la suppression On update À la mise à jour On truncate Au tronquage Arguments Table Trigger func. Fonc. de déclenchement Condition Deferment Ajournement Execution mode Mode d'exécution Commands Commandes Comparison type Type de comparaison Position Ref. columns Colonnes de ref. Expressions Fill factor Facteur de remplissage No inherit Non hérité Op. classes Classes op. Operators Opérateurs Ref. table Table de ref. Unique Predicate Prédicat Inherited Hérité Collations SSL Referrers Référents USING expr. Faut-il le traduire ? CHECK expr. Faut-il le traduire ? RLS enabled RLS forced Also restart sequences Warning Avertissement You're running a demonstration version! The data manipulation feature is available only in the full version! Vous utilisez une version de démonstration ! Cette fonctionnalité de manipulation de données est uniquement disponible dans la version complète ! <strong>CAUTION:</strong> You are about to drop the entire database <strong>%1</strong>! All data will be completely wiped out. Do you really want to proceed? <strong>ATTENTION :</strong> Vous êtes sur le point de supprimer l'intégralité de la base de données <strong>%1</strong> ! Toutes les données seront définitivement détruites. Voulez-vous vraiment le faire ? Open the grid to visualize or edit data Ouvrir la grille pour visualiser ou modifier les données Open a new SQL execution pane Ouvrir un nouveau panneau d'exécution de code SQL Ctrl+F6 Update the objects tree Mettre à jour l'arborescence des objets Drop this database Supprimer cette base de données Filters the currently loaded items in the tree by using a pattern and matching their names. If <strong>By OID</strong> is checked the pattern is interpreted as an integer value that represents the object id (OID). <br><br/><strong>HINT:</strong> if you need to search the entire database use the full refresh (<strong>Ctrl+F5</strong>) prior the filtering. Filtre les éléments actuellement chargés dans l'arborescence en utilisant un motif et en faisant correspondre leurs noms. Si <strong>Par OID</strong> est coché, le motif est interprété comme une valeur entière qui représente l'identifiant de l'objet (OID).<br><br/><strong>ASTUCE :</strong> si vous devez effectuer une recherche dans toute la base de données, utilisez l'actualisation complète (<strong>Ctrl+F5</strong>) avant le filtrage. Show raw attributes Afficher les attributs brutes -- Source code not generated! Hit F7 or middle-click the item to load it. -- -- Code source non généré ! Appuyer sur F7 ou faire un clic molette sur l'élément pour le charger. -- Rename Renommer Source code Code source Quick refresh Rafraîchissement rapide Full refresh Rafraîchissement complet Do you really want to <strong>cascade</strong> drop the object <strong>%1</strong> <em>(%2)</em>? This action will drop all the other objects that depends on it. Voulez-vous vraiment supprimer en <strong>cascade</strong> l'objet <strong>%1</strong><em> (%2)</em> ? Cette action supprimera tous les autres objets qui en dépendent. Src. table: %1 Src. column(s): %2 Table src. : %1 Colonne(s) src. : %2 Ref. table: %1 Ref. column(s): %2 Table de ref. : %1 Colonne(s) de ref. : %2 -- Source code genaration for buil-in and base types currently unavailable -- -- Génération de code source pour les types intégrés et les type de base actuellement indisponibles -- -- Source code unavailable for the object %1 (%2). -- -- Code source indisponible pour l'objet %1 (%2). -- Toggle the display of filter widget as well the system/extension objects. (Dés)activer l'affichage du widget de filtre ainsi que les objets système/extension. Sort items alphabetically. When unchecked, items are sorted by OID. Trier les éléments par ordre alphabétique. Lorsque ce n'est pas coché, les éléments sont triés par OID. Sort alphabetically Trier par ordre alphabétique DatabaseImportForm &Import &Importer &Close &Fermer Options Options Enables the import of objects created by extensions. Generally there is no need to check this option but if there are objects in the database that directly references this category of objects this mode must be enabled. Active l'import des objets créés par les extensions. Généralement il n'y a pas lieu d'activer cette option sauf si des objets en base référencent directement ce type d'objet. Import extension objects Importer les objets des extensions Connection: Connexion : Ignore import errors Ignorer les erreurs pgModeler ignores import errors and will try to create as many as possible objects. By checking this option the import operation will be not aborted but an incomplete model will be constructed. This option generates a log file on pgModeler's temp directory. pgModeler ignorera les erreurs qui pourront survenir lors de l'import et essayera de créer autant d'objets qui lui sera possible. En activant cette fonction le processus d'import ne sera pas interrompu, toutefois vous pourrez vous retrouver avec un modèle incomplet. Cette option active la génération d'un fichier log dans le dossier temporaire de pgModeler. Enables the import of system built-in objects. It's recommend to select only those objects that are directly referenced by the ones to be imported. WARNING: Try to import a huge set of system objects can bloat the resultant model or even crash pgModeler due to memory/cpu overuse. Active l'importation d'objets intégrés au système. Il est recommandé de sélectionner uniquement les objets directement référencés par ceux à importer. AVERTISSEMENT : Essayer d'importer un grand nombre d'objets système peut gonfler le modèle résultant ou même planter pgModeler en raison de la surutilisation de la mémoire/cpu. Import system objects Importer les objets système Automatically resolve dependencies Résoudre automatiquement les dépendances ... ... Debug mode Activer le mode debug Settings Paramètres Random colors will be assigned to imported relationships facilitating the identification of links between tables mainly in large models. Colorer les associations de manière aléatoire afin de faciliter l'identification des liens entre les tables, cela peut être utile sur de grands modèles. Random colors for relationships Colorer les associations de manière aléatoire Database Base de données Select all objects Tout cocher Clear object selection Tout décocher Expands all items Développer tous les éléments Collapses all items Replier tous les éléments Filter: Filtrer : Filter object by it's OID Filtrer un objet par son OID By OID Par OID Output Sortie Progress label... Indicateur de progression... Cancel Annuler Retrieving objects from database... Récupération des objets depuis la base de données... Importing process aborted! Processus d'import abandonnée ! Importing process canceled by user! Processus d'import interrompu par l'utilisateur ! Importing process sucessfuly ended! Processus d'import terminé avec succès ! No databases found Aucune base de données trouvée Found %1 database(s) %1 base(s) de données trouvée(s) Retrieving cluster level objects... Récupération des objets du cluster... Retrieving objects of schema `%1'... Récupération des objets du schéma `%1'... Retrieving objects of `%1' (%2)... Réccupération des objets de `%1' (%2)... This is a PostgreSQL built-in data type and cannot be imported. C'est un type de données nativement intégré à PostgreSQL. Il ne peut être importé. This is a pgModeler's built-in object. It will be ignored if checked by user. C'est un objet nativement intégré à pgModeler. Il sera ignoré s'il est coché par l'utilisateur. Create all imported objects in the current working model instead of create a new one. Créer tous les objets importés dans le modèle de travail actuel au lieu d'en créer un nouveau. Import objects to the working model Importer les objets dans le modèle de travail en cours <strong>ATTENTION:</strong> You are about to import objects to the current working model! This action will cause irreversible changes to it even in case of critical errors during the process. Do you want to proceed? <strong>ATTENTION :</strong> Vous êtes sur le point d'importer des objets dans le modèle de travail actuel ! Cette action entraînera des modifications irréversibles même en cas d'erreurs critiques au cours du processus. Voulez-vous poursuivre ? Resolve some of the object's dependencies by querying the catalog when a needed object does not exists on the loaded set. In some cases it's necessary to combine this option with others below. This option does not applies to database level objects like role, tablespace and language as well for data types, extensions. Résoudre certaines dépendances de l'objet en interrogeant le catalogue. Dans certains cas, il est nécessaire de combiner cette option avec les autres ci-dessous. Cette option ne s'applique pas aux objets du niveau de la base de données, tels que le rôle, l'espace de stockage et la langue, pour les types de données et les extensions. All catalog queries as well the created objects' source code are printed to standard output (stdout). Toutes les requêtes de catalogue ainsi que le code source des objets créés sont imprimés sur la sortie standard (stdout). Import database Importer une base de données DatabaseImportHelper Retrieving system objects... `%1' Récupération des objets système... `%1' Retrieving objects... `%1' Récupération des objets... `%1' Creating table inheritances... Création des tables héritées... Creating object `%1' (%2)... Création de l'objet `%1' (%2)... Creating columns permissions... Création des permissions sur les champs... Destroying unused detached columns... Destruction des colonnes détachées inutilisées... The database import ended but some errors were generated and saved into the log file `%1'. This file will last until pgModeler quit. L'import de la base de données est términée mais des erreurs ont été générées et sauvegardées dans le journal `%1'. Ce fichier sera disponible jusqu'à la fermeture de pgModeler. Creating object `%1' (%2), oid `%3'... Création de l'objet `%1' (%2), oid `%3'... Trying to recreate object `%1' (%2), oid `%3'... Tentative de création de l'objet `%1' (%2), oid `%3'... Import failed to recreate some objects in `%1' tries. L'import a échoué à recréer certains objets à `%1' reprise(s). Creating permissions for object `%1' (%2)... Création des autorisations pour l'objet `%1' (%2)... Updating relationships of `%1' (%2)... Mise à jour des relations de `%1' (%2)... Validating relationships... Validation des relations... Assigning sequences to columns... Affectation des séquences aux colonnes... DatabaseModel The demonstration version can create only `%1' instances of each object type! You've reach this limit for the type: `%2' Cette version de démonstration peut seulement créer `%1' instances pour chaque type d'objet ! Cette limite a été atteinte pour les objets de type : `%2' Loading: `%1' (%2) Chargement : `%1' (%2) Validating relationships... Validation des relations... Generating %1 code: `%2' (%3) Saving object `%1' (%2) Enregistrement de l'objet `%1' (%2) Saving metadata of the object `%1' (%2) Enregistrement des métadonnées de l'objet `%1' (%2) Metadata file successfully saved! Fichier de métadonnées enregistré avec succès ! Process successfully ended but no metadata was saved! Le processus s'est terminé avec succès mais aucune métadonnée n'a été enregistrée ! Creating object `%1' (%2) Création de l'objet `%1' (%2) Object `%1' (%2) already exists. Ignoring. L'objet `%1' (%2) existe déjà et a été ignoré. Loading metadata for object `%1' (%2) Chargement des métadonnées de l'objet `%1' (%2) Object `%1' (%2) not found. Ignoring metadata. Objet`%1' (%2) introuvable. Métadonnée ignorée. Metadata file successfully loaded! Fichier de métadonnées chargé avec succès ! DatabaseWidget Attributes Attributs Template DB: Modèle de BDD : Model Author: Auteur du modèle : Encoding: Encodage : Default Objects Attributs par défaut des objets Tablespace: Espace de stockage : Schema: Schéma : Collation: Collation : Owner: Propriétaire : LC_COLLATE: LC_COLLATE : Connections: Connexions : LC_CTYPE: LC_CTYPE : The fields <strong>LC_COLLATE</strong> and <strong>LC_CTYPE</strong> have pre-configured values based upon the running system. You can freely modify those values if you intend to export the model to another host. Les champs <strong>LC_COLLATE</strong> et <strong>LC_CTYPE</strong> ont déjà des valeurs pré-configurées basées sur le système. Vous pouvez librement les modifier si vous devez exporter le modèle vers une autre machine hôte. Use the above fields to specify the default attributes assigned to new objects created on the database model. Leaving a field empty will cause PostgreSQL to use the default values when exporting the model. Utilisez les champs ci-dessus pour spécifier les attributs par défaut à assigner aux nouveaux objets créés dans le modèle. Laisser un champ vide fera que PostgreSQL utilisera ses valeurs par défaut lors de l'export du modèle. Default Défaut Options: Options : Allow connections Autoriser les connexions Is template Est le modèle DomainWidget Name: Nom : Default Value: Valeur par défaut : Attributes Attributs Not null Non nulle Check constraints Vérifier les contraintes Expression: Expression : Name Nom Expression DonateWidget Form Formulaire Donate to pgModeler Faire un don à pgModeler Hide this widget Cacher ce widget ... ... <html><head/><body><p>pgModeler is brought to you thanks to a <span style=" font-style:italic;">great effort to create and distribute a quality product</span>. This project is reaching out levels of maturity never imagined. All this is the result of a joint work between its author and the <span style=" font-weight:600;">Open Source community</span>. <br/><br/>This software has a long way to go yet and with your help we'll keep maintaining the good job and bringing new improvements on each release. If you did like pgModeler and thinks it deserves a contribution please make a donation!</p></body></html> <html><head/><body><p>pgModeler vous est offert grâce à un <span style=" font-style :italic;">gros effort pour créer et distribuer un produit de qualité </span>. Ce projet atteint un niveau de maturité jamais imaginé. Tout ceci est le résultat d'un travail conjoint entre son auteur et la <span style="font-weight :600;">Communauté Open Source</span>.<br/><br/>Ce logiciel a encore un long chemin à parcourir mais avec votre aide, nous continuerons à faire du bon travail et à apporter de nouvelles améliorations à chaque version. Si vous avez aimé pgModeler et pensez qu'il mérite une contribution, faites un don ! </p></body></html> I want to help! Je veux aider ! ElementsWidget Form Formulaire Column: Colonne : Expression: Expression : Collation: Collation : Operator Class: Classe d'opérateurs : Operator: Opérateur : Sorting: Tri : Ascending Ascendant Descending Descendant Nulls first Null en premier Element Élément Type Operator Class Classe d'opérateur Sorting Tri Nulls First Vides en premier Collation Operator Operateur Expression Yes Oui No Non EventTriggerWidget Event: Évènement : Function: Fonction : Filter Filtrer Tag: Étiquette : Tag command Balise de la commande Exception Assignment of a pseudo-type to the type of the column! Utilisation d'un pseudo-type comme type de la colonne ! Assignment of a precision greater than the length of the type! Utilisation d'une précision est plus grande que la longueur du type ! Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! Utilisation d'une précision de type time, timestamp ou interval invalide. La précision de ces types doit être inférieure ou égale à 6 ! Reference to a column which index is out of the capacity of the column list! Référence à une colonne dont l'index dépasse la capacité de la liste des colonnes ! Assignment of not allocated object! Utilisation d'un objet non référencé ! Assigning object of an invalid type! Assignation d'un objet dont le type est invalide ! Removing an object of an invalid type! Suppression d'un objet dont le type est invalide ! Obtaining an object of an invalid type! L'objet obtenu est de type invalide ! Assignment of empty name to table return type! Affectation d'un nom vide au type retourné par la table ! Reference to an event which does not belongs to trigger! Référence à un évènement qui n'appartient pas au déclencheur ! Assignment of a function which language is invalid! Définition d'une fonction dont le langage est invalide ! Assignment of empty name to an object! Affectation d'un nom vide à l'objet ! Assignment of schema object which type is invalid! Affectation d'un schema dont le type est invalide ! Assignment of tablespace object with invalid type! Utilisation d'un espace logique dont le type est invalide ! Assignment of tablespace to an invalid object! Affectation d'un espace logique à un objet invalide ! Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique! Affectation d'un espace logique à une contrainte dont le type est invalide ! Pour appartenir à un espace logique une contrainte doit être une clé primaire ou unique ! Assignment of owner object which type is invalid! Affectation d'un propiétaire dont le type est invalide ! Assignment of owner to an invalid object! Affectation d'un propriétaire à un objet invalide ! Reference to a function with invalid type! Référence à une fonction dont le type est invalide ! Reference to an argument of the operator with invalid type! Référence à un argument de l'opérateur dont le type est invalide ! Reference to an operator with invalid type! Référence à un opérateur dont le type est invalide ! Assignment of value to an invalid option type on role! Utilisation d'un attribut invalide pour un rôle ! Reference to an invalid role type! Référence à un type de rôle invalide ! Insertion of empty command to the rule! Insertion d'une commande vide dans cette règle ! Is not possible to create a self generalization/copy relationship! The table can not inherit or copy their own attributes! Impossible de créer une association de généralisation/copie de relation avec elle même ! Une table ne peut hériter ou copier ses propres attributs ! Assignment of an object that already belongs to another table! Utilisation d'un objet appartenant déjà à une autre table ! Assignment of a schema to the sequence which differs from the schema of the owner table! Affectation d'un schéma à la séquence diffèrent du schéma de la table ! Assignment of an invalid value to one of the sequence attributes! Utilisation d'une valeur invalide comme attribut de séquence ! Assignment of a minimum value to the sequence which is greater than the maximum value! La valeur minimale de la séquence est supérieure à la valeur maximale ! Assignment of a null increment value to the sequence! La valeur de l'incrément de la séquence est nulle ! Assignment of null cache value to the sequence! La valeur cache de la séquence est nulle ! Allocation of object with invalid type! Le type de l'objet alloué est invalide ! Assignment of not allocated language! Utilisation d'un langage inconnu ! Assignment of language object which type is invalid! Définition d'un objet langage dont le type est invalide ! Reference to data type with an index outside the capacity of data types list! Référence à un type de donnée dont l'index est en dehors de la capacité de la liste des types de données ! Assignment of invalid type to the object! Affectation d'un type invalide à l'objet ! Obtaining types with invalid quantity! Utilisation d'une quantité de types invalide ! Insertion of item which already exists in the attributes list of the type! Insertion d'un attribut déjà présent dans la définition de ce type ! Insertion of invalid item in the attributes list of the type! Insertion d'un attribut invalide à la liste des attributs de ce type ! Insertion of item which already exists in the enumarations list of the type! Insertion d'un élément déjà existant dans l'énumeration ! Insertion of invalid item in the enumerations list of the type! Insertion d'un élément invlaide dans l'énumeration ! Assignment of invalid configuration to the type! La configuration assigné au type est invalide ! Assignment of an operator which input type count is invalid to aggregate function! Utilisation d'un opérateur dont le nombre d'argument est invalide avec une fonction d'agrégation ! Assignment of an operator which types of arguments is invalid! Utilisation d'un opérateur dont le type des arguments est invalide ! There is already a relationship between `%1' (%2) and `%3' (%4) in the model! When using relationships of the type generalization, copy and one-to-one there can't be other relationships linked to the pair of tables. Il y a déjà une relation entre `%1 '(%2) et `%3' (%4) dans le modèle ! Lors de l'utilisation de relations de type généralisation, copie et un-à-un, il ne peut y avoir d'autres relations liées à la paire de tables. A view reference must be used in at least one these SQL scopes: View Definition, SELECT-FROM, FROM-WHERE or After WHERE! Lors de la définition d'une vue, une référence doit utiliser au moins un des champs SQL : SELECT-FROM, FROM-WHERE ou après WHERE ! Unable to load the configuration file `%1'! Please check if file exists in its folder and/or if it is not corrupted! Impossible de charger le fichier de configuration `%1'! Merci de vérifier que le fichier existe dans son dossier et / ou s'il n'est pas corrompu ! Could not find the default settings file `%1'! To restore default settings check the existence of the file and try again! Impossible de trouver le fichier des préférences par défaut `%1' ! Pour restaurer les préférences par défaut veuillez vérifier l'existance de ce fichier et réessayez ! Could not load the plugin `%1' from the library `%2'! Message returned by plugin manager: `%3' Impossible de charger l'extension `%1' depuis la bibliothèque`%2' ! Message retourné par le gestionnaire d'extension : `%3' Failed to drop the database `%1' because it is defined as the default database for the connection `%2'! Impossible de supprimer la base de données `%1 'car elle est définie comme base de données par défaut pour la connexion`%2' ! The column `%1' must be `NOT NULL' because it composes the primary key of the table `%2'. You need to remove the column from the mentioned contraint in order to disable the `NOT NULL' on it! La colonne `%1' doit être `NOT NULL' car elle compose la clé primaire de la table `%2'. Vous devez supprimer la colonne de la contrainte mentionnée afin de désactiver le `NOT NULL' dessus ! The identity column `%1' has an invalid data type! The data type must be `smallint', `integer' or `bigint'. La colonne d'identité `%1' a un type de données invalide ! Le type de données doit être `smallint', `integer' ou `bigint'. Reference to an invalid affected command in policy `%1'! Référence à une commande affectée invalide dans la règle `%1' ! Reference to an invalid special role in policy `%1'! Référence à un rôle spécial invalide dans la politique `%1' ! Assignment of a second definition expression to the view! Assignation d'une seconde expression à la vue ! Assignment of collation object which type is invalid! Utilisation d'un objet collation invalide ! Collations must be created at least with attributes LC_COLLATE and LC_CTYPE defined! Les collations doivent être définies avec les attributs LC_COLLATE et LC_CTYPE renseignés ! Reference to an invalid copy table option! Référence à une option invalide de copie de table ! The INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers! Le mode AU LIEU DE (INSTEAD OF) ne peut être utilisé comme déclencheur de table ! Ce n'est valable que pour les déclencheurs de vue ! The TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table! L'événement TRUNCATE ne peut être utilisé que lors d'un déclencheur sur chaque ligne et que s'il appartient à une table ! The INSTEAD OF mode cannot be used on view triggers that executes for each statement! Le mode AU LIEU DE (INSTEAD OF) ne peut être utilisé avec des déclencheurs de vues qui s’exécutent à chaque requête ! Constraint triggers can only be executed on AFTER events and for each row! Les déclencheurs de contraintes ne peuvent être exécutés qu'APRÈS les événements et pour chaque ligne ! A view trigger cannot be AFTER/BEFORE when it executes for each row! Les déclencheurs de vues ne peuvent être AFTER/BEFORE quand il sont configurés pour une exécution sur chaque ligne ! A trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event! Un déclencheur ne peut faire référence aux colonnes quand il est utilisé en mode INSTEAD OF sur un événement de type UPDATE ! Only constraint triggers can be deferrable or reference another table! Seuls les déclencheurs de contraintes peuvent être déférés ou référencer une autre table ! The validation process failed due to an error triggered by the validation helper. For more details about the error check the exception stack! La procédure de validation a échouée à cause d'une erreur levée par l'assistant de validation. Pour de plus d'informations, referez-vous à la pile des exceptions ! Assignment of an invalid strategy/support number to an operator class element! Affectation d'un numéro de stratégie/support invalide à un élément de la classe 'operator' ! Insertion of element which already exists in the element list! Insertion d'un élément déjà existant dans la liste des éléments ! Reference to a parameter which index is out of the parameter list bounds! Référence un paramètre dont l'index est hors des limites de la liste de ces derniers ! Reference to an argument which index is out of argument list bounds! Référence un argument dont l'index est hors des limites de la liste de ces derniers ! Assignment of a name which contains invalid characters! Utilisation de caractères invalides dans le nom ! Assignment of a name which length exceeds the maximum of 63 characters! Utilisation de plus de 63 caractères dans le nom ! Reference to a role which index is out of role list bounds! Référence un rôle dont l'index est hors des limites de la liste de ces derniers ! Reference to a command which index is out of the command list bounds! Référence une commande dont l'index est hors des limites de la liste de ces dernières ! Assignment of a start value to the sequence which is extrapolating the range defined by minimum and maximum values! Affectation de la valeur de départ de la séquence en dehors de la plage de cette dernière définie par les valeurs min et max ! Reference to a label which index is out of labels list bounds! Référence un label dont l'index est hors des limites de la liste de ces derniers ! Reference to an attribute which index is out of the attributes list bounds! Référence un attribut dont l'index est hors des limites de la liste de ces derniers ! Reference to an enumeration which index is out of the enumerations list bounds! Référence une énumération dont l'index est hors des limites de la liste de ces dernières ! Reference to an element which index is out of element list bounds! Référence un élément dont l'index est hors des limites de la liste de ces derniers ! Reference to an object which index is out of object list bounds! Référence un objet dont l'index est hors des limites de la liste de ces derniers ! Removal of an object not allocated! Suppression d'un objet non alloué ! The object `%1' (%2) can not be manipulated because it is reserved to PostgreSQL! This object is present in the database model only as a reference! L'objet `%1' (%2) ne peut être modifié car il est est réservé à PostgreSQL ! Cet objet apparaît dans le modèle uniquement comme référence ! Operation with object(s) which type(s) is invalid! Opérations sur un ou des objets dont les types sont invalides ! Reference to object with invalid type! Référence à un objet ayant un type invalide ! Operation with object not allocated! Opération sur des objets non alloués ! The relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user! Une association de type 1-1, quand les deux tables sont obligatoires, n'est pas implémentée car cela requiert la fusion des tables, ce qui casse le modèle réalisé par l'utilisateur ! Assignment of an invalid expression to the object! Affectation d'une expression invalide à l'objet ! Assignment of a primary key to a table which already has one! Impossible de définir une clé primaire à une table qui en possède déjà une ! Identifier relationship can not be created for a self relationship, relationships of the type n-n, copy or generalization! La relation d'identifiant ne peut pas être créée pour une relation vers elle même, pour les relations de type n-n, pour la copie ou pour la généralisation! An attribute can not be added to a copy or generalization relationship! Un attribut ne peut être ajouté à une relation copie ou généralisation ! A foreign key can not be added to a relationship because is created automatically when this is connected! Une clé étrangère ne peut être ajoutée à une relation car elle est créée automatiquement lors de la mise en relation ! Reference to an user-defined data type that not exists in the model! Référence à un type de donné défini par l'utilisateur qui n'existe pas dans le modèle ! Assignment of invalid maximum size to operation list! La taille maximum affectée à la liste d'opérations est invalide ! One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! Un ou plusieurs objets ont été invalidés et automatiquement supprimés car ils référençaient des colonnes qui étaient incluses dans des associations et qui n'existaient plus du fait de la suppression de l'associations ou de l'exclusion de ces colonnes ! Reference to an invalid privilege type! Référence à un type de privilège invalide ! Insertion of a role which already exists in the role list of the permission! Insertion d'un rôle déjà existant dans la liste de cette permission ! Assignment of privilege incompatible with the type of object referenced by permission! Utilisation d'un privilège incompatible avec le type d'objet référencé par la permission ! It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! Il est impossible de créer des tableaux de domaines ou de séquences (dimension >= 1) ! PostgreSQL n'inplémente pas encore cette fonctionnalité ! Assignment of invalid name to the table generated from N-N relationship! Le nom de la table générée par la relation N-N est invalide ! Reference to a column of the objects table with invalid index! Référence à une colonne de la table ayant un index invalide ! Reference to a row of the objects table with invalid index! Référence à une ligne de la table ayant un index invalide ! Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns! Les contraintes telles que clé primaire, clé étrangère ou unicité doivent avoir au moins une colonne associée ! Pour les clés étrangères, les colonnes référencées doivent également être sélectionnées ! The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 Le process d'exportat a échoué suite à une erreur déclenchée par le serveur PostgreSQL lors de la tentative d'exécution d'une commande SQL. Pour plus de détails concernant l'erreur vérifiez la pile d'exceptions ! ** Commande SQL exécutée: ** %1 One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. Une ou plusieurs extensions n'ont pas été activées suite à la survenue d'erreurs lors du chargement. Pour plus de détails, consultez la pile d'exceptions. Assignment of empty XML buffer to parser! Passage d'un tampon XML vide à l'analyseur ! Assignment of empty DTD file name! Le nom du fichier DTD est vide ! Assignment of empty name to the DTD declaration! Le nom de la déclaration DTD est vide ! Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! Opération sur l'arbre d'élément non alloué ! Il est nécessaire de charger le tampon d'analyseur XML et de l'interpréter pour que l'arbre soit généré ! Operation with unallocated tree element! Opération avec un élément de l'arbre non alloué ! Operation with element which does not exists in the element tree currently loaded! Opération avec un élément inexistant dans l'arbre des éléments actullement chargé ! Assignment of a value to an invalid connection parameter! Affectation d'une valeur à un paramètre de connexion invalide ! Operation on connection not established! Opération sur une connexion non établie ! Attempt to connect without define configuration parameters! Tentative de connexion sans paramètre de configuration défini ! Assignment of not allocated SQL command result! Affectation d'un résultat de commande SQL non alloué ! Unable to allocate the result of the SQL command because the response from the DBMS was not understood by the client! Impossible de retourner le résultat de la commande SQL car la réponse du SGBD n'a pas été comprise par le client ! Reference to a column of tuple with invalid index! Référence à une colonne de tuple dont l'index est invalide ! Reference to a column of tuple with invalid name! Référence à une colonne de tuple dont le nom est invalide ! Assignment of a not allocated column to object `%1' (%2)! Affectation d'une colonne non allouée à l'objet `%1 '(%2) ! Assignment of a not allocated schema to object `%1' (%2)! Affectation d'un schéma non allouée à l'objet `%1 '(%2) ! The object `%1' (%2) has inconsistent SQL or XML definition! L'objet `%1 '(%2) a une définition SQL ou XML incohérente ! The object `%1' (%2) already exists on `%3' (%4)! L'objet `%1 '(%2) existe déjà sur `%3' (%4) ! The object `%1' (%2) cannot be assigned because there is already exists in the container object `%3'! L'objet `%1 '(%2) ne peut être assigné car il existe déjà dans l'objet conteneur `%3' ! The insertion of the parameter `%1' will not be possible because there is another parameter with same name in the function `%2'! L'insertion du paramètre `%1' ne sera pas possible car il existe un autre paramètre avec le même nom dans la fonction `%2' ! The insertion of the table return type `%1' will not be possible because there is another return type with the same name in the `%2'! L'insertion du type de retour de la table `%1' ne sera pas possible car il existe un autre type de retour avec le même nom dans le`%2' ! The column `%1' cannot be assigned to the trigger `%2' because they belongs to different parent tables! La colonne `%1' ne peut pas être affectée au déclencheur `%2' car ils appartiennent à des tables parentes différentes ! Assignment of a not allocated function to object `%1' (%2)! Affectation d'une fonction non allouée à l'objet `%1' (%2) ! Assignment of a function which return type is different from `%1'! Affectation d'une fonction dont le type de retour est différent de `%1' ! Assignment of a function which parameter count is invalid to the object `%1' (%2)! Affectation d'une fonction dont le nombre de paramètres n'est pas valide pour l'objet `%1' (%2) ! Event trigger function must be coded in any language other than SQL! La fonction de déclenchement d'événement doit être codée dans n'importe quelle langue autre que SQL ! Assignment of not allocated table to object `%1' (%2)! Affectation de la table non allouée à l'objet `%1' (%2) ! Assignment of appended or prepended SQL to an invalid object! Affectation de code SQL ajouté ou préfixé à un objet invalide ! The insertion of the role `%1' is not possible because this is already being referenced by role `%2'! L'insertion du rôle `%1 n'est pas possible car il est déjà référencé par le rôle `%2' ! Reference redundancy detected by having the role `%1' referencing the role `%2'! Redondance de références détectée en ayant le rôle `%1' référençant le rôle `%2' ! The role `%1' can not be listed as a member of itself! Le rôle `%1' ne peut pas être listé comme un membre de lui-même ! Assignment of owner table which is not in the same schema as the sequence `%1'! Affectation de la table propriétaire qui n'est pas dans le même schéma que la séquence `%1' ! Assignment of owner table which does not belong to the same owner of the sequence `%1'! Affectation de la table propriétaire qui n'appartient pas au même propriétaire de la séquence `%1' ! Assignment of a nonexistent owner column to the sequence `%1'! Affectation d'une colonne propriétaire inexistante à la séquence `%1' ! Assignment of an owner column to the sequence `%1' that is not related to any table! Affectation d'une colonne propriétaire à la séquence `%1' qui n'est liée à aucune table ! Assignment of a function with invalid return type to object `%1' (%2)! Affectation d'une fonction avec un type de retour invalide à l'objet `%1' (%2) ! Assignment of a function with invalid parameter(s) type(s) to object `%1' (%2)! Affectation d'une fonction avec un (des) paramètre(s) non valide(s) à l'objet `%1' (%2) ! Assignment of an empty directory to object `%1' (%2)! Affectation d'un répertoire vide à l'objet `%1' (%2) ! Assignment of system reserved name to the object `%1' (%2)! Affectation du nom réservé au système à l'objet `%1' (%2) ! One function with invalid configuration is been used by the object `%1' (%2)! Une fonction avec une configuration invalide est utilisée par l'objet `%1' (%2) ! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4)! L'objet `%1' (%2) ne peut pas être supprimé car il est référencé par l'objet `%3' (%4) ! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4) that belongs to `%5' (%6)! L'objet `%1' (%2) ne peut pas être supprimé car il est référencé par l'objet `%3' (%4) appartenant à `%5' (%6) ! The creation of the relationship `%1' between the table `%2' and `%3' can not be done because one does not have a primary key. If the relationship is of the type n-n both tables must have primary keys! La création de la relation `%1' entre la table `%2' et `%3' ne peut pas être effectuée car il n'y a pas de clé primaire. Si la relation est du type n-n, les deux tables doivent avoir des clés primaires ! Unable to create a copy relationship because the column `%1' in table `%2' already exists in table `%3'! Impossible de créer une relation de copie car la colonne `%1' de la table `%2' existe déjà dans la table `%3' ! Unable to create the generalization relationship because the column `%1' in table `%2' can not be merged with the column `%3' of table `%4' because they have incompatible types! Impossible de créer la relation de généralisation car la colonne `%1' de la table `%2' ne peut pas être fusionnée avec la colonne `%3' de la table `%4' car ils ont des types incompatibles ! The object `%1' (%2) is referencing the object `%3' (%4) which was not found in the model! L'objet `%1' (%2) fait référence à l'objet `%3' (%4) qui n'a pas été trouvé dans le modèle ! Unable to write the file or directory `%1'! Make sure the output directory exists, or if the user has write permissions over it! Impossible d'écrire le fichier ou le répertoire `%1' ! Assurez-vous que le répertoire de sortie existe et que l'utilisateur a les droits d'écriture dedans ! The primary key `%1' can only be allocated if declared within a block of code that defines a table or relationship! La clé primaire `%1' ne peut être allouée que si elle est déclarée dans un bloc de code qui définit une table ou une relation ! There is already a permission on object `%1' (%2) which has one or more equal roles from those present on permission to be assigned to the object! Il y a déjà une permission sur l'objet `%1' (%2) qui a un ou plusieurs rôles égaux à ceux présents dans l'autorisation à assigner à l'objet ! A permission is referencing the object `%1' (%2) which was not found in the model! Une permission fait référence à l'objet `%1' (%2) qui n'a pas été trouvé dans le modèle ! The object `%1' (%2) can not be created because its not being assigned to any schema! L'objet `%1' (%2) ne peut pas être créé car il n'est affecté à aucun schéma ! The tablespace `%1' can not be inserted into the model because it points to the same directory as the tablespace `%2'! L'espace de stockage `%1' ne peut pas être inséré dans le modèle car il pointe sur le même répertoire que l'espace de table `%2' ! The function `%1' can not get a source code as a definition because its language is set to C. Use the attributes symbol and dynamic library instead! La fonction `%1' ne peut pas obtenir un code source en tant que définition car sa langue est définie sur C. Utilisez plutôt le symbole d'attributs et la bibliothèque dynamique ! The function `%1' can have the attributes symbol and dynamic library configured only if the language is set to C. For all other cases you must specify a source code that defines it in the DBMS! La fonction `%1' peut avoir le symbole des attributs et la bibliothèque dynamique configurés uniquement si la langue est définie sur C. Dans tous les autres cas, il faut spécifier un code source qui le définit dans le SGBD ! The operator `%1' can not be assigned as a comutator of operator `%2' because it has incompatible settings! L'opérateur `%1' ne peut pas être affecté en tant que commutateur de l'opérateur `%2'car il comporte des paramètres incompatibles ! The operator `%1' can not be assigned as negator of operator `%2' because it has incompatible settings! L'opérateur `%1' ne peut pas être affecté en tant que négateur de l'opérateur `%2' car il a des paramètres incompatibles ! The type `%1' can not self refer in the attributes `element' or `copy type' or be used as a data type of an attribute in the configuration of a composite type! Le type `%1' ne peut pas se référer à lui-même dans les attributs `element' ou `copy type' ou être utilisé comme type de données d'un attribut dans la configuration d'un type composite ! Assignment of invalid element to type `%1'! Affectation d'un élément invalide de type `%1' ! Assignment of invalid alignment to type `%1'! Affectation de l'alignement invalide de type `%1' ! The relationship `%1' can not make use of the special primary key because it is marked as identifier or it is a self relationship! La relation `%1' ne peut pas utiliser la clé primaire spéciale car elle est marquée comme identifiant ou c'est une association d'elle-même ! The object `%1' (%2) can not be edited or deleted because it was automatically included through a relationship! If the object is an attribute or constraint the modifications must be done on the relationship editing form. L'objet `%1' (%2) ne peut pas être modifié ou supprimé car il a été automatiquement inclus dans une association ! Si l'objet est un attribut ou une contrainte, les modifications doivent être effectuées sur le formulaire d'édition de la relation. The object `%1' (%2) can not be deleted because it is protected! L'objet `%1' (%2) ne peut pas être supprimé car il est protégé ! The group `%1' has already been declared earlier! Le groupe `%1' a déjà été déclaré ! The group `%1' can not be built in the groups declaration block (%2)! Le groupe `%1' ne peut pas être construit dans le bloc de déclaration de groupe (%2) ! The group `%1' was built but not declared in the groups declaration block (%2)! Le groupe `%1' a été construit mais pas déclaré dans le bloc de déclaration de groupe (%2) ! The group `%1' can not be built without possessing child elements! Le groupe `%1' ne peut pas être construit sans posséder d'éléments enfants ! The group `%1' can not be built once more because this was done in previous blocks! Le groupe `%1' ne peut pas être construit une fois de plus car cela a été fait dans les blocs précédents ! The group `%1' has been declared but not built! Le groupe `%1' a été déclaré mais pas construit ! The new configuration of the function invalidates the object `%1' (%2)! In this case it is needed to undo the relationship between the affected object and function in order to the new configuration to take effect! La nouvelle configuration de la fonction invalide l'objet `%1' (%2) ! Dans ce cas, il est nécessaire d'annuler la relation entre l'objet affecté et la fonction afin que la nouvelle configuration prenne effet ! Error while interpreting XML buffer at line %1 column %2. Message generated by the parser: %3. %4 Erreur lors de l'interprétation du tampon XML à la ligne %1, colonne %2. Message généré par l'analyseur : %3. %4 Attempt to start a connection already stablished! Tentative de lancement d'une connexion déjà établie ! Could not connect to the database. Message returned: `%1' Impossible de se connecter à la base de données. Message renvoyé : `%1' Unable to allocate command result for the SQL because the server has generated a fatal error! Message returned by the DBMS: `%1' Impossible d'allouer le résultat de la commande SQL car le serveur a généré une erreur fatale ! Message renvoyé par le SGBD : `%1' Reference to a column of a tuple which was not yet initialized (tuple navigation not started)! Référence à une colonne d'un tuple qui n'a pas encore été initialisé (navigation en tuple non démarrée) ! Could not execute the SQL command. Message returned: `%1' Impossible d'exécuter la commande SQL. Message renvoyé : `%1' It is not possible mix ordinary references (SELECT-FROM, FROM-WHERE, After WHERE) with references used as view SQL definition! Il n'est pas possible de mélanger des références ordinaires (SELECT-FROM, FROM-WHERE, Après WHERE) avec des références utilisées comme vue de définition SQL ! The object `%1' (%2) cannot reference itself! This operation is not permitted for this kind of object! L'objet `%1' (%2) ne peut pas se référencer lui-même ! Cette opération n'est pas autorisée pour ce genre d'objet ! Only operator families which uses `btree' as indexing method are accepted by operator class elements! Seules les familles d'opérateurs qui utilisent `btree 'comme méthode d'indexation sont acceptées par les éléments de classe d'opérateur ! Copy relationship between tables `%1' and `%2' cannot be done because the first one already copies attributes from `%3'! Tables can have only one copy table! L'association de copie entre les tables `%1' et `%2' ne peut pas être effectuée car la première copie déjà les attributs de `%3' ! Les tables ne peuvent avoir qu'une seule table de copie ! Assignment of a column which has no parent table to the object `%1' (%2)! Affectation d'une colonne qui n'a pas de table parent à l'objet `%1' (%2) ! The operator class assigned to the object `%1' (%2) must use `btree' as indexing method! La classe d'opérateur affectée à l'objet `%1' (%2) doit utiliser` btree' comme méthode d'indexation ! The extension `%1' is registered as a data type and cannot have the attribute `handles datatype' modified! L'extension `%1' est enregistrée en tant que type de données et ne peut pas avoir l'attribut `handle datatype' modifié ! The fk relationship `%1' cannot be created because the foreign-key that represents it was not created on table `%2'! L'association clé étrangère `%1' ne peut pas être créée car la clé étrangère qui la représente n'a pas été créée sur la table `%2' ! Assignement of an invalid object name pattern to the relationship `%1'! Affectation d'un modèle de nom d'objet invalide à la relation `%1' ! Reference to an invalid object name pattern id on the relationship `%1'! Référence à un identifiant de modèle de nom d'objet invalide sur la relation `%1' ! Mixing incompatibles DBMS export modes: `ignore object duplications', `drop database' or `drop objects' cannot be used with `simulate export'! Mélange incompatibles des modes d'export du SGBD : `ignore object duplications', `drop database' ou `drop objects' ne peuvent être utilisés avec `simulate export' ! Mixing incompatibles DROP options: `drop database' and `drop objects' cannot be used at the same time! Mixage incompatible des options DROP : `drop database' et `drop objects' ne peuvent pas être utilisés en même temps ! Invalid object id swapping operation! The objects involved are the same! Opération d'échange d'identifiant d'objet invalide ! Les objets impliqués sont les mêmes ! Invalid object id swapping operation! The database itself, tablespaces or roles cannot have the ids swapped! Opération d'échange d'identifiant d'objet invalide ! La base de données elle-même, les espaces de stockage ou les rôles ne peuvent pas échanger leurs identifiants ! The widget already has a parent and cannot be assigned to a different object! Le widget a déjà un parent et ne peut pas être assigné à un objet différent ! Could not load the database model file `%1'. Check the error stack to see details. Try to run `pgmodeler-cli --fix-model' in order to correct the structure of the file if that is the case. Impossible de charger le fichier de modèle de base de données `%1'. Vérifiez la pile d'erreurs pour plus de détails. Essayez d'exécuter `pgmodeler-cli --fix-model' afin de corriger la structure du fichier si besoin. The column `%1' cannot reference it's parent table `%2' as data type! La colonne `%1' ne peut pas référencer sa table parent `%2' comme type de données ! Operation with an invalid element id `%1'! Opération avec un identifiant d'élément invalide `%1' ! Reference to an invalid color id `%1' for element `%2'! Référence à un identifiant de couleur invalide `%1' pour l'élément `%2' ! The sequence `%1' can't be assigned to the column `%2' because the data type of the latter is incompatible. The type used must be an integer one! La séquence `%1' ne peut pas être affectée à la colonne `%2' car le type de données de cette dernière est incompatible. Le type utilisé doit être un entier ! The option to generate temporary object names can only be used in simulation mode! L'option de génération de noms d'objets temporaires ne peut être utilisée qu'en mode simulation ! Could not assign the variable `%1' to event trigger's filter. Currently, PostgreSQL supports only the `TAG' variable! Impossible d'affecter la variable `%1 'au filtre du déclencheur d'événement. Actuellement, PostgreSQL supporte uniquement la variable `TAG' ! Malformed unescaped value on row `%1' column `%2'! Valeur non echappée malformée à la ligne `%1', colonne `%2' ! The object `%1' (%2) can't be handled because some needed fields are not set! Please, make sure to fill at least the requires fields in order to properly create or update the object. L'objet `%1' (%2) ne peut pas être manipulé car certains champs nécessaires ne sont pas définis ! Merci de vous assurer de remplir au moins les champs requis afin de créer ou de mettre à jour correctement l'objet. A relationship can only be swapped by other object of the same kind! Une association ne peut être permutée que par un autre objet du même genre ! Assignment of a null type to object `%1' (%2)! Affectation d'un type nul à l'objet `%1' (%2) ! Unable to create the generalization relationship because the constraint `%1' in table `%2' can not be merged with the constraint `%3' of table `%4' due to their incompatible composition! Impossible de créer l'association de généralisation car la contrainte `%1' de la table `%2' ne peut pas être fusionnée avec la contrainte `%3' de la table `%4' en raison de leurs compositions incompatibles ! Unable to write the file `%1' due to one or more errors in the definition generation process! Impossible d'écrire le fichier `%1' en raison d'une ou de plusieurs erreurs dans le processus de génération de définition ! The configuration of the relationship `%1' generates a redundancy between the relationships `%2'. Redundancy on identifier or generalization/copy relationships are not accepted since they result in incorrect column spreading making the model inconsistent! La configuration de la relation `%1' génère une redondance entre les associations `%2 . La redondance sur l'identificateur ou les relations de généralisation/copie de l'association ne sont pas acceptées car elles entraînent une répartition incorrecte des colonnes, ce qui rend le modèle incohérent ! Invalid syntax in file `%1', line %2, column %3! Syntaxe non valide dans le fichier `%1', ligne %2, colonne %3! Invalid instruction `%1' on file `%2', line %3, column %4! Instruction invalide `%1' dans le fichier `%2', ligne `%3', colonne `%4' ! Unknown attribute `%1' in file `%2', line %3, column %4! Attribut inconnu `%1' dans le fichier `%2', ligne `%3', colonne `%4' ! Invalid metacharacter `%1' in file `%2', line %3, column %4! Métacaractère invalide `%1' dans le fichier `%2', ligne `%3', colonne `%4' ! Invalid operator `%1' in comparison expression, file `%2', line %3, column %4! Opérateur invalide `%1' dans l'expression de comparaison, fichier `%2', ligne`%3', colonne `%4' ! Attribute `%1' with an undefined value in file `%2', line %3, column %4! L'attribut `%1' a une valeur non définie dans le fichier `%2', ligne`%3', colonne `%4' ! Attribute `%1' with an invalid name in file `%2', line %3, column %4! L'attribut `%1' a un nom invalide dans le fichier `%2', ligne`%3', colonne `%4' ! Could not access the file or directory `%1'! Make sure that it exists or if the user has access permissions on it! Impossible d'acceder au fichier ou fossier `%1' ! Vérifiez qu'il existe et que l'utilisateur à les droits d'écritures ! Could not load file `%1'. The same appears to be inconsistent or one of its dependencies (DTD files) has errors or is missing! Impossible de charger le fichier `%1'. La même chose semble être incohérente ou l'une de ses dépendances (fichiers DTD) a des erreurs ou est manquante ! Reference to a tuple with an invalid index or the result is empty (no tuples)! Référence à un tuple avec un index invalide ou le résultat est vide (pas de tuple) ! Invalid use of a view reference as whole SQL definition! The assigned reference must be an expression! Utilisation invalide d'une référence de vue comme définition SQL entière ! La référence affectée doit être une expression ! At the moment pgModeler does not support the creation of primary keys which some columns were generated by relationship connection. To create primary keys with this feature you can use the field `Identifier' or the tab `Primary key' on relationship editing form! Actuellement pgModeler ne supporte pas la création de clés primaires dont certaines colonnes ont été générées par la connection d'associations. Pour créer des clés primaires avec cette fonctionnalité, vous pouvez utiliser le champ `Identifier' ou l'onglet `Primary key' sur le formulaire d'édition de relation ! Reference to a function id which is incompatible with the user define type configuration! Référence à un identifiant de fonction incompatible avec la configuration du type de définition de l'utilisateur ! Unsupported PostgreSQL version (%1) detected! Valid versions are between %2 and %3. Version PostgreSQL non prise en charge (%1) détectée! Les versions valides sont comprises entre %2 et %3. Invalid use of variadic parameter mode! This mode can be used only with an array or "any" data type! Utilisation invalide du mode paramètre variadique ! Ce mode ne peut être utilisé qu'avec un tableau ou un type de données "any" ! The object `%1' (%2), oid `%3', could not be imported due to one or more errors! Check the exception stack for more details. `HINT:' if the object somehow references objects in `pg_catalog' or `information_schema' consider enable the importing of system objects. L'objet `%1 '(%2), oid `%3', n'a pu être importé en raison d'au moins une erreur ! Vérifiez la pile d'exceptions pour plus de détails. `REMARQUE : 'Si l'objet référence d'une manière ou d'une autre les objets dans` pg_catalog' ou `information_schema ', envisagez d'importer les objets système. Assignment of an invalid object to `%1' (%2)! The assigned object must be of type `%3'. Affectation d'un objet invalide à `%1' (%2) ! L'objet affecté doit être de type `%3'. It's not possible convert the type of the column `%1' to serial! It must have an `integer' based type and its default value must be a call to `nextval(seq_name::regclass)' function or a sequence object must be directly assigned to the column! Il n'est pas possible de convertir le type de la colonne `%1' en série ! Il doit avoir un type basé sur `integer' et sa valeur par défaut doit être un appel à la fonction `nextval (seq_name::regclass)' ou un objet séquence doit être directement assigné à la colonne ! Could not perform the `%1' operation on `%2' using the data on row `%3'! All changes were rolled back. ** Returned error ** %4 Impossible d'exécuter l'opération `%1 'sur `%2' en utilisant les données de la ligne `%3 '! Tous les changements ont été annulés. ** Erreur retournée ** %4 Trying to undo/redo an invalid operation over an object that does not exists anymore or can't be handled! The operation history will be cleaned up. Tentative d'annulation/de rétablissement d'une opération invalide sur un objet qui n'existe plus ou ne peut plus être géré ! L'historique des opérations sera nettoyé. A parent table of `%1' which OID is `%2' was not found in the set of imported objects! Une table parente de `%1' dont l'OID est `%2' n'a pas été trouvée dans l'ensemble des objets importés ! The enumeration `%1' can't be assigned to the type `%2' because contains invalid characters! L'énumération `%1' ne peut pas être affectée au type `%2' car elle contient des caractères non valides ! The enumeration `%1' can't be assigned to the type `%2' because is too long! L'énumération `%1' ne peut pas être affectée au type `%2' car elle est trop longue ! The connection was idle for too long and was automatically closed! La connexion était inactive depuis trop longtemps et a été automatiquement fermée ! The connection was unexpectedly closed by the database server `%1' at port `%2'! La connexion a été fermée de manière inattendue par le serveur de la base de données `%1' sur le port `%2' ! ExtensionWidget Version: Version : Old Version: Ancienne version : This attribute cannot be changed once the object is created. Cet attribut ne peut être modifié une fois l'objet créé. Handles data type Gérer les types de données FindReplaceWidget Form Formulaire Hide this widget ... ... Replace one occurrence Remplace une occurrence Replace Remplacer Replace all occurrences Remplace toutes les occurrences Replace All Remplacer tout Replace the selection and find the next one Remplacer l'occurrence courante et trouver le suivant Replace && Find Remplacer && Suivant Replace: Remplacer par : Find: Recherche : Find previous Précédent Shift+F3 Maj+F3 Find next Suivant F3 F3 Case sensitive Respecter la casse Regular expression Expression régulière Whole words Mots entier FunctionWidget Attributes Attributs Function Type: Type de fonction : Execution Cost: Coût d'exécution : Rows Returned: Lignes retournées : Behavior: Comportement : Security: Sécurité : Return Method: Type de retour : Set Multiple Return Table Table de retour Windown Func. Fonct. fenêtrage. Leakproof Leakproof Parameters Arguments Definition Définition Dynamic Library: Bibliothèque dynamique : Symbol: Symbole : Library: Bibliothèque : Source code: Code source : Column Colonne Type Name Nom Mode Default Value Valeur par défaut Si&mple Si&mple Tab&le Tab&le Language: Langage : GeneralConfigWidget Form Formulaire Milimeters Millimètres Pixels Pixels Inches Pouces Centimeter Centimètres A0 (841 x 1189 mm) A0 (841 x 1189 mm) General && Design Général && modélisation Check if there is a new version on server Vérifier la présence d'une nouvelle version au lancement Design Modélisation Graphical objects (table, views and textboxes) will be created in a single step without the need to click on canvas Les objets graphiques (tables, vues, zones de textes) seront créés en une seule étape sans avoir besoin de cliquer sur le canevas. Simplify creation of graphical objects Créer les nouveaux objets en un clic After loading the model the last zoom and position on canvas will be restored Après le chargement du modèle, le dernier zoom et la position du canevas seront restaurés. Save and restore last position and zoom Sauvegarder la position et le zoom Disable render smoothness Désactiver l'anticrénelage Hide the object that represents the relationship name Masque l'étiquette indiquant le nom de chaque association. Validate before save, export or diff Validation du modèle toujours requise Hide the object which represents the tag assigned to the table Masquer l'objet qui représente la balise affectée à la table. Hide the portion of table which represent triggers, indexes and rules Masque les règles, les déclencheurs et les index dans l'affichage des tables. Enable SQL code completion Activer la complétion du code SQL Printing && Code Impression && édition Size: Taille : pt pt Font: Police : Hide relationship name Masquer le nom des associations Hide table extended attributes Masquer les attributs étendus des tables Paper: Papier : Orientation: Orientation : General Général Operation history: Historique des opérations : Hide table tags Masquer les balises des tables Printing Impression Options: Options : Print grid Imprimer la grille A1 (594 x 841 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) B0 (1030 x 1456 mm) B1 (728 x 1030 mm) B10 (32 x 45 mm) B2 (515 x 728 mm) B3 (364 x 515 mm) B4 (257 x 364 mm) B5 (182 x 257 mm) B6 (128 x 182 mm) B7 (91 x 128 mm) B8 (64 x 91 mm) B9 (45 x 64 mm) C5E (163 x 229 mm) Comm10E (105 x 241 mm) DLE (110 x 220 mm) Executive (191 x 254 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Legal (216 x 356 mm) Letter (216 x 279 mm) Tabloid (279 x 432 mm) Custom Personnalisé Unity: Unité : Custom Size: Taille papier : Width: Largeur : Height: Hauteur : Page Margins: Marges : Left: Gauche : Left margin Marge de gauche Top: Haut : Top margin Marge du haut Right: Droite : Right margin Marge de droite Bottom: Bas : Bottom margin Marge du bas Landscape Paysage Portrait Portrait Print page numbers Imprimer les numéros de page Start move the canvas when the cursor is on the canvas edges Commencer à déplacer le canevas lorsque le curseur se trouve sur les bords de celui-ci. Move canvas by keep mouse on corners Déplacer le canevas en gardant la souris sur les coins Disable antialiasing for lines and texts improving performance when handling huge models. Désactiver l'antialiasing pour les lignes et les textes améliore les performances lors de la manipulation d'énormes modèles. Triggers a dialog asking the user to validate the model before a save, export or diff operation. Déclenche une boîte de dialogue demandant à l'utilisateur de valider le modèle avant une opération de sauvegarde, d'export ou de comparaison. When enabled this option creates a placeholder object at the previous table's position when starting to move it. This will cause graphical updates on relationship lines to be performed only when the drag & drop action is done improving the performance. Disabling placeholders will cause those updates to be executed every time the table's position changes a single pixel (classical behavior). Lorsqu'elle est activée, cette option crée un objet réservé à la position de la table précédente lorsque vous commencez à la déplacer. Afin d'améliorer les performances, la mise à jour graphique sur les lignes associées ne se fera uniquement qu'une fois l'action de glisser-déposer términée. La désactivation des espaces réservés entraîne l'exécution de ces mises à jour chaque fois que la position de la table change d'un seul pixel (comportement classique). Use placeholders when moving tables Utiliser des espaces réservés lors du déplacement de tables Toggles the code completion in all fields that accepts the input of SQL commands. (Dés)active l'achèvement du code dans tous les champs qui acceptent les commandes SQL en entrée. Code style Style du code Colors: Couleurs : Display line numbers Afficher les numéros de ligne Highlight lines at cursor's position Surligner les lignes à la position du curseur Custom tab width: Largeur d'onglet personnalisé : Line numbers' font color Couleur de la police des numéros de ligne Line numbers' background color Couleur d'arrière-plan des numéros de ligne Highlighted line color Couleur de la ligne en surbrillance The little brown fox jumps over the lazy dog Le petit renard brun saute par-dessus le chien paresseux System default Défaillance du système All files (*.*) Tous les fichiers (*.*) Load file Charger un fichier Minimum object opacity (%): Opacité min. des objets (%) : Defines the minimum opacity percentage applied to the objects when using the fade out feature. A zero opacity causes the object to be completely hidden not being possible to interact with it in the canvas area. Définit le pourcentage d'opacité minimum appliqué aux objets lorsqu'ils sont estompés. Une opacité nulle cache complètement l'objet sans qu'il soit possible d'interagir avec lui dans la zone de canevas. Canvas grid size: Taille de grille du canevas : Defines the vertical and horizontal grid size. This value affects the spacing of objects when using object grid alignment feature. Définit la taille de la grille verticale et horizontale. Cette valeur affecte l'espacement des objets lors de l'utilisation de la fonction d'alignement des objets sur la grille. By default the range selection is triggered with Shift + left click. By checking this option range selection will be activated only with a single click and move. Par défaut, la sélection de plage est déclenchée avec Maj + clic gauche. En cochant cette option, la sélection de la gamme sera activée qu'en un seul clic et se déplacera. Trigger range selection with a single click Déclenchement de la sélection en un clic Defines the maximum amount of elements held in the operation history. Once reached the maximum number the history is automatically cleaned. Définit le nombre maximal d'éléments contenus dans l'historique des opérations. Une fois le nombre maximum atteint, l'historique est automatiquement nettoyé. Defines the period when the opened models will be saved automatically. Définit la période (en minute) d'enregistrement automatique des modèles ouverts. Autosave interval (minutes): Intervalle sauv. auto : Replaces any straight line in relationship by curved ones in order to improve the model's visualization. Remplace les lignes droites des relations par des courbes pour améliorer la lisibilité du modèle. Use curved lines for relationships Utiliser des lignes courbes pour les associations SQL history max. length: Longueur max. de l'historique SQL : Souce code editor: Éditeur de code source : lines lignes Clear the entire SQL comand history. Nettoyer complètement l'historique des commandes SQL. Clear history Nettoyer l'historique Configurations directory: Dossier de configuration : Browse the source code editor application Rechercher l'éditeur de code source Open in file manager Ouvrir dans le gestionnaire de fichier Check updates at startup Vérifier MAJ au démarrage Souce code editor args: Arg. pour l'éditeur de code source : User interface language: Langue de l'interface graphique : Overrides the default user interface language defined by the system. Requires restarting the program. <strong>NOTE:</strong> UI translations are third party collaborations thus any typo or mistake should be reported directly to their respective maintainers. Remplace la langue de l'interface utilisateur définie par défaut par le système. Nécessite de redémarrer le programme. <strong>REMARQUE :</strong> les traductions de l'interface utilisateur sont des collaborations avec des tiers; par conséquent, toute faute de frappe ou erreur doit être signalée directement à leurs responsables respectifs. GenericSQLWidget SQL code Code SQL HintTextWidget Form Formulaire IndexWidget Attributes Attributs Indexing: Indexation : Fill Factor: Taux de remplissage : Options: Options : Concurrent Concurrent Unique Unique Fast update Mise à jour rapide Elements Éléments Buffering Mémoire tampon Predicate: Prédicat : LanguageWidget Trusted: De confiance : The functions to be assigned to the language should have, respectively, the following signatures:<br/><br/> <strong>Handler Function:</strong> <em>language_handler function()</em><br/> <strong>Validator Function:</strong> <em>void function(oid)</em><br/> <strong>Inline Function:</strong> <em>void function(internal)</em> Les fonctions attribuées au langage doivent avoir respectivement les signatures suivantes :<br/><br/> <strong>Fonction de gestion :</strong> <em>language_handler function()</em><br/> <strong>Fonction de validation :</strong> <em>void function(oid)</em><br/> <strong>Fonction sur une ligne :</strong> <em>void function(internal)</em> Validator Func.: Fonc. de validation : Handler Func.: Fonc. gestionnaire : Inline Func.: Fonc. en ligne : MainWindow pgModeler - PostgreSQL Database Modeler pgModeler – Modeleur de bases de données PostgreSQL &Validation Alt+V Ctrl+F Alt+O Alt+B &File &Fichier &Edit Édit&ion &Show &Affichage Plugins Extensions New Nouveau Controls Contrôles General Général Ctrl+N Ctrl+N Ctrl+S Ctrl+S Zoom in Zoom + Ctrl+= Ctrl+= Zoom out Zoom - Zoom - Zoom - Ctrl+- Ctrl+- Ctrl+O Ctrl+O Ctrl+Q Ctrl+Q Export the current opened model in different modes Exporter le modèle courant sous différentes formes Close current model Fermer le modèle courant Ctrl+H Ctrl+H Edit pgModeler settings Configurer pgModeler F10 F10 Access the list of loaded plugins Accéder à la liste des extensions chargées Load recently opened model Charger des modèles ouverts récemment Import existing database to new model (reverse engineering) Importer une base de données existante vers un modèle (reverse engineering) Ctrl+Shift+I Ctrl+Maj+I New version found! Nouvelle version disponible ! Update for the current version is available on project's site Une mise à jour pour votre version est disponible sur le site de pgModeler Main menu Menu principal Show expanded Afficher la barre de menus Hide main menu Cacher la barre de menus Hides the main menu bar and put the action on a separated action Masque la barre de menu (le menu reste accessible via un bouton dans la barre d'outils) Ctrl+Shift+H Ctrl+Maj+H Welcome Accueil Welcome screen Écran d'accueil Design Modéliser Manage Administrer Manage existent databases Administrer des bases existantes O&bjects O&bjets &Operations &Opérations Find Object Chercher un objet Ctrl+Shift+S Ctrl+Maj+S Show grid Afficher la grille Align objects position to grid Aligner les objets sur la grille Show the page delimiters Afficher les délimiteurs de page Save all Tout enregistrer Show the model overview Afficher la vue d'ensemble du modèle Clear Menu Vider le menu The demonstration version can create only `one' instance of database model! La version de démonstration ne peut gérer qu'une seule instance de modèle de base de données ! Save model Enregistrer le modèle Warning Avertissement Save '%1' as... Enregistrer '%1' sous... Database model (*.dbm);;All files (*.*) Modèle de base de données (*.dbm);; Tous les fichiers (*.*) Database model printing Impression du modèle de base de données Save anyway Sauvegarder quand même Validate Valider Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. Des modifications ont été détectées dans les définitions du papier ou des marges du modèle ce qui pourrait causer une mauvaise impression des objets. Souhaitez-vous continuer l'impression avec les nouveaux paramètres ? Pour utiliser les paramètres par défaut cliquez sur 'Non' ou sur 'Annuler' pour interrompre l'impression. Load model Charger un modèle Could not load the database model file `%1'. Check the error stack to see details. You can try to fix it in order to make it loadable again. Impossible de charger le ficher modèle de base de données `%1'. Consultez la pile d'appel pour plus de détails. Essayez de réparer le modèle pour tenter de l'ouvrir à nouveau. Fix model Réparer un modèle Cancel Annuler This action will open a web browser window! Want to proceed? Cette action ouvrira votre navigateur web ! Souhaitez vous continuer ? Toggle the model objects widget (Dés)activer le widget des objets du modèle Toogle the model validation widgets (Dés)activer le widget de validation du modèle Toggle the operation history widget (Dés)activer le widget de l'historique des opérations Toggle the object finder (Dés)activer le chercheur d'objet action_main_menu action_menu_principal Expands the main menu bar in classical mode Développe la barre de menus principale en mode classique Saving temp. models Sauvegarde temp. des modèles Grid Grille Hierarchical Hiérarchique Scattered Dispersé (Demo) (Démo) You're running a demonstration version! The model saving feature is available only in the full version! Vous utilisez une version de démonstration ! La fonction d'enregistrement du modèle est uniquement disponible dans la version complète ! Confirmation <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! It's recommended to validate it before save in order to create a consistent model otherwise the generated file will be broken demanding manual fixes to be loadable again! <strong>AVERTISSEMENT :</strong> Le modèle <strong>%1</strong> n'a pas été validé ! Il est recommandé de le valider avant de l'enregistrer afin de créer un modèle cohérent, sinon il peut en résulter un fichier cassé nécessitant une réparation manuelle pour être chargé à nouveau chargeable ! <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the export process it's recommended to validate in order to correctly create the objects on database server! <strong>AVERTISSEMENT :</strong> Le modèle <strong>%1</strong> n'a pas été validé ! Avant de procéder à un export il est recommandé de le valider afin de s'assurer de correctement créer les objets sur le serveur de base de données ! Export anyway Exporter quand même <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the diff process it's recommended to validate in order to correctly analyze and generate the difference between the model and a database! <strong>AVERTISSEMENT :</strong> Le modèle <strong>%1</strong> n'a pas été validé ! Avant de procéder à une comparaison il est recommandé de le valider afin de s'assurer que l'analyse entre celui-ci de la base de donnée se fasse correctement ! Diff anyway Comparer quand même (no samples found) (aucun exemple trouvé) save sauvegarde export exporter diff comparer Executing pending <strong>%1</strong> operation... Exécution de l'opération <strong>%1</strong> en attente... Rearrange objects over the canvas is an irreversible operation! Would like to proceed? Réorganiser les objets sur le canvas est une opération irréversible ! Voulez-vous poursuivre ? He&lp Ai&de Pl&ugins Mod&ules &New &Nouveau New model Nouveau modèle &Save E&nregistrer &Zoom in &Zoomer Zoo&m out Dézoo&mer &Load C&harger Sa&ve as Enre&gistrer sous E&xit Qui&tter Exit pgModeler Quitter pgModeler &About pgModeler &À propos de pgModeler F4 &Print Im&primer Print model Imprimer le modèle Ctrl+P &Undo Ann&uler Undo operation Annuler l'opération Ctrl+Z &Redo &Rétablir Redo operation Rétablir l'opération Ctrl+Y &Export &Exporter Ctrl+Shift+E Ctrl+Maj+E &Show grid A&fficher la grille Ctrl+G &Close &Fermer Ctrl+W &Normal zoom Zoom &normal Ctrl+0 &Align to grid &Aligner sur la grille Show &delimiters Afficher les &délimiteurs Ctrl+L &Settings Paramètre&s F12 &Overview &Vue d'ensemble &Support Access the support page Accéder à la page du support F1 New object Nouvel objet &Recent Models Modèles &récents &Import &Importer Rest&ore Session Restaurer la sessi&on &Fix a model Réparer u&n modèle &Check for update Re&chercher une mise à jour &Diff &Comparer Ctrl+Shift+D Ctrl+Maj+D Shift+W Maj+W Design database models Conception de modèles de base de données Shift+D Maj+D Shift+M Maj+M &Bug report Rapport de &bug Report a bug Rapporter un bug Donate Faire un don Help pgModeler by donating! Aider pgModeler en faisant un don ! Objects me&tadata Mé&tadonnées des objets Objects metadata Métadonnées des objets Save modified model(s) Enregistrer le(s) modèle(s) modifié(s) The following models were modified but not saved: %1. Do you really want to quit pgModeler? Les modèles suivants ont été modifiés mais non enregistrés : %1. Voulez-vous vraiment quitter pgModeler ? The model <strong>%1</strong> was modified! Do you really want to close without save it? Le modèle <strong>%1</strong> a été modifié ! Êtes-vous certain de vouloir quitter sans l'enregistrer ? Access support page Accéder à la page de support You're running a demonstration version! Note that you'll be able to create only <strong>%1</strong> instances of each type of object and some key features will be disabled or limited!<br/><br/>You can purchase a full binary copy or get the source code at <a href='http://pgmodeler.com.br'>pgmodeler.com.br</a>. <strong>NOTE:</strong> pgModeler is an open source software, but purchasing binary copies or providing some donations will support the project and cover all development costs.<br/><br/> <strong>HINT:</strong> in order to test all features it's recommended to use the <strong>demo.dbm</strong> model located in </strong>Sample models</strong> at <strong>Welcome</strong> view.<br/><br/><br/><br/> Vous utilisez une version de démonstration ! Notez que vous ne pourrez créer que <strong>%1</strong> instances de chaque type d'objet et que certaines fonctionnalités clés seront désactivées ou limitées !<br/><br/>Vous pouvez acheter une copie binaire complète ou obtenir le code source sur <a href='http://pgmodeler.com.br'> pgmodeler.com.br </a>. <strong> REMARQUE :</strong> pgModeler est un logiciel open source, mais l'achat de copies binaires ou la fourniture de dons soutiendra le projet et couvrira tous les coûts de développement.<br/><br/> <strong>CONSEIL :</strong> Pour tester toutes les fonctionnalités, il est recommandé d'utiliser le modèle <strong>demo.dbm</strong> situé dans <strong>exemples de modèles</strong> dans la vue <strong>Bienvenue</strong>.<br/><br/><br/><br/><br/> Determine the changes between model/database and another database Déterminer les changements entre le modèle/la base de données et une autre base de données Arrange objects Organiser des objets Rearrange objects over the canvas Réorganiser les objets sur le canevas Messagebox Dialog Boîte de dialogue msg message Exceptions Exceptions Show/hide exceptions stack. Afficher/cacher la pile d'exceptions. ... ... &Yes &Oui &No &Non Information Confirmation Cancel Annuler Error Erreur Alert Alerte &Ok &Ok &Cancel A&nnuler Show raw text errors or information. Afficher le texte brute des erreurs ou des informations. MetadataHandlingForm Handle metadata Gérer les métadonnées &Apply &Appliquer &Cancel A&nnuler Handle objects metadata Gérer les métadonnées d'objets Settings Paramètres Extract from: Extraction depuis : Loading a metadata file to the current model is an irreversible operation so be sure to specify a backup file before proceed. Le chargement d'un fichier de métadonnées dans le modèle actuel est une opération irréversible, assurez-vous de spécifier un fichier de sauvegarde avant de continuer. Handles the following database model attributes in the metadata file: author, zoom factor, last position and default objects. Gère, dans le fichier de métadonnées, les attributs de modèle de base de données suivants : auteur, facteur de zoom, dernière position et objets par défaut. Database model metadata Métadonnées du modèle de base de données Handles the objects' positioning in the metadata file. Gère le positionnement des objets dans le fichier de métadonnées. Options Objects' positioning Positionnement des objets Handles the objects' custom colors in the metadata file. Currently available only for relationships and schemas. Gère les couleurs personnalisées des objets dans le fichier de métadonnées. Actuellement disponible uniquement pour les associations et les schémas. Custom object's colors Couleurs de l'objet personnalisé Handles the objects' protection status in the metadata file. Gère l'état de protection des objets dans le fichier de métadonnées. Objects' protection status Statut de protection des objets Handles the objects' SQL disabled status in the metadata file. Gère le statut désactivé du code SQL des objets dans le fichier de métadonnées. Objects' SQL disabled status Statut désactivé du code SQL des objets Handles the objects' custom SQL commands in the metadata file. Gère les commandes SQL personnalisées des objets dans le fichier de métadonnées. Custom SQL commands Commandes SQL personnalisées Textbox objects Objets de zone de texte Tag objects Balises des objets Backup file: Fichier de sauvegarde : Select file Sélectionner un fichier Apply to: Appliquer à : Operation: Opération : Output Sortie Progress label... Indicateur de progression... model not saved yet modèle pas encore enregistré The backup file cannot be the same as the input model! Le fichier de sauvegarde ne peut être le même que le modèle d'entrée ! Extracting metadata to file `%1' Extraction des métadonnées vers le fichier `%1' Saving backup metadata to file `%1' Enregistrement des métadonnées de sauvegarde vers le fichier `%1' Applying metadata from file `%1' Application des métadonnées depuis le fichier `%1' Metadata processing aborted! Traitement des métadonnées abandonné ! Objects metadata file (*.omf);;All files (*.*) Fichiers de métadonnées d'objets (*.omf);;Tous les fichiers (*.*) Handles the objects' fade out status in the metadata file. Gère l'estompement des objets dans le fichier de métadonnées. Objects' fade out status Effet d'estompement des objets Save tags to the output file when extracting metadata. When loading the file, the tags are recreated and duplicated ones are ignored. Enregistrer les étiquettes dans le fichier de sortie lors de l'extraction des métadonnées. Lors du chargement du fichier, les balises sont recréées et les doublons ignorés. Save textboxes to the output file when extracting metadata. When loading the file, the textboxes are recreated and duplicated ones are ignored. Enregistrer les zones de texte dans le fichier de sortie lors de l'extraction des métadonnées. Lors du chargement du fichier, les zones de texte sont recréées et les zones dupliquées ignorées. Handles the tables' and views' extended attributes display status in the metadata file. Gère l'état d'affichage des attributs étendus des tables et des vues dans le fichier de métadonnées. Tables' extended attributes display Affichage étendu des attributs des tables Save generic SQL objects to the output file when extracting metadata. When loading the file, the objects are recreated and duplicated ones are ignored. Enregistrer les objets SQL génériques dans le fichier de sortie lors de l'extraction des métadonnées. Lors du chargement du fichier, les objets sont recréés et les doublons ignorés. Generic SQL objects Objets SQL génériques ... Extracts the objects' metadata from the loaded models and apply to the current focused model. A backup file can be specified to where the focused model's current metadata will be saved. Extrait les métadonnées des objets des modèles chargés et s'applique au modèle ciblé actuel. L'emplacement du fichier de sauvegarde dans lequel les métadonnées actuelles du modèle ciblé seront enregistrées peut-être spécifié. &Extract and restore &Extraction et restauration Extracts the objects metadata from one of the loaded models saving the info to a backup file. Extrait les métadonnées d'objets de l'un des modèles chargés et enregistre les informations dans un fichier. Extract &only Extracti&on seule Reads the objects' metadata from a previously saved backup file and apply to the current model. Lit les métadonnées des objets à partir d'un fichier de sauvegarde précédemment enregistré et s'applique au modèle actuel. &Restore a backup file &Restaurer une sauvegarde ModelDatabaseDiffForm Settings Paramètres Connection: Connexion : Ignore import errors Ignorer les erreurs d'import Import system objects Importer les objets système Import extension objects Importer les objets des extensions File: Fichier : Select output file Sélectionner un fichier de sortie Cancel Annuler Progress label... Indicateur de progression... &Close &Fermer Waiting process to start... En attente du démarrage de la tâche... SQL code (*.sql);;All files (*.*) Code SQL (*.sql);;Tous les fichiers (*.*) Database: Base de données : For DROP command, the objects that depends on an object to be dropped will be deleted as well. For TRUNCATE command, tables that are linked to a table to be truncated will be truncate too. <strong>NOTE:</strong> this option can affect more objects than listed in the output or diff preview. Pour la commande DROP, les objets qui dépendent d'un objet à supprimer seront également supprimés. Pour la commande TRUNCATE, les tables liées à une table à tronquer seront également tronquées. <strong>REMARQUE :</strong> cette option peut affecter plus d'objets que ceux listés dans l'aperçu de sortie ou de comparaison. Drop or truncate in cascade mode Supprimer ou tronquer en mode cascade Permissions already set on database objects will be kept.The ones configured on the model will be applied to the database. Les autorisations déjà définies sur les objets de la base de données seront conservées. Les données configurées sur le modèle seront appliquées à la base de données. Keep object's permissions Conserver les permissions des objets Database cluster level objects like roles and tablespaces will not be dropped. Les objets de niveau de cluster de base de données tels que les rôles et les espaces de stockage ne seront pas supprimés. Keep cluster objects Conserver les objets de cluster Recreate only unmodifiable objects Recréer uniquement des objets non modifiables Force recreation of objects Forcer la recréation d'objets Ignores errors generated by duplicated objects when exporting the diff to database. Ignore les erreurs générées par les objets dupliqués lors de l'export de la comparaison vers la base de données. Ignore duplicity errors Ignorer les erreurs de duplicité Serial columns are converted to integer and having the default value changed to <strong>nextval(sequence)</strong> function call. By default, a new sequence is created for each serial column but checking this option sequences matching the name on column's default value will be reused and will not be dropped. Les colonnes de séries sont converties en nombre entier et la valeur par défaut est changée en appel de fonction <strong>nextval(sequence)</strong>. Par défaut, une nouvelle séquence est créée pour chaque colonne série, mais en cochant cette option, les séquences correspondantes au nom de la valeur par défaut de la colonne seront réutilisées et ne seront pas supprimées. Reuse sequences on serial columns Réutiliser des séquences sur des colonnes de séries Diff mode Mode comparaison Override the PostgreSQL version when generating the diff. The default is to use the same version as the input database. Outrepasser la version de PostgreSQL lors de la génération de la comparaison. Par défaut, la valeur est celle de la version de la base de données. Use PostgreSQL: Utiliser PostgreSQL : Compares the model and the input database storing the diff in a SQL file for later usage. Compare le modèle avec la base de données d'entrée et stock le résultat dans un fichier SQL pour une utilisation ultérieure. ... Compares the model and the input database generating a diff and applying it directly to the latter. <strong>WARNING:</strong> this mode causes irreversible changes on the database and in case of failure the original structure is not restored, so make sure to have a backup before proceed. Compare le modèle et la base de données d'entrée générant un résultat qui est appliqué directement à cette dernière. <strong>AVERTISSEMENT :</strong> ce mode entraîne des modifications irréversibles sur la base de données et, en cas d'échec, la structure d'origine n'est pas restaurée. Assurez-vous donc d'avoir une sauvegarde avant de continuer. Output Sortie Changes: Modifications : Step label... Étiquette étape... <html><head/><body><p>Objects marked with an <span style=" font-weight:600;">ALTER</span> may not be effectively changed unless that the differences detected are in attributes that can be modified through ALTER commands otherwise no operationwill be performed or, if the force recreation is checked, the object will be dropped and created again.</p></body></html> <html><head/><body><p>Les objets marqués d'un <span style="font-weight : 600;">ALTER</span> ne peuvent être modifiés efficacement que si les différences détectées sont dans les attributs qui peuvent être modifié à l'aide des commandes ALTER. Dans le cas contraire, aucune opération ne sera effectuée ou, si la recréation de force est vérifiée, l'objet sera supprimé et créé à nouveau.</p></body></html> Objects to be created Objets à créer 0 Objects to be dropped Objets à supprimer Possible objects to be changed Objets possiblement modifiables Ignored objects (system ones or with sql disabled) Objets ignorés (ceux du système ou avec code SQL désactivé) Diff Preview Aperçu de la comparaison &Apply diff &Appliquer la comparaison &Generate &Générer <strong>WARNING:</strong> The generated diff is ready to be exported! Once started this process will cause irreversible changes on the database. Do you really want to proceed? <strong>AVERTISSEMENT :</strong> La comparaison générée est prête à être exportée ! Une fois démarré, ce processus entraînera des changements irréversibles dans la base de données. Voulez-vous vraiment poursuivre ? Apply diff Appliquer la comparaison Preview diff Aperçu de la comparaison model not saved yet modèle pas encore enregistré (none) (aucun) Step %1/%2: Importing database <strong>%3</strong>... Étape %1/%2 : Import de la base de données <strong>%3</strong>... Step %1/%2: Comparing <strong>%3</strong> and <strong>%4</strong>... Étape %1/%2 : Comparaison de <strong>%3</strong> et de <strong>%4</strong>... Confirmation Step %1/%2: Exporting diff to database <strong>%3</strong>... Étape %1/%2 : Export de la comparaison de la base de données <strong>%3</strong>... Diff process paused. Waiting user action... Comparaison mise en pause. En attente d'une action utilisateur... Saving diff to file <strong>%1</strong> Enregistrement de la comparaison vers le fichier <strong>%1</strong> Diff process sucessfully ended! Comparaison términée avec succès ! No operations left. Aucune opération restante. Operation cancelled by the user. Opération annulée par l'utilisateur. Process aborted due to errors! Processus abandonné en raison d'erreurs ! -- No differences were detected between model and database. -- -- Aucune différence détectée entre le modèle et la base de données. -- Error code <strong>%1</strong> found and ignored. Proceeding with export. Code erreur <strong>%1</strong> reçu et ignoré. Poursuite de l'export. Save diff as... Enregistrer la comparaison sous... Ignores as many as possible errors on import step. This option generates an incomplete diff. Ignore autant d'erreurs que possible sur l'étape de l'import. Cette option génère une comparaison incomplète. Clears the data of all tables which will have columns modified. This is useful to avoid errors related to type casting. <strong>WARNING:</strong> DO NOT use this option on production servers and always make a backup before use it. Efface les données de toutes les tables qui auront des colonnes modifiées. Ceci est utile pour éviter les erreurs liées à la conversion de type. <strong>AVERTISSEMENT :</strong> N'utilisez PAS cette option sur les serveurs de production et faites toujours une sauvegarde avant de l'utiliser. Import system (built-in) objects. Use this if the import step is returning errors related to missing objects. Importer des objets système (intégrés). Utiliser cette option si l'étape d'import renvoie des erreurs liées à des objets manquants. Import objects created by extensions. Use this if the import step is returning errors even importing built in ones. Importer des objets créés par des extensions. Utiliser cette option si l'étape d'import renvoie des erreurs, même si celles-ci sont importées. Instead of use an ALTER command to modify certain kind of objects a DROP and CREATE will be used in order to do a full modification. This option does not affects the database object. Au lieu d'utiliser une commande ALTER pour modifier certains types d'objets, un DROP et un CREATE seront utilisés pour effectuer une modification complète. Cette option n'affecte pas l'objet de base de données. No command to rename the destination database will be generated even the model's name differ from database name. Aucune commande permettant de renommer la base de données de destination ne sera générée même si le nom du modèle diffère du nom de la base de données. Preserve database name Conserver le nom de la base de données Avoid the generation of DROP commands for objects that exists in database but not in the model. This is useful when diff a partial model against the complete database. Éviter la génération de commandes DROP pour les objets qui existent dans la base de données mais pas dans le modèle. Ceci est utile lorsque un modèle partiel a été comparé à la base de données complète. Do not drop missing objects Ne pas supprimer les objets manquants Store in S&QL file Stocker dans un fichier S&QL Appl&y on server Appliquer sur le serveur -- SQL code purposely truncated at this point in demo version! -- Le code SQL est volontairement tronqué à ce stade dans la version démo ! Diff tool Outil de comparaison Generate diff code Générer un code de comparaison Source database Base de données source Current model: Modèle courant : (model) (modèle) Compare to Comparer à Diff Comparaison Import && Export Import && Export Import Export This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Cette option avancée oblige pgModeler à ignorer les erreurs supplémentaires par leurs codes numériques. Ces erreurs doivent être renseignées dans l'entrée ci-dessous et séparées par des espaces. Pour la liste complète des codes d'erreur, consulter les documents PostgreSQL, section <strong>Annexe A. Codes d'erreur PostgreSQL</strong>. <strong>AVERTISSEMENT :</strong> utiliser cette option avec un soin extrême, car elle peut interférer dans le résultat de l'export finale. Ignore error codes Ignorer les codes d'erreur Froce the generation of DROP commands for columns and constraints that exist in database but not in the model. This is useful when diff a partial model against the complete database and the user needs to drop columns and constraint but preserve the rest of the objects. Forcer la génération de commandes DROP pour les colonnes et les contraintes qui existent dans la base de données mais pas dans le modèle. Ceci est utile lorsqu'un modèle partiel est comparé à la base de données complète et que l'utilisateur doit supprimer les colonnes ainsi que les contraintes mais conserver les autres objets. Drop missing columns and constraints Supprimer colonnes/contraintes manquantes Truncate tables before alter columns Tronquer les tables avant de modifier les colonnes ModelExportForm File: Fichier : Select target file Sélectionner le fichier cible ... ... Zoom: Zoom : Export model Export d'un modèle Settings Paramètres Database server Serveur de base de données pgModeler ignores errors generated by duplicated objects and creates only that ones which does not exists in the database. This option may be used when an object was created after a previous model export. pgModeler ignorera les erreurs générées en raison d'objets dupliqués et ne créera uniquement ceux qui n'existent pas déjà en base. Cette option peut être utile lorsqu'un objet est créé après un précédent export. PostgreSQL version in which the SQL code should be generated. It is recommended to select this option only when the version of the DBMS, somehow, is not identifiable or if you need to generate a specific version of SQL code for test purposes. Version de PostgreSQL pour laquelle le code SQL sera généré. Il est recommandé d'activer cette option uniquement si la version du SGBD n'est pas identifiable ou pour une raison spécifique par exemple pour des essais. If <strong>DB</strong> is checked pgModeler will destroy the database if already exists on the server. When <strong>Objects</strong> is checked pgModeler will execute the DROP command attached to SQL-enabled objects. <strong>WARNING:</strong> this option leads to data loss so make sure to have a backup first. Si <strong>BDD</strong> est coché, pgModeler procédera à la suppression complète de la base de données si elle existe déjà. Lorsque <strong>Objets</strong> est coché pgModeler effectuera la commande DROP rattachée à l'objet (si la génération du code SQL pour cet objet n'a pas été désactivée dans ses propriétés). <strong>AVERTISSEMENT :</strong> cette option engendre la perte de données, pensez à faire une sauvegarde avant. Drop: Suppr. : DB BDD Show delimiters Afficher les délimiteurs de page Exporting the model page by page will generate files with a <strong>_p[n]</strong> suffix where <strong>n</strong> is the page id. Check if the current user has write permission on output folder. Exporter le modèle page par page générera des fichiers avec un suffixe de type <strong>_p[n]</strong> où <strong>n</strong> est le numéro de la page. Vérifiez que vous avez bien le droit d'écriture dans le dossier de sortie. Page by page Une image par page PostgreSQL: PostgreSQL : PostgreSQL version in which the SQL code should be generated Version de PostgreSQL pour laquelle le code SQL doit être généré Cancel Annuler pgModeler will destroy the database if already exists on the server. Make sure to have a backup before use this option because all data will be lost. pgModeler détruira la base de données si elle existe déjà sur le serveur. Assurez-vous d'avoir une sauvegarde si besoin avant car les données seront définitivement perdues. Show grid Afficher la grille Connection: Connexion : Ignore object duplicity Ignorer les objets dupliqués SQL file Fichier texte SQL I&mage (PNG) Output Progression Progress label... Indicateur de progression... &Export &Exporter &Close &Fermer Initializing model export... Initialisation de l'export du modèle... Saving file '%1' Enregistrement du fichier '%1' Exporting process aborted! Export abandonnée ! Exporting process canceled by user! Export annulée par l'utilisateur ! Exporting process sucessfuly ended! Export terminée avec succès ! Export model as... Exporter le modèle sous... Error code <strong>%1</strong> found and ignored. Proceeding with export. Code erreur <strong>%1</strong> reçu et ignoré. Poursuite de l'export. Ob&jects Ob&jets Graphics file Fichier graphique Type: Type : SQL script (*.sql);;All files (*.*) Script SQL (*.sql);;Tous les fichiers (*.*) Portable Network Graphics (*.png);;All files (*.*) Portable Network Graphics (*.png);;Tous les fichiers (*.*) Scalable Vector Graphics (*.svg);;All files (*.*) Scalable Vector Graphics (*.svg);;Tous les fichiers (*.*) This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Cette option avancée oblige pgModeler à ignorer les erreurs supplémentaires par leurs codes numériques. Ces erreurs doivent être renseignées dans l'entrée ci-dessous et séparées par des espaces. Pour la liste complète des codes d'erreur, consulter les documents PostgreSQL, section <strong>Annexe A. Codes d'erreur PostgreSQL</strong>. <strong>AVERTISSEMENT :</strong> utiliser cette option avec un soin extrême, car elle peut interférer dans le résultat de l'export finale. Ignore error codes Ignorer les codes d'erreur &Vectorial (SVG) &Vectoriel (SVG) ModelExportHelper Generating SQL code for PostgreSQL `%1' Génération du code SQL pour PostgreSQL `%1' Output SQL file `%1' successfully written. Fichier SQL de sortie `%1' écrit avec succès. Rendering objects to page %1/%2. Rendu des objets de la page %1/%2. Output image `%1' successfully written. Fichier image de sortie `%1' écrit avec succès. Starting export to DBMS. Lancement de l'export vers le SGBD. PostgreSQL version detection overridden. Using version `%1'. Détection de version dépassée de PostgreSQL. Utilisation de la version `%1'. PostgreSQL `%1' server detected. Serveur PostgreSQL `%1' détecté. Generating temporary names for database, roles and tablespaces. Génération de noms, de rôles et d'espace de stockage temporaires pour la base de données. Enabling the SQL code for database `%1' to avoid errors. Activation du code SQL de la base de données `%1' pour éviter les erreurs. Ignoring object duplication errors. Omission des erreurs de duplication d'objet. Ignoring the following error code(s): `%1'. Omission des codes erreur suivants : `%1'. Trying to drop database `%1'. Tentative de suppression de la base de données `%1'. Simulation mode activated. Mode simulation activé. Generating SQL for `%1' objects... Génération de code SQL pour `%1' objets... Destroying objects created on the server. Destruction des objets créés sur le server. Restoring original names of database, roles and tablespaces. Restauration des noms, des rôles et des espaces de stockage originaux de la base de données. Creating object `%1' (%2) Création de l'objet `%1' (%2) Dropping object `%1' (%2) Suppression de l'objet `%1' (%2) Changing object `%1' (%2) Modification de l'objet `%1' (%2) Running auxiliary command. Exécution de la commande auxiliaire. Exporting model to SVG file. Export du modèle vers un fichier SVG. SVG representation of database model Représentation SVG d'un modèle de base de données SVG file generated by pgModeler Fichier SVG généré par pgModeler Output file `%1' successfully written. Fichier de sortie `%1' écrit avec succès. Creating database `%1' Création de la base de données `%1' Connecting to database `%1' Connexion à la base de données `%1' Renaming `%1' (%2) to `%3' Renommage de `%1' (%2) en `%3' ModelFixForm Model file fix Réparer un fichier modèle &Fix &Réparer &Close &Fermer Fix model file Réparer un modèle <html><head/><body><p>[pgmodeler-cli not found error]</p></body></html> <html><head/><body><p>[pgmodeler-cli not found error]</p></body></html> pgmodeler-cli: pgmodeler-cli : Browse for pgmodeler-cli tool Rechercher l'outil pgmodeler-cli ... ... The specified file is not the pgModeler command line tool (pgmodeler-cli). Ce fichier n'est pas l'outil en ligne de commande de pgModeler (pgmodeler-cli). Input file: Fichier source : Output file: Fichier cible : Fix tries: Tentatives : Select input file Sélectionner le modèle à réparer Select output file Sélectionner un fichier de sortie Load fixed model when finish Charger le modèle réparé une fois l'opération terminée In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. <strong>NOTE:</strong> relationships may lost their graphical configuration like custom points and line color. Dans certains cas, le processus de réparation peut échouer à restaurer et récupérer tous les objets du modèle, ce qui peut réclamer des modifications manuelles dans le fichier à partir d'un éditeur de texte. <strong>REMARQUE :</strong> les associations peuvent perdre leur configuration graphique tels que des points placés manuellement par l'utilisateur ou la couleur. Waiting process to start... Processus en attente de lancement... Could not locate <strong>%1</strong> tool on <strong>%2</strong>. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below. Impossible de localiser l'outil <strong>%1</strong> sur <strong>%2</strong>. Le processus de réparation ne peut continuer ! Vérifiez votre installation de pgModeler ou spécifiez manuellement la commande ci-dessous. pgModeler command line tool (%1) Outil en ligne de commande de pgModeler (%1) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Waiting process to start...</span></p></body></html> < !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http ://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">En attente du lancement du processus...</span></p></body></html> ModelNavigationWidget Form Formulaire Previous model Modèle précédent Alt+C Next model Modèle suivant Close model Fermer ... ... (model not saved yet) (modèle pas encore enregistré) Ctrl+Left Ctrl+Gauche Ctrl+Right Ctrl+Droite ModelObjectsWidget Model Objects Objets du modèle Hide this widget Cacher ce widget 1 1 Object Objet Type Type Parent Object Objet parent Parent Type Type parent Select All Tout sélectionner Clear All Tout effacer Select Sélectionner Return Retour Cancel Annuler Esc Échap Objects view configuration Filtres d'affichage des objets Expands all items Développer tous les éléments Collapses all items Replier tous les éléments Filter: Filtrer : ... ... Tree view Vue en arbre List view Vue en liste New Nouveau ID Identifiant By ID Par identifiant Visible object types Types d'objets visibles Model objects Objets de modèle ModelOverviewWidget Model overview Vue générale du modèle Failed to generate the overview image. The requested size %1 x %2 was too big and there was not enough memory to allocate! Impossible de générer l'aperçu de l'image. La taille demandée%1 x%2 était trop grande et il n'y avait pas assez de mémoire à allouer ! ModelRestorationForm Model restoration Restauration de modèle &Restore &Restaurer &Cancel A&nnuler pgModeler was not closed properly in a previous execution and some models were still being edited. Click <strong>Restore</strong> to reopen the models or <strong>Cancel</strong> to abort the restoration. pgModeler n'a pas été fermé correctement lors d'une précédente exécution et certains modèles étaient encore en cours d'édition. Cliquez sur <strong>Restaurer</strong> pour rouvrir les modèles ou sur <strong>Annuler</strong> pour abandonner la restauration. pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler. pgModeler va essayer de récupérer les modèles sélectionnés mais ne les détruira pas en cas d'échec de chargement. Cette option sert de dernier recours pour essayer de récupérer le modèle de base de données. Les modèles temporaires resteront jusqu'à ce que l'application soit fermée. L'utilisateur doit donc essayer de récupérer manuellement les fichiers avant de quitter pgModeler. Keep temporary models in case of restoration failure Conserver les modèles temporaires en cas d'échec de la restauration Database Base de données File Fichier Modified Modifié Size Taille ModelValidationHelper There are pending errors! SQL validation will not be executed. Il y a des erreurs en attente ! La validation SQL ne sera pas exécutée. Operation canceled by the user. Opération annulée par l'utilisateur. ModelValidationWidget Form Formulaire 0 0 Try to apply a fix on the selected validation info. Essayer d'appliquer le correctif sur l’élément sélectionné. Clear validation results Effacer le résultat de la validation Va&lidate Va&lider Warnings: does not prevents model to be saved. Avertissements : n'empêche de pouvoir sauvegarder le modèle. Errors: model will not be saved while there are validation errors. Erreurs : le modèle ne peut être sauvegardé tant que des erreurs de validation subsistent. SQL Validation: Validation SQL : PostgreSQL version Version de PostgreSQL Try to resolve the reported issues. Essayer de résoudre les problèmes rencontrés. Ctrl+S Ctrl+S Clear Effacer Options Options Cancel the SQL validation in progress. Annuler le processus de validation SQL en cours. Cancel Annuler Esc Échap Apply fixes Change the creation order for two objects by swapping their ids Modifie l'ordre de création de deux objets en échangeant leurs numéros d'identification Swap ids Échanger identifiants Hide this widget Fermer ce widget ... ... The object <strong>%1</strong> <em>(%2)</em> [id: %3] is being referenced by <strong>%4</strong> object(s) before its creation. L'objet <strong>%1</strong> <em>(%2)</em> [id: %3] est référencé par <strong>%4</strong> objet(s) avant sa création. Autodetect Auto détection The object <strong>%1</strong> <em>(%2)</em> [id: %3]%4 is referencing columns created by <strong>%5</strong> relationship(s) but is created before them. L'objet <strong>%1</strong> <em>(%2)</em> [id : %3]%4 référence des colonnes créées par <strong>%5</strong> association(s) mais a été créé avant eux. The object <strong>%1</strong> <em>(%2)</em> has a name that conflicts with <strong>%3</strong> object's name(s). Le nom de l'objet <strong>%1</strong> <em>(%2)</em> entre en conflit avec celui de l'objet<strong>%3</strong>. Processing object: %1 Traitement de l'objet : %1 Conflicting object: <strong>%1</strong> <em>(%2)</em>. Objet en conflit : <strong>%1</strong> <em>(%2)</em>. Referrer object: <strong>%1</strong> <em>(%2)</em> [id: %3]. Objet réferent : <strong>%1</strong> <em>(%2)</em> [id: %3]. SQL validation failed due to error(s) below. <strong>NOTE:</strong><em> These errors does not invalidates the model but may affect operations like <strong>export</strong> and <strong>diff</strong>.</em> La validation SQL a échoué en raison des erreurs ci-dessous. <strong>REMARQUE :</strong><em> Ces erreurs n'invalident pas le modèle mais peuvent affecter des opérations telles que <strong>l'export</strong> et <strong>la comparaison</strong>. </em> The column <strong>%1</strong> on <strong>%2</strong> <em>(%3)</em> is referencing the geospatial data type <strong>%4</strong> but the <strong>postgis</strong> extension is not present in the model! <strong>HINT:</strong> Create the extension in the model or let it be created by applying the needed fixes. <em>The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!</em> <em>L'objet ci-dessus a été créé par une relation. Changer le motif du nom sur sa relation de générateur. La correction ne sera pas appliquée !</Em> Relationship: <strong>%1</strong> [id: %2]. Relation : <strong>%1</strong> [id : %2]. Running SQL commands on server... Exécution des commandes SQL sur le serveur... Enables the validation of SQL code in DBMS. This process requires the use of a pre-configured connection. SQL validation will occur only in the last step (when all objects were validated) or when there are no warnings. Active la validation du code SQL dans la SGBD. Ce processus nécessite l'utilisation d'une connexion pré-configurée. La validation SQL ne se produira qu'à la dernière étape (lorsque tous les objets ont été validés) ou lorsqu'il n'y a pas d'avertissement. Connection to be used in the SQL validation Connexion à utiliser dans la validation SQL pgModeler will generate unique and temporary names for database, role and tablespace objects. This option avoids object duplication errors when running the SQL validation. pgModeler générera des noms uniques et temporaires pour les objets base de données, rôle et espace de stockage. Cette option évite les erreurs de duplication d'objet lors de l'exécution de la validation SQL. Use unique temporary names for cluster level objects Utiliser des noms temporaires uniques pour les objets de niveau cluster The relationship <strong>%1</strong> [id: %2] is in a permanent invalidation state and needs to be relocated. La relation <strong>%1</strong> [id : %2] est dans un état d'invalidation permanent et a besoin d'être déplacé. <strong>HINT:</strong> try to swap the relationship by another ones that somehow are linked to it through generated columns or constraints to solve this issue. Note that other objects may be lost in the swap process. <strong>CONSEIL :</strong> essayer d'échanger la relation par une autre qui est liée à celle-ci via des colonnes générées ou des contraintes pour résoudre ce problème. Noter que d'autres objets peuvent être perdus dans le processus d'échange. SQL validation not executed! No connection defined. La validation SQL n'est pas exécutée ! Aucune connexion définie. Database model successfully validated. Modèle de base de données validé avec succès. ModelWidget Copy Copier Convert Convertir New Nouveau Quick Actions rapides Source code Code source Show object source code Afficher le code source de l'objet Properties Propriétés Space Espace Edit the object properties Modifier les propriétés de l'objet Protect Vérrouiller Unprotect Déverrouiller Protects object(s) from modifications Empêcher la modification du ou des objets Delete Effacer Shift+Del Shift+Suppr Select all Tout sélectionner Selects all the graphical objects in the model Sélectionner tous les objets graphiques du modèle Paste Coller Cut Couper Deps && Referrers Dépendances && Rèférences Add a new object in the model Ajouter un nouvel objet dans le modèle Rename Renommer Quick rename the object Renommage rapide de l'objet Move to schema Déplacer vers le schema Edit permissions Modifier les permissions Change owner Changer le propriétaire Select children Sélectionner les enfants Del Suppr Custom SQL Code SQL personnalisé Loading database model Ouverture du modèle de base de données Saving database model Enregistrement du modèle de base de données Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. Copier également les dépendences des objets sélectionnés ? Cela minimise la casse des références lorsque les objets copiés sont collés dans un autre modèle. Pasting objects... Collage des objets... Not all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! Tous les objets n'ont pas été collés dans le modèle car des erreurs ont été retournées durant le processus ! Se référer à la pile d'erreurs pour plus de détails ! Do you really want to delete the selected object? Souhaitez-vous réellement effacer l'objet sélectionné ? (no objects) (aucun objet) None Constraints Contraintes One to One (1-1) Un à un (1-1) One to Many (1-n) Un à plusieurs (1-n) Many to Many (n-n) Plusieurs à plusieurs (n-n) <strong>ATTENTION:</strong> The database model is protected! Operations that could modify it are disabled! <strong>ATTENTION :</strong> Le modèle de base de données est protégé ! Les opérations qui pourraient le modifier sont désactivées ! Edit data Modifier données Source Alt+S Del. cascade Supprimer en cascade Ctrl+C Ctrl+V Ctrl+X Quick action for the selected object Action rapide pour l'objet sélectionné F2 Set tag Affecter une balise Ctrl+E Select tagged Séléction balisée Select Sélectionner Open relationship Ouvrir les relations Alt+Q Convert to sequence Convertir en séquence Convert to serial Convertir en série Break line Ligne d'interruption Remove points Supprimer des points Enable SQL Activer le code SQL Disable SQL Désactiver le code SQL Duplicate Dupliquer Ctrl+D Extended attributes Attributs étendus Show Afficher Hide Masquer Jump to table Sauter à la table Schemas rectangles Rectangles de schémas Fade in/out Effets de fondu Fade in Accentuer Fade out Estomper Relationships Associations Swap ids Échanger identifiants Edit the objects creation order by swapping their ids Modifier l'ordre de création des objets en échangeant leurs identifiants 90° (vertical) 90° (horizontal) 90° + 90° (vertical) 90° + 90° (horizontal) All objects Tous les objets Schemas Schémas Views Vues Textboxes Boites de textes Tables Ctrl+A Zoom: %1% Zoom : %1% Do you really want to convert the relationship into an intermediate table? Voulez-vous vraiment convertir les relations en une table intermédiaire ? Validating object: `%1' (%2) Validation de l'objet : `%1' (%2) Generating XML for: `%1' (%2) Génération du code XML pour : `%1' (%2) Pasting object: `%1' (%2) Collage de l'objet : `%1' (%2) <strong>CAUTION:</strong> You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed? <strong>ATTENTION :</strong> Vous êtes sur le point de supprimer des objets en mode cascade, ce qui signifie que des objets non sélectionnés seront également supprimés. Voulez-vous vraiment poursuivre ? <strong>CAUTION:</strong> Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? <strong>ATTENTION :</strong> Supprimer plusieurs objets à la fois peut entraîner des invalidations irréversibles sur d'autres objets du modèle, entraînant également la suppression de ces objets invalides. Voulez-vous vraiment poursuivre ? <strong>CAUTION:</strong> Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? <strong>ATTENTION :</strong> Supprimer une relation peut entraîner des invalidations irréversibles d'autres objets dans le modèle, entraînant également la suppression de ces objets invalides. Voulez-vous vraiment poursuivre ? The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details. La suppression en cascade a rencontré des problèmes lors de son exécution ! Certains objets n'ont pas pu être supprimés ou enregistrés dans l'historique des opérations ! Veuillez vous reporter à la pile d'erreurs pour plus de détails. Inheritance Héritage Do you want to %1 the selected schema's children too? Voulez-vous %1 les enfants du schèma séléctionné aussi ? protect protéger unprotect déprotéger ModelsDiffHelper Processing object `%1' (%2)... Traitement de l'objet `%1' (%2)... Skipping object `%1' (%2)... Omission de l'objet `%1' (%2)... Processing diff infos... Comparaison des informations... Processing `%1' info for object `%2' (%3)... Traitement de l'info `%1' pour l'objet `%2' (%3)... No differences between the model and database. Aucune différence entre le modèle et la base de données. Preparing diff code... Préparation du code de comparaison... NewObjectOverlayWidget Form Formulaire Role Rôle Tag Tag Cast Conversion de type Language Langage Textbox Zone de texte Event Trigger Déclencheur sur évènement Tablespace Espace de stockage Schema Schéma Domain Domaine Conversion Conversion Extension Type Aggregate Agrégat Collation Sequence Séquence Table Function Fonction View Vue Permissions Index Rule Règle Column Colonne Constraint Contrainte Trigger Déclencheur Copy Copie A G K H J D E F L O U I R S Q T P M Y W 9 Z X C V B 8 1 2 3 5 4 0 Op. Family Famille d'op. Op. Class Classe d'op. Operator Opérateur Many-to-many Plusieurs-à-plusieurs One-to-many Un-à-plusieurs One-to-one Un-à-un Inheritance Héritage Generic SQL SQL générique Policy Politique NumberedTextEditor Load Charger Load the object's source code from an external file Charger le code source de l'objet depuis un fichier externe Edit Modifier Edit the source code in the preferred external editor Modifier le code source avec son éditeur préféré Clear Nettoyer Upper case Majuscule Lower case Minuscule Ident right Ident droit Ident left Ident gauche SQL file (*.sql);;All files (*.*) Fichier SQL (*.sql);;Tous les fichiers (*.*) Load file Charger un fichier The source editor `%1' is running on `pid: %2'. L'éditeur de source `%1' s'exécute sur pid : `%2'. Could not start the source code editor application `%1'! Make to sure that the source editor path defined in the general settings points to a valid executable and the current user has permission to run the application. Error message returned: `%2' Impossible de démarrer l'application de l'éditeur de code source `%1' ! Assurez-vous que le chemin de l'éditeur source défini dans les paramètres généraux pointe vers un exécutable valide et que l'utilisateur actuel a l'autorisation d'exécuter l'application. Message d'erreur renvoyé : `%2' ObjectDepsRefsWidget Dependencies Dépendances Object Objet Type Type Parent Object Objet parent Parent Type Type parent References Références ID ID Exclude indirect dependencies Exclure les dépendances indirectes Include indirect references Inclure les références indirectes This object does not exists anymore. The dependencies and references listing are disabled. Cet objet n'existe plus. L'affichage de ses dépendances et références est désactivé. Object's dependencies & references Dépendances et références d'un objet ObjectFinderWidget Form Formulaire Pattern: Motif : Hide this widget Cacher ce widget ... ... Find Chercher Clears the search results Effacer les résultats Clear Effacer (Un)selects the graphical objects in the results grid Regular Expression Expression régulières Exact Match Correspondance exacte Select All Tout sélectionner Clear All Tout effacer Case Sensitive Sensible à la casse Object Objet Type Type Parent Object Objet parent Parent Type Type parent Fades outs all the graphical objects in the results grid (or those not listed). The current fade in/out state of all objects is modified. Defines the search filter Défini le filtre de recherche Filter Filtrer Listed Not listed Found <strong>%1</strong> object(s). <strong>%1</strong> objet(s) trouvé(s). No objects found. Aucun objet trouvé. ID Identifiant Select Sélectionner Fade out Estomper ObjectRenameWidget Form Formulaire .... .... to: en : Rename Renommer Cancel Annuler ObjectSelectorWidget Form Formulaire Clear field Effacer le champ Select Object Sélectionner un objet Select %1 Sélectionner %1 ObjectsTableWidget Form Formulaire Add Item Ajouter un élément Ins Insérer Remove Item Supprimer un élément Del Suppr Update Item Actualiser l'élément Alt+R Remove All Tout supprimer Shift+Del Maj+Suppr. Duplicate item Dupliquer l'élément Ctrl+D Edit Item Modifier l'élément Space Espace Move Up Déplacer vers le haut Ctrl+Up Ctrl+Haut Move Down Déplacer vers le bas Ctrl+Down Ctrl+Bas Move to start Déplacer au début Ctrl+Home Ctrl+début Move to end Déplacer à la fin Ctrl+End, Ctrl+S Ctrl+Fin, Ctrl+S Do you really want to remove the selected item? Souhaitez-vous réellement supprimer l'élément sélectionné ? Confirmation Do you really want to remove all the items? Souhaitez-vous réellement supprimer tous les éléments ? OperationList (invalid object) (objet invalide) OperationListWidget Executed Operations Opérations exécutées Hide this widget Cacher ce widget ... ... 1 1 Operations: Opérations : 0 0 Position: Position : Delete operation history Supprimer l'historique des opérations Undo Annuler Redo Rétablir Object: %1 Objet : %1 Name: %1 Nom : %1 created créé removed supprimé modified modifié moved déplacé Operation: %1 Opération : %1 Operation history exclusion Exclure l'historique des opérations Delete the executed operations history is an irreversible action, do you want to continue? Effacer l'historique des opérations exécutées est une action irréversible, souhaitez-vous continuer ? OperatorClassWidget Default Class: Classe par défaut : Indexing: Indexation : Elements Éléments Element Type: Type d'élément : Operator Opérateur Function Fonction Storage Stockage Function: Fonction : Operator: Opérateur : Support/Strategy: Support/Stratégie : Op. Family: Famille d'opérateurs : Storage Type Type de Stockage Object Objet Type Support/Strategy Support/Stratégie Operator Family Famille d'opérateurs OperatorFamilyWidget Indexing: Indexation : OperatorWidget Options: Options : MERGES MERGES HASHES HASHES Arguments Arguments Advanced Avancé Restrict: Restriction : Commutator: Commutateur : Negator: Négateur : Operator Func.: Fonction de l'opérateur : Join: Jointure : Right Argument Type Type argument droit Left Argument Type Type d'argument gauche To create a unary operator it is necessary to specify as <strong><em>'any'</em></strong> one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator. Pour créer un opérateur unitaire, il est nécessaire de spécifier <strong><em>'any'</em></strong> comme l'un de ses arguments. De plus, la fonction qui définit l'opérateur doit avoir seulement un paramètre et celui-ci doit avoir le même type de donnée que l'argument de l'opérateur unitaire. ParameterWidget Default Value: Valeur par défaut : Mode: Mode : IN IN OUT OUT VARIADIC VARIADIC PermissionWidget Roles Rôles ID: Identifiant : Permissions Permissions Add Permission Ajouter permission Update Permission Actualiser permission Cancel Operation Annuler l'opération Privileges Privilèges Disable SQL code Désactiver le code SQL Cascade Cascade Privilege Privilège GRANT OPTION GRANT OPTION Code Preview Prévisualisation du code Name Nom Id Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. Laissez la grille <em><strong>Rôles</strong></em> vide afin de créer un %1 applicable à <strong><em>PUBLIC</em></strong>. -- No permissions defined for the specified object! -- Aucune permission définie pour cet objet ! /* Could not generate the SQL code preview for permissions! /* Impossible de générer la prévisualisation du code SQL pour les permissions ! Edit permissions Modifier les permissions &Grant Acco&rder Re&voke Ré&voquer PgModelerCLI Unrecognized option '%1'. Option '%1' non reconnue. Value not specified for option '%1'. Valeur pour l'option '%1' manquante. Option '%1' does not accept values. L'option '%1' n'accepte pas de valeur. Usage: pgmodeler-cli [OPTIONS] Utilisation : pgmodeler-cli [OPTIONS] command line interface. interface en ligne de commande. General options: Options générales : DBMS export options: Options d'export directe dans un serveur : Input file must be different from output! Le fichier source doit être différent du fichier de sortie ! Incomplete connection information! Les informations de connexion sont incomplètes ! Starting model export... Début de l'export du modèle... Miscellaneous options: Options diverses : There are no connections configured. Il n'y a aucune connexion configurée. Invalid zoom specified! Zoom spécifié invalide ! Invalid action specified to update mime option! Action spécifiée invalide pour mettre à jour l'option mime ! Starting model fixing... Lancement de la fixation du modèle... Starting mime update... Lancement de la mise à jour du mime... Model successfully fixed! Modèle fixé avec succès ! Extracting objects' XML... Extraction des objets XML... Connection aliased as '%1' was not found in the configuration file. PostgreSQL Database Modeler Project - pgmodeler.io Copyright 2006-2018 Raphael A. Silva <raphael@pgmodeler.io> This CLI tool provides several operations over models and databases without the need to perform them in pgModeler's graphical interface. All available options are described below. %1, %2 [FILE] Input model file (.dbm). This is mandatory for fix, export operations. %1, %2 [DBNAME] Input database name. This is mandatory for import operation. %1, %2 [FILE] Output file. This is mandatory for fixing model or exporting to file, png or svg. %1, %2 Try to fix the structure of the input model file in order to make it loadable again. %1, %2 [NUMBER] Model fix tries. When reaching the maximum count the invalid objects will be discarded. %1, %2 Export the input model to a sql script file. %1, %2 Export the input model to a png image. %1, %2 Export the input model to a svg file. %1, %2 Export the input model directly to a PostgreSQL server. %1, %2 Import a database to an output file. %1, %2 Compares a model and a database or two databases generating the SQL script to synch the latter in relation to the first. %1, %2 Force the PostgreSQL version of generated SQL code. %1, %2 Silent execution. Only critical messages and errors are shown during process. %1, %2 Show this help menu. Connection options: %1, %2 List available connections in file %3. %1, %2 [ALIAS] Connection configuration alias to be used. %1, %2 [HOST] PostgreSQL host in which a task will operate. %1, %2 [PORT] PostgreSQL host listening port. %1, %2 [USER] PostgreSQL username. %1, %2 [PASSWORD] PostgreSQL user password. %1, %2 [DBNAME] Connection's initial database. %1, %2 Draws the grid in the exported image. %1, %2 Draws the page delimiters in the exported image. %1, %2 Each page will be exported in a separated png image. (Only for PNG images) %1, %2 [FACTOR] Applies a zoom (in percent) before export to png image. Accepted zoom interval: %3-%4 (Only for PNG images) %1, %2 Ignores errors related to duplicated objects that eventually exist in the server. %1, %2 [CODES] Ignores additional errors by their codes. A comma-separated list of alphanumeric codes should be provided. %1, %2=[CODES] Ignore les erreurs supplémentaires par leurs codes. Une liste de codes alphanumériques séparés par des virgules doit être fournie. {1,?} {2 ?} %1, %2 Drop the database before execute a export process. %1, %2 Runs the DROP commands attached to SQL-enabled objects. %1, %2 Simulates an export process by executing all steps but undoing any modification in the end. %1, %2 Generates temporary names for database, roles and tablespaces when in simulation mode. Database import options: %1, %2 Ignore all errors and try to create as many as possible objects. %1, %2 Import system built-in objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Import extension objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Run import in debug mode printing all queries executed in the server. Diff options: %1, %2 [DBNAME] The database used in the comparison. All the SQL code generated is applied to it. %1, %2 Save the generated diff code to output file. %1, %2 Apply the generated diff code on the database server. %1, %2 Don't preview the generated diff code when applying it to the server. %1, %2 Drop cluster level objects like roles and tablespaces. %1, %2 Revoke permissions already set on the database. New permissions configured in the input model are still applied. %1, %2 Drop missing objects. Generates DROP commands for objects that are present in the input model but not in the compared database. %1, %2 Force the drop of missing columns and constraints. Causes only columns and constraints to be dropped, other missing objects aren't removed. %1, %2 Rename the destination database when the names of the involved databases are different. %1, %2 Don't drop or truncate objects in cascade mode. %1, %2 Truncate tables prior to alter columns. Avoids errors related to type casting when the new type of a column isn't compatible to the old one. %1, %2 Don't reuse sequences on serial columns. Drop the old sequence assigned to a serial column and creates a new one. %1, %2 Don't force the recreation of objects. Avoids the usage of a DROP and CREATE commands to create a new version of the objects. %1, %2 Don't recreate the unmodifiable objects. These objects are the ones which can't be changed via ALTER command. %1, %2 [ACTION] Handles the file association to .dbm files. The ACTION can be [%3 | %4]. ** The diff process allows the usage of the following options related to import and export operations: * Export: * Import: ** When running the diff using two databases (%1 and %2) there's the need to specify two connections/aliases. If only one connection is set it will be used to import the input database as well to retrieve database used in the comparison. A second connection can be specified by appending a 1 on any connection configuration parameter listed above. Available connections (alias : connection string) No operation mode was specified! Export, fix model, import database, diff and update mime operations can't be used at the same time! Multiple export mode was specified! No input file was specified! No input database was specified! No output file was specified! No input file or database was specified! The input file and database can't be used at the same time! No database to be compared was specified! No diff action (save or apply) was specified! No output file for the diff code was specified! ** Error code `%1' found and ignored. Proceeding with export. ** Command: %1 Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted! Fichier d'entrée invalide ! Il semble que ce ne soit pas un modèle généré par pgModeler ou que le fichier soit corrompu ! Recreating objects... Recréation des objets... ** Object(s) that couldn't fixed: ** Ces objets ne peuvent être corrigés : WARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2) AVERTISSEMENT : Certains objets ne peuvent peut-être pas être corrigés. Nouvel essai... (%1/%2) Loading input file: %1 Fixed model file: %1 Export to PNG image: %1 Export to SVG file: %1 Export to SQL script file: %1 Export to DBMS: %1 Export successfully ended! Starting database import... Input database: %1 Saving the imported database to file... Import successfully ended! Starting diff process... Input model: %1 Compare to: %1 Loading input model... Importing the database `%1'... Comparing the generated models... No differences were detected. Saving diff to file `%1' ** WARNING: You are about to apply the generated diff code to the server. Data can be lost in the process! ** Proceed with the diff applying? (yes/no) > yes no Diff code not applied to the server. Applying diff to the database `%1'... Diff successfully ended! Mime database successfully updated! Database model files (.dbm) are already associated to pgModeler! Les fichiers de modèle de bases de données (.dbm) sont déjà associés à pgModeler ! There is no file association related to pgModeler and .dbm files! Il n'y a pas d'association entre pgModeler et .les fichiers dbm ! Mime database operation: %1 Opération de base de données mime : %1 Can't erase the file %1! Check if the current user has permissions to delete it and if the file exists. Impossible d'effacer le fichier %1 ! Vérifiez si l'utilisateur actuel dispose des autorisations pour le supprimer et si le fichier existe. Running update-mime-database command... Exécution de la commande update-mime-database... PNG and SVG export options: Options d'export en PNG et SVG : PgModelerPlugin Plugin Information Information d'extension Version: %1 Version : %1 Author: %1 Auteur : %1 PgModelerUiNS Do you want to apply the <strong>SQL %1 status</strong> to the object's references too? This will avoid problems when exporting or validating the model. Souhaitez-vous appliquer <strong>statut SQL %1 </strong> aux références de l'objet également ? Cela permet d'éviter des problèmes lors de l'export ou de la validation du modèle. disabling désactivation enabling activation PgSQLTypeWidget Form Formulaire Data Type Type de donnée SRID: SRID : Variation: Variation : Z Z M M Precision Précision Spatial: Spatial : Dimension Dimension Format: Format : Timezone: Fuseau horaire : Type: Type : P: P : Length Longueur L: L : Interval: Intervalle : [ ]: [ ] : NONE AUCUN PluginsConfigWidget Form Formulaire Plug-ins root directory: Répertoire racine des extensions : Open in file manager Ouvrir dans le gestionnaire de fichier Loaded plug-ins Extensions chargées Plugin Extension Version Library Bibliothèque PolicyWidget Basics Notions de base Command: Commande : Permissive Permissif Roles Rôles Expressions USING: UTILISANT : CHECK: VÉRIFIER : Name Nom Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. Laissez la grille <em><strong>Rôles</strong></em> vide afin de créer un %1 applicable à <strong><em>PUBLIC</em></strong>. QObject new_database nouvelle_base_de_données %1 (line: %2) %1 (ligne : %2) Relationship %1_has_one_%2 Faut-il le traduire ? %1_has_many_%2 Faut-il le traduire ? many_%1_has_many_%2 Faut-il le traduire ? %1_inherits_%2 Faut-il le traduire ? %1_copies_%2 Faut-il le traduire ? RelationshipConfigWidget Form Formulaire Connect FK to PK columns Relier les colonnes associant clés étrangères/clés primaires Connect tables' center points Relier les associations aux tables en un point central Foreign key settings Clés étrangères Deferral: Report : Deferrable: Reportable : ON DELETE: ON DELETE : ON UPDATE: ON UPDATE : Name patterns Règles de nommage Relationship type: Type d'association : Foreign Key (Target): Clé étrangère (Cible) : Unique Key Name: Nom contrainte unique : Primary Key Name: Nom contrainte clé primaire : Primary Key Column: Nom colonne clé primaire : Column (Target): Colonne (Cible) : Foreign Key (Source): Clé étrangère (Source) : Column (Source): Colonne (Source) : One to one (1:1) Un à un (1 :1) Connection Mode Affichage FK Settings && Patterns Clés étrangères && nommage One to many (1:n) Un à plusieurs (1 :n) Many to many (n:n) Plusieurs à plusieurs (n :n) Generalization Généralisation Copy Copie Default Défaut Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Motif pour les noms de clés étrangères générées qui sont basées sur la clé primaire d'une table référencée (1 :1 et 1 :n) ou sur la clé primaire de la table source (n :n). Pattern for columns generated based upon target table's pk (n-n). Motif pour les noms de colonnes générées qui sont basées sur la clé primaire de la table cible (n :n). Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Motif pour les noms de colonnes générées qui sont basées sur la clé primaire d'une table référencée (1 :1 et 1 :n) ou sur la clé primaire de la table source (n :n). Pattern for foreign key generated based upon target table's pk (n-n). Motif pour les noms de clés étrangères générées qui sont basées sur une clé primaire de la table cible (n :n). Pattern for unique key generated by the relationship. Motif pour les noms de clés uniques qui sont générées par une association. Pattern for primary key generated by identifier relationship. Motif pour les noms de clés primaires qui sont générées par une association. This mode renders the relationships in crow's foot notation which has a better semantics and readability. It also determines the optimal point where the relationship is connected on the tables' edges taking their position into account. Ce mode affiche les associations en pied d'oiseau ce qui améliore le sémantique et la lisibilité. Il détermine également le point optimal où la relation est connectée sur les bords des tables en tenant compte de leur position. Crow's foot notation Affichage en pied d'oiseau This mode determines the optimal point where the relationship is connected on the tables' edges taking their position into account. It implies the usage of the classical ER notation. Ce mode détermine le point optimal où la relation est connectée sur les bords des tables en tenant compte de leur position. Cela implique l'utilisation de la notation ER classique. Connect tables' edges Connecter les bords des tables This mode is available only for <strong>one-to-one</strong>, <strong>one-to-many</strong> and <strong>fk relationships</strong> but provides a better semantics when linking tables by placing the lines on the exact point where the relationship occurs. It implies the usage of the classical ER notation. Ce mode d'affichage est disponible uniquement pour les associations de type <strong>un-à-un</strong>, <strong>un-à-plusieurs</strong> et <strong>les associations aux clés étrangères</strong> mais fournit une meilleure sémantique lors de l'association de tables en plaçant les lignes sur le point exact où l'association se produit. Cela implique l'utilisation de la notation ER classique. This mode is the classical one. It connects the relationship to tables through their central points. It implies the usage of the classical ER notation. Ce mode est le classique. Il relie les associations de tables depuis leurs points centraux. Cela implique l'utilisation de la notation ER classique. RelationshipWidget General Général One to one relationship Association un à un One to many relationship Association un à plusieurs 1-n 1-n Many to many relationship Association plusieurs à plusieurs n-n n-n Generalization relationship (inheritance) Association de généralisation (héritage) Dependency / Copy relationship Relation de dépendance / copie dep dep Relationship generated via foreign key Relation générée par une clé étrangère fk fk Identifier Identifiant Rel. Type: Type de relation : Table 1: Table n°1 : Table 2: Table n°2 : Foreign key Settings Propriétés par défaut des clés étrangères Use the values defined on settings dialogs for the fields below Utiliser les paramètres de pgModeler pour les champs ci-dessous Use global settings for these fields Utiliser les paramètres globaux de pgModeler ON DELETE: ON DELETE : ON UPDATE: ON UPDATE : &1-1 &gen Name Patterns Règles de nommage Column (Source): Colonne (Source) : Column (Target): Colonne (Cible) : Foreign Key (Source): Clé étrangère (Source) : Foreign Key (Target): Clé étrangère (Cible) : Cardinality: Cardinalité : [SRC] is required [SRC] est requis [DST] is required [DST] est requis Name of the table generated from many to many relationship Nom de la table générée par une relation plusieurs à plusieurs Deferrable: Reportable : Deferral: Report : Copy Options Options de copie INDEXES INDEX COMMENTS COMMENTAIRES INCLUDING INCLURE DEFAULTS DEFAUTS CONSTRAINTS CONTRAINTES Use defaults Utiliser les valeurs par défauts ALL TOUT STORAGE STOCKAGE Gen. Table Name: Nom nouvelle table : Attributes Attributs Constraints Contraintes Primary key Clé primaire Advanced Avancé Attribute Attribut Type Constraint Contrainte Name Nom This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables. Cet onglet avancé montre les objets (colonnes ou tables) générés automatiquement par la relation ainsi que les clés étrangères qui forment le(s) lien(s) entre les tables. is required est requis Reference Table: Table référente : Default Défaut Receiver Table: Table de destination : Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Motif pour les noms de colonnes générées qui sont basées sur la clé primaire d'une table référencée (1 :1 et 1 :n) ou sur la clé primaire de la table source (n :n). Pattern for columns generated based upon target table's pk (n-n). Motif pour les noms de colonnes générées qui sont basées sur la clé primaire de la table cible (n :n). Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Motif pour les noms de clés étrangères générées qui sont basées sur la clé primaire d'une table référencée (1 :1 et 1 :n) ou sur la clé primaire de la table source (n :n). Pattern for foreign key generated based upon target table's pk (n-n). Motif pour les noms de clés étrangères générées qui sont basées sur une clé primaire de la table cible (n :n). Pattern for primary key generated by identifier relationship. Motif pour les noms de clés primaires qui sont générées par une association. Primary Key Name: Nom de clé primaire : Pattern for unique key generated by the relationship. Motif pour les noms de clés uniques qui sont générées par une association. Unique Key Name: Nom clé unique : Primay Key Column: Colonne de clé primaire : The receiver's primary key will be composed by the generated foreign key columns. La clé primaire du destinataire sera composée des colonnes de clé étrangère générées. Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key. Au lieu de créer une clé primaire à valeurs multiples avec les colonnes de clés étrangères générées, une seule colonne est créée et utilisée comme clé primaire. Single PK column Colonne clé primaire simple Custom Color: Couleur personnalisée : Use the special primary key if you want to include a primary key containing generated columns to the receiver table. <strong>Important:</strong> if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key. Utilisez la clé primaire spéciale si vous souhaitez inclure une clé primaire contenant des colonnes générées dans la table de destination. <strong>Important :</strong> s'il s'agit d'une nouvelle relation, il est nécessaire de terminer sa création et de réouvrir cette boîte de dialogue pour créer la clé primaire spéciale. Referer View: Vue référente : Referer view references one or more columns of a table to construct it's own columns. La vue référente référence une ou plusieurs colonnes d'une table pour construire ses propres colonnes. Referenced table has its columns referenced by a view in order to construct the columns of this latter. La table référencée a ses colonnes référencées par une vue afin de construire les colonnes de cette dernière. Referer Table: Table référente : Referer table references one or more columns of a table through foreign keys. This is the (n) side of relationship. La table référente référence une ou plusieurs colonnes d'une table via des clés étrangères. C'est le côté (n) de la relation. Referenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship. La table référencée a ses colonnes référencées par la clé étrangère d'une table. C'est le côté (1) de la relation. Referenced Table: Table référencée : Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship. La table de référence a les colonnes de sa clé primaire copiées dans la table de réception afin de représenter la liaison entre elles. C'est le côté (1) de la relation. Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship. La table référente recevra les colonnes générées et la clé étrangère afin de représenter la liaison entre elles. C'est le côté (n) de la relation. In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table. Dans les relations plusieurs-à-plusieurs, les deux tables sont utilisées comme référence pour générer la table qui représente la liaison. Les colonnes des deux tables sont copiées dans la table résultante et deux clés étrangères sont également créées afin de référencer chaque table participante. E&XCLUDING E&XCLUSION Available tokens to define name patterns:<br/> <strong>%1</strong> = Reference (source) primary key column name. <em>(Ignored on constraint patterns)</em><br/> <strong>%2</strong> = Reference (source) table name.<br/> <strong>%3</strong> = Receiver (destination) table name.<br/> <strong>%4</strong> = Generated table name. <em>(Only for n:n relationships)</em> Formes disponibles pour définir les modèles de noms : <br/> <strong>%1</strong> = Nom de la colonne de clé primaire de référence (source). <em>(Ignoré sur les modèles de contrainte)</em><br/> <strong>%2</strong> = Nom de la table de référence (source).<br/> <strong>%3</strong> = Nom de la table référencée (ou de déstination). <br/> <strong>%4</strong> = Nom de la table générée. <em>(Seulement pour les relations n:n)</em> ResultSetModel [binary data] [données binaires] RoleWidget Password: Mot de passe : Connections: Connexions : Attributes Attributs Superuser Super utilisateur Inherit permissions Hériter des permissions Can create database Peut créer des bases de données Can use replication Peut utiliser la réplication Can login Peut se loguer Encrypted Encrypté Members Membres Member of Membre de Members (Admin.) Membres (Admin.) Role Rôle Validity Validité yyyy-MMM-dd hh:mm:ss aaaa-MMM-jj hh :mm :ss Assigning <strong><em>-1</em></strong> to <strong><em>Connections</em></strong> creates a role without connection limit.<br/> Unchecking <strong><em>Validity</em></strong> creates an role that never expires. L'affectation de <strong><em>-1</em></strong> à <strong><em>Connexions</em></strong> crée un rôle sans limite de connexion.<br/> Décocher <strong><em>Validité</em></strong> crée un rôle qui n'expire jamais. Bypass RLS Contournement RLS Can create role Peut créer des rôles RuleWidget Event: Évènement : Execution Type: Type d'exécution : Conditional Expr.: Expr. conditionnelle : Commands Commandes SQL Command: Commandes SQL : SQL command Commande SQL To create a rule that does not perform any action (<strong>DO NOTHING</strong>) simply do not specify commands in the SQL commands table. Pour créer une règle qui n'éxécute aucune action (<strong>DO NOTHING</strong>), ne spécifiez aucune commandes dans le champs des commandes SQL. SQLExecutionWidget Form Formulaire Save SQL commands Sauvegarder commandes SQL Alt+F Alt+F Run the specified SQL command Exécuter la commande SQL entrée Run SQL Exécuter SQL F6 F6 Clear sql input field and results Effacer le code SQL et la grille de résultat Clear All Effacer Export results to a CSV file Exporter les résultats dans un fichier CSV Snippe&ts Extrai&ts Alt+T E&xport E&xporter ... ... SQL file (*.sql);;All files (*.*) Fichier SQL (*.sql);;Tous les fichiers (*.*) Load Charger Save Enregistrer Save as Enregistrer sous [binary data] [données binaires] Messages (%1) [%1]: SQL command successfully executed in <em><strong>%2</strong></em>. <em>%3 <strong>%4</strong></em> Save CSV file Sauvegarder fichier CSV Comma-separated values file (*.csv);;All files (*.*) Fichiers CSV avec champs séparés par des virgules (*.csv);;Tous les fichiers (*.*) The SQL input field and the results grid will be cleared! Want to proceed? Le champ d'entrée SQL ainsi que la grille des résultats vont être purgés ! Voulez-vous poursuivre ? Save history Enregistrer l'historique Reload history Recharger l'historique Find in history Rechercher dans l'historique Hide find tool Masquer l'outil de recherche This action will wipe out all the SQL commands history for the current connection! Do you really want to proceed? Cette action effacera tout l'historique des commandes SQL pour la connexion en cours ! Voulez-vous vraiment poursuivre ? Load SQL commands Charger commandes SQL Copy selection Copier la sélection Search in SQL code Rechercher dans le code SQL Toggles the output pane (Dés)active le volet de sortie &Output S&ortie Alt+O Alt+O Results Résultats Messages History Historique No results retrieved or changes done due to the error above. Aucun résultat n'a été récupéré ou des modifications ont été effectuées en raison de l'erreur ci-dessus. Results (%1) Resultats (%1) Rows affected Lignes affectées Rows retrieved Lignes récupérées Plain format Format simple CVS format Format CVS This action will wipe out all the SQL commands history for all connections! Do you really want to proceed? Cette action effacera tout l'historique des commandes SQL pour toutes les connexions ! Voulez-vous vraiment poursuivre ? Clear history Nettoyer l'historique Close the current SQL script Fermer le script SQL actuel SQL script currently handled Script SQL actuellement géré (not saved) (non enregistré) Handle external SQL script Gérer le script SQL externe &Script Fi&nd &Rechercher Alt+X Current working database Base de données de travail actuelle SQLToolWidget Form Formulaire Database explorer Explorateur de bases de données SQL execution Exécuteur de code SQL ... ... Warning Avertissement Disconnect from all databases Se déconnecter de toutes les bases de données Update the database list Mettre à jour la liste des bases de données Toggle the object's attributes grid (Dés)active la grille des attributs de l'objet Attributes Attributs Alt+R Alt+R Toggle the display of source code pane (Dés)active l'affichage du volet du code source Source code Code source <strong>ATTENTION:</strong> Disconnect from all databases will close any opened tab in this view! Do you really want to proceed? <strong>ATTENTION :</strong> Se déconnecter de toutes les bases de données fermera tout onglet ouvert dans cette vue ! Voulez-vous vraiment poursuivre ? SceneInfoWidget Form Formulaire Current position of the mouse in the canvas Position actuelle de la souris dans le canevas - Current zoom factor Facteur de zoom actuel Currently selected object(s) Objet(s) actuellement sélectionné(s) Dimensions of the selected object(s) Dimensions de(s) l'objet(s) sélectionné(s) No selection Aucune séléction N/A Inconnu Sel. objects: %1 Objets select. : %1 SchemaWidget Show rectangle Afficher le rectangle Fill color: Couleur de remplissage : SequenceWidget Cyclic: Cyclique : Start: Début : Maximum: Maximum : Minimum: Minimum : Defualt values: Increment: Incrément : Cache: Cache : Owner Col.: Proprio. Col. : User defined SnippetsConfigWidget Form Formulaire Create new connection Créer une nouvelle connexion Cancel edition Annuler l'édition Edit selected connection Modifier la connexion sélectionnée Delete selected connection Supprimer la connexion sélectionnée Remove All Tout supprimer Shift+Del Maj+Suppr Filter: Filtrer : ID: Identifiant : Add Ajouter Update Mettre à jour General Général Label: Étiquette : Applies to: S'applique à : Parsable or dynamic snippets are written in the <strong>schema micro language</strong> syntax. When using a parsable snippet the attributes surrounded in <strong>{}</strong> will be replaced by the selected object's matching attributes. Les extraits de code analysables ou dynamiques sont écrits dans la syntaxe <strong>schema micro language</strong>. Lorsque vous utilisez un extrait de code analysé, les attributs entourés par des <strong>{}</strong> seront remplacés par les attributs correspondants de l'objet sélectionné. Parsable Analysable When handling parsable snippets empty attributes will be replaced by a value in the format <strong>{attribute}</strong>. Note that this option can affect the semantics of the resulting snippet. Lors de la manipulation d'extraits de code analysables, les attributs vides seront remplacés par une valeur au format <strong>{attribut}</strong>. Noter que cette option peut affecter la sémantique de l'extrait résultant. Placeholders Élément de substitution Parse the snippet in order to check if there are syntax errors. Analyser l'extrait de code afin de vérifier s'il existe des erreurs de syntaxe. Parse Analyser Snippets: Extraits : General purpose Usage général All snippets Tous les extraits /* Error parsing the snippet '%1': %2 */ /* Erreur lors de l'analyse de l'extrait '%1': %2 */ Duplicated snippet id <strong>%1</strong> detected. Please, specify a different one! Identifiant <strong>%1</strong> d'extrait dupliqué détécté. Merci d'en choisir un autre ! Invalid ID pattern detected <strong>%1</strong>. This one must start with at leat one letter and be composed by letters, numbers and/or underscore! Motif d'identification <strong>%1</strong> incorrect détecté. Celui-ci doit commencer par au moins une lettre et être composé de lettres, de chiffres et/ou de tirets bas _ ! Empty label for snippet <strong>%1</strong>. Please, specify a value for it! Label vide pour l'extrait <strong>%1</strong>. Merci de lui spécifier une valeur ! Empty code for snippet <strong>%1</strong>. Please, specify a value for it! Code vide pour l'extrait <strong>%1</strong>. Merci de lui spécifier une valeur ! The dynamic snippet contains syntax error(s). Additional info: <br/><em>%1</em> L'extrait dynamique contient des erreurs de syntax. Plus d'informations : <br/><em>%1</em> Do you really want to remove all snippets? Voulez-vous vraiment supprimer tous les extraits ? No syntax errors found in the snippet. Aucune erreur de syntax retrouvée dans l'extrait. SourceCodeWidget Version: Version : PostgreSQL PostgreSQL iconecodigo icône SQL SQL Original XML XML Source code visualization Visualisation du code source SQL code (*.sql);;All files (*.*) Code SQL (*.sql);;Tous les fichiers (*.*) Generating source code... Génération du code source... -- NOTE: the code below contains the SQL for the selected object -- as well for its dependencies and children (if applicable). -- -- This feature is only a convinience in order to permit you to test -- the whole object's SQL definition at once. -- -- When exporting or generating the SQL for the whole database model -- all objects will be placed at their original positions. -- NOTE: le code ci-dessous contient le code SQL de l'objet sélectionné -- ainsi que de ses dépendances et enfants (le cas échéant). -- -- Cette fonctionnalité n'est qu'une commodité vous permettant de tester -- la définition SQL de l'objet entier. -- -- Lors de l'export ou de la génération du code SQL pour l'ensemble du modèle de base de données, -- tous les objets seront placés à leurs positions d'origine. -- SQL code unavailable for this type of object -- -- Code SQL non disponible pour ce type d'objet. -- Code display: Affichage du code : Original + depedencies' SQL Original + dépendances de SQL Original + children's SQL Original + enfants de SQL Save the SQL code to a file. Enregistrer le code SQL dans un fichier. Save SQL Enregistrer le code SQL Save SQL code as... Enregistrer le code SQL sous... <!-- XML code preview disabled in demonstration version --> < !-- Aperçu du code XML désactivé dans la version de démonstration --> <strong>Original:</strong> displays only the original object's SQL code.<br/><br/> <strong>Dependencies:</strong> displays the original code including all dependencies needed to properly create the selected object.<br/><br/> <strong>Children:</strong> displays the original code including all object's children SQL code. This option is used only by schemas, tables and views. <strong>Original :</strong> affiche uniquement le code SQL de l'objet d'origine.<br/><br/> <strong>Dépendances :</strong> affiche le code d'origine ainsi que toutes les dépendances nécessaires pour créer correctement l'objet sélectionné.<br/><br/> <strong>Enfants :</strong> affiche le code original ainsi que le code SQL de tous les enfants. Cette option est utilisée uniquement par les schémas, les tables et les vues. -- SQL code purposely truncated at this point in demo version! -- Le code SQL est volontairement tronqué à ce stade dans la version démo ! SwapObjectsIdsWidget Create: Créer : ID: Identifiant : Before: Avant : Swap the values of the fields Procède à l'échange Swap values Échanger Change objects creation order Changer l'ordre de création des objets Change the objects creation order is an irreversible operation and cause the operations history to be automatically erased. Note that the creation order configured in this form is not definitive and may change after a model validation. Modifier l'ordre de création des objets est une opération irréversible qui entraîne l'effacement automatique de l'historique des opérations. Noter que l'ordre de création configuré dans ce formulaire n'est pas définitif et peut changer après la validation d'un modèle. Swap the object ids changing their creation order Modifie l'ordre de création de deux objets en échangeant leurs numéros d'identification Swap ids Échanger identifiants Filter: Filtrer : ID Identifiant Object Objet Type Parent Object Objet parent Parent Type Type parent Table new_table nouvelle_table In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2' Dans la version de démonstration, les tables ne peuvent contenir que `%1' instance(s) de chaque type d'objet enfant ou table ancêtre ! Vous avez atteint cette limite pour le type : `%2' TableDataWidget Edit table data Modifier les données de la table Copy items on the grid Copier les éléments sur la grille Copy Add empty rows Ajouter des lignes vides Add row Ins Insérer Ctrl+D Add an empty column Ajouter une colonne vide Delete rows Remove all rows from the grid preserving columns Supprimer toutes les lignes des colonnes de préservation de la grille Shift+Del Maj+Suppr Delete the selected rows Supprimer les lignes sélectionnées Del Suppr Duplicate the selected rows Dupliquer les lignes sélectionnées Delete the selected columns Supprimer les colonnes sélectionnées Delete column Paste items on the grid Copier les éléments sur la grille Paste Coller Ctrl+V <html><head/><body><p>Some invalid or duplicated columns were detected. In order to solve this issue double-click the header of the highlighted ones in order to define the correct name in which the data belongs to or delete the entire column. Note that these columns are completely ignored when generating the <span style=" font-weight:600;">INSERT</span> commands.</p></body></html> Add column Duplicate rows Change the values of all selected cells at once Modifier d'un coup les valeurs de toutes les cellules sélectionnées Bulk data edit Modification de données en masse Ctrl+E Ctrl+E Remove all columns (and rows) from the grid Supprimer toutes les colonnes (et lignes) de la grille Delete all columns Ctrl+Shift+Del Ctrl+Maj+Suppr Delete all rows Delete columns is an irreversible action! Do you really want to proceed? Effacer des colonnes est une action irréversible ! Voulez-vous vraiment poursuivre ? Remove all rows is an irreversible action! Do you really want to proceed? Supprimer toutes les lignes est une action irréversible ! Voulez-vous vraiment poursuivre ? Remove all columns is an irreversible action! Do you really want to proceed? Supprimer toutes les colonnes est une action irréversible ! Voulez-vous vraiment poursuivre ? Unknown column Colonne inconnue Duplicated column Colonne dupliquée Fills the grid using a CSV file Remplit la grille en utilisant un fichier CSV <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> <html><head/><body><p>Les valeurs vides sont supposées être <span style="font-weight :600;">DEFAULT</span>. Pour utiliser des valeurs spéciales comme <span style="font-weight :600;">NULL</span>, un appel de fonction comme <span style="font-weight :600;">now()</span> ou un échappement des données spécifiques, entourer les valeurs de deux barres obliques, par exemple <span style="font-weight :600;">/valeur/</span>. Pour utiliser une barre oblique dans le cadre de la valeur, ajouter le caractère barre oblique inverse, par exemple <span style="font-weight :600;">/</span>.</p></body></html> TableObjectView Relationship: %1 Relations : %1 TableWidget Options Options Tag: Balise : With OID Avec OID Generate ALTER for columns/constraints Utiliser ALTER pour les colonnes/contraintes Unlogged Unlogged Name Nom Schema Schéma Type PK Faut-il le traduire ? CP Default Value Valeur par défaut Attribute(s) Attribut(s) It is not possible to mark a column as primary key when the table already has a primary key which was created by a relationship! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. Il n'est pas possible de marquer une colonne comme clé primaire quand la table a déjà une clé primaire qui a été créée par une relation ! Cette action doit être effectuée dans la section <strong>Clé primaire</strong> du formulaire d'édition de la relation. It is not possible to mark a column created by a relationship as primary key! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. Il n'est pas possible de marquer une colonne créée par une relation comme clé primaire ! Cette action doit être effectuée dans la section <strong>Clé primaire</strong> du formulaire d'édition de la relation. ON DELETE Faut-il le traduire ? À la suppression ON UPDATE Faut-il le traduire ? À la mise à jour Refer. Table Table de référ. Firing Déclencheur Events Evènements Execution Exécution Event Evènement Indexing Indexation Command Commande Permissive Permissif USING expression Faut-il le traduire ? CHECK expression Faut-il le traduire ? Roles Rôles Parent Copy Copie Yes Oui No Non &Columns &Colonnes Co&nstraints Co&ntraintes Tri&ggers Décl&encheurs &Rules &Régles &Indexes &Index &Tables &Tables Edit data Modifier données Define initial data for the table Définir les données initiales de la table Enable row level security Activer la sécurité au niveau de la ligne Force RLS for owner Forcer RLS pour le propriétaire &Policies &Politiques TablespaceWidget Form Formulaire Directory: Dossier : TagWidget Colors Couleurs Extended body: Corps étendu : Body: Corps : Title: Titre : Schema name: Nom du schéma : Table name: Nom de la table : TaskProgressWidget Executing tasks Exécution des tâches Waiting task to start... En attente du démarrage de la tâche ... TextboxWidget Font: Police : Text Texte pt pt Color: Couleur : Bold Gras Italic Italique Underline Souligné Select text color Sélection de la couleur du texte TriggerWidget Event: Évènement : INSERT INSERT DELETE DELETE UPDATE UPDATE TRUNCATE TRUNCATE Deferrable: Reportable : Columns Colonnes Column: Colonne : Arguments Arguments Constraint Contrainte FOR EACH ROW Pour chaque ligne Refer. Table: Table référ. : Condition: Condition : Argument: Argument : Function: Fonction : Options: Options : Excution: Exécution : Column Colonne Type TypeWidget Configuration: Configuration : Base Type Type de base Enumeration Énumération Enumerations Énumérations Enumeration: Énumération : Attributes Attributs Internal Length: Long. interne : Storage: Stockage : Category: Catégorie : Delimiter: Délimiteur : Alignment: Alignement : char char smallint smallint integer integer double precision double précision Default Value: Valeur par défaut : Range Intervalle Options: Options : By value Par valeur Preferred Préféré Collatable Assemblable Functions Fonctions INPUT: INPUT : OUTPUT: OUTPUT : RECV: RECV : SEND: SEND : TPMOD_IN: TPMOD_IN : TPMOD_OUT: TPMOD_OUT : ANALYZE: ANALYZE : Name: Nom : Collation: Collation : Subtype Diff Func.: Fonction de différence du sous-type : Operator Class: Classe d'opérateurs : Canonical Func.: Fonction canonique : Like Type Type de Like Element Type Type d'élement Subtype Sous-type Name Nom Type Collation The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table> Les fonctions assignées à un type devraient être écrites en langage C et possèder, les signatures suivantes :<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table> The functions to be assigned to a range type should have the following signatures:<br/><br/><strong>Canonical:</strong> <em>any function(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision function(subtype, subtype)</em> Les fonction assignables au type plage (RANGE) doivent avoir la signature suivante :<br/><br/><strong>Canonical:</strong> <em>any function(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision function(subtype, subtype)</em> Co&mposite Co&mposite UpdateNotifierWidget Update Notifier Vérificateur de mise à jour Hide this widget Cacher ce widget ... ... Released in: Date de sortie : mmm dd, yyyy jj mmm aaaa 0.0.0 0.0.0 Changelog Journal des modifications Redirects to purchase page. Redirige vers la page web pour acheter. Get binary package Télécharger l'application compilée Redirects to GitHub source repository. Redirige vers la page web du dépôt GitHub. Get source code Télécharger le code source Failed to check updates Impossible de vérifier la présence de mise à jour The update notifier failed to check for new versions! Please, verify your internet connectivity and try again! Connection error returned: <em>%1</em> - <strong>%2</strong>. Le notificateur de mise à jour n'a pas pu vérifier les nouvelles versions ! Merci de vérifier votre connexion internet et de réessayer ! Erreur de connexion renvoyée : <em>%1</em> - <strong>%2</strong>. No updates found Aucune mise à jour trouvée You are running the most recent pgModeler version! No update needed. Vous utilisez déjà la version de pgModeler la plus récente ! Aucune mise à jour requise. The update notifier failed to check for new versions! A HTTP status code was returned: <strong>%1</strong> Le vérificateur de mise à jour n'a pas pu vérifier la présence de nouvelles versions ! Code retour HTTP reçu : <strong>%1</strong> Update found! Mise à jour trouvée ! New version: Nouvelle version : ViewWidget References Références Column Colonne Expression Expression Used in: Utilisé dans : Reference Type: Type de référence : View Definition Définition de la vue Options Options Tag: Balise : Mode: Mode : Ordinary Ordinaire With no data Sans données Table: Table : Table Alias: Alias table : Column: Colonne : Column Alias: Alias colonne : Expression: Expression : Expression Alias: Alias expression : SELECT ... Faut-il le traduire ? WHERE ... Faut-il le traduire ? FROM ... Faut-il le traduire ? Triggers Déclencheur Rules Règles Indexes Table Expression CTE Code Preview Prévisualisation du code Alias Col. Alias col. Col./Expr. Alias Flags: SF FW AW EX VD Marques : SF FW AW EX VD To reference all columns in a table (*) just do not fill the field <strong>Column</strong>, this is the same as write <em><strong>[schema].[table].*</strong></em> Pour référencer toutes les colonnes d'une table (*), ne pas remplir le champ <strong>Colonne</strong> revient à écrire <em><strong>[schema].[table].*</Strong></em> Name Nom Refer. Table Table de référ. Firing Déclenche Events Evènements Indexing Indexation Execution Exécution Event Evènement /* Could not generate the SQL code. Make sure all attributes are correctly filled! /* Le code SQL ne peut être généré. Vérifiez que les champs sont correctement remplis ! Recursi&ve Récursi&f &Materialized &Matérialiser The element will be used as part of the SELECT statement to retrieve columns or expressions that will compose the view's columns L'élément sera utilisé dans le cadre de l'instruction SELECT pour extraire des colonnes ou des expressions qui composeront les colonnes de la vue. The element will be used as part of the WHERE clause in form of conditional expression L'élément sera utilisé dans le cadre de la clause WHERE sous forme d'expression conditionnelle. The element is used in the FROM portion of the command in order to reference tables or construct JOIN statements L'élément est utilisé dans la partie FROM de la commande afin de référencer des tables ou de construire des instructions JOIN. The element's expression is used exclusively as the view's definition L'expression de l'élément est utilisée exclusivement comme définition de la vue. The element will be appended to the very end of the view's definition. This is useful when using GROUP BY/HAVING statements L'élément sera ajouté à la fin de la définition de la vue. Ceci est utile lors de l'utilisation des instructions GROUP BY/HAVING. End expression Expression finale WelcomeWidget Form Formulaire New model Nouveau modèle Open model Ouvrir modèle Sample models Modèles de démo Recent models Modèles récents Last session Dernière session pgmodeler-0.9.2/lang/nl_NL.qm000066400000000000000000011127171360462764600160120ustar00rootroot00000000000000GJHKIKFJKKL&LLTMLMOM:PNQOORO}SPTPURiVRWRXS*YSXZSZr2k"As;U]TczRX9:O">O#t*'t7't,+O+[( +[1+19W1}%11P11!1U1P1111"1511J1Yh1h1w1%1D4>gF FsGXGaI@rIBrJ;J-JckJ 4J-LL ]Mz4Mz*MzKMzPSPSdPS aSɓTzTx TT4X\Y+Zw.*ZwQz]K_$_&jXpq>t.{*`,`Gs$k$((Gy,TyHyy!O]bD[֍֍R֍}P֍֍N֍" ֍#0֍8֍M֍֍ ֍Jl֍\%֍`֍aw֍d֍֍֍֍%֍1֍&֍~֍&p֍S4%5t}5tS5t^E)H5xH5=H5*H5H5,H5PH5#nH544H5P m)%,%O%$3%-(%O%%BRWc*:Lqe.epee$e,UeeR2eY3e_es$e0ege%ne.eBįmm/2R Cyiw5o y.^Y !E9_Sw*_*%`+5t`J+`+g`2r$3N3D46v"8_9B:4 ;H5$2TT(*TZz|TZOT5TjT4_VV7pV V5|V͡Wz5XmzWX5X9YbYbYbYYb$YuYQjZHZg~Zg>ZggIZy%-Zy%Zy%PZC\+\ \A\\Ze]._z֖`^}af ^dJd[eA dghS)6h^~jB)j~˃k lrn o-q`oE8Fp>q crV.Lr"As~s~ntln:v'jv: w<|T>xc-yC-y[J~S kcI^a` n a[^b! 6<=U_ 444#h44 4\4k4Fh^cV4%w̠+y1PZ!9a@1A{ Tǭ%~tϋy-@|E C1ߛᬱw@cMνMOM95@ 0qQ l <glOnl g m;p.P!$!U!B~Ӗ!a2!$2|'4)5,q/2/6ks!8RL8מhAHCEzǕP^la45_.N`uQNb}Ce4egegl!s=ue3w2xHn{x{y1zQ2d|{y.%}A7k~^~I&~J&MZ`!.MtcJ2CMe6o[Jdŀy0ƅ-Ơ<:ɀ1.c-5&3jQnCֳѴQFZFZ3;.CLA Q  A  5GqCOc)B8z Q'~KDJO22ZQg%0w*$4؎:eJ6lЁB$AJZZJ7O9teQKS2S2PT*Xky1\a/f>"Hh3kPo{ekp`1p`~sX9x?+#,SA ROd*0d* d* d*15dck0K0/E0i4^̯%HBw9'w9SZ+~K666_q6k66bYMf,,bRk_nCHßsNsoa0ėŖ^Ŗ**qV+,9U-Q1В+ ;n( pًo0bܟ1W[y-[SQ9S@ƫ3ARTUJ=t# #Ne%@8p9 6 C1HKE/c>qA!1##C1V(R?(>) (>(> ^(>G(>0)h})hL.@Th2i̓3bM6n?Z?\gBSL?tQ!}S.+VYNTZAZy1jJ,m^BIp Q:t1Ct1xZ)CZVVm/N'5AXzzg(ٴ4p~='\Z7a}(aN;#VqWw2j|ÌkuFǤ^^L<>ϸ`y'cѥ~؁ΔΔWΔ^ Δ? ;'y\L;y-AeRZF"=JJcv`* . x~, Vd~Nc H !&Ѥa'(]9=_;zb[@NkAЮKM!Y` M`  g"ilueduN xy*{<~RfB:P ,M^#4W#0bIIcRIII^I)II`@nISSys6Z)6&<>)Z<>gC<><>'<>H<>++<>M3\b@Z*4ɓ3D%Qo-{jjGjx,,,jjk k<kmkkkl% q-m8-N mP s m,.n6Rn]5~G#2GOsW(1W+>bM7*87I7HoARG2zn@HSnk!hT7~]9NE|teY_ȤTMZMZz$zz,ų!ųNv_?vL:%:[АG3АG"fАGO8Jq3k|c#|c b =Ig,Zz3|zt-YnRA+17ڐP?JvaCv@|zv;^iWiհ# * ) Ht HuK8/as5Дfvdku)yʔ"i~!&Vv$p1'],Nn,Nc/3 [L2B~}A3H$3HWc3H^l3HM5tܶ5t%8Gwo8ng9'!k:ʔ";I<F]CHEI/K hM2PێSUfY $Y V;Y ]Y piY `ُ%bߎcEewghlZE@hT$kiklll?l-nLZ5MnLZp3E|sw!eL{y6 =,3QmH5H5;H5``Gbr~5vBjzG~c/ jr1-U1Ԋ1PG1%++}{y3RoR&?'zI5XQgnPZ_Fm'^2U{P` Lƨeaƨƨ sȡ"ȼ[q1ѵu$ѵuPҵWŵ*:A޽q4ߺM%{%M1=c˥?@=W/=Wnh|% IUB [ i77@_-fm8[a#JP$Qw&%*  * +^^-3.f58>T9^:D%;<;8=ÆCCCQh C1P oDUV~dYZ>:&[g_p`Gt/]`*Gdg_|Ng_|gxh8m]szr7&wLwoBwovxxmykŎ{U{{ *{$8{P7|hM!>8JYZcjA${+s{uQjsB61L $GtE}. 9N,tz]GgIU8y}K>(]Q“Q^lfbl `]9ĩSȐ+ȐlȐ"ȐNȐpAɓؒɓM|*BR֣8μEvϾ٢ѥX&nv&n4D,ے4ے1Cے~@%4\:a>L%ީ\,i#ʔʥ '\Ȕf/fw?MN6!&"O>%*1,'|2…3c5U5jJ5 !7n:l,h;y(=;L/C*iCIC`N.WN'N)aRDn]c7iA j0@k5%rsUtvjw%w|ww|zxC\~4> >="O&p$hvvB8A ړoP+1!s.k(iQ ` z` Di` O` u` -` 5ra{,^F>,ƨ; -ρ $KӸ*Avtv!(.TC pQ)SeHnNc;@9YAJaW@w-~`M"9')c*z/+J#{+J4+ɳ,/er/yݜ/y4{|t58k_9*B;z7 Eet ln{ƁV'$]cybHЮ׮)\ʴ5JkQ.Q.Q.!Q.Nq`Dώ=Ͻlҥө|mli2r c)O:ʁ|8 >)3IlnvnFAs ?As2As',AsN1AsNAs1As!As/}#RB Fr 7F Tm  )g $: J^ 5 dz F " - % - -ֈ 0F 6 7p C_k Hde IJyT' IJy Oy Oy Rn Ty~/ ZJU3, ZJUK _ b+ e! h> kJ3 lQ,/ t|x8 t|S v/ yEG |~r^ n } v& *T r ۠7' 6V    ; 1  kR ZQ g% 1B ! X  ĝ]  " ' z'= !C m ʮU NJl NJo NJ NJ, (A  կ Hh ݳ 1C  V U c6< ^ !   J 1Ǎ  ^y m zl _!X h9)  Z\ . O$%  j$ 9 #N )`=g *pa +X 0l 1 1ױ 20 6  6=>G =J Am F M(o! M(f M( MJql` O T#N\^ T82 ZM Z [4 _1R `A ci* ci*5 cg cG c+ cZgx cZK cZ cZ+] cZM de d< e9 eb e+U f"C< gh h z i$ o^| qL r*j r3] r3! tsu x:o x  | ~ ~  m z zi l 1 + &%f & dq I' I9 IS I I x , QY 6 6 c޷ Y )q :b : :B G1 yX e ֭ >a > _Cѓ ׳ q v& c 5 56= Q t t t) tz )  H<  , J0 S E šd š Ԯ* ԮI Ǭ Lu= Rz+j t t*D ɗ , .N δn# δO δp" δsX v_ v Ϡ6 ϩ8.R ϩ8Q Ϭ5 ϼ %~ zT~   N ꚅ } %EF / NVV /* "   :P" ^:| w 1 $~2 T ~ , v" 3 % V3  ye] dZ+ nv nߕ .8> .Y 0ȯ 2; 2 ;l @+ AUN BR E.y OA VMh [1a [- \) er!+ g! hx*6 ia m{ʣ r%/ s t! w  Ui n  ݒ. ݒQ F 5 P  ڠ ? Enx L  k  _  ]1Q zj ll A- !  Y W." Oo O   ! x "g. "xs[ &A5 'y '~y -ɣO -ˣ .*+! /F /m 0D 1 @ N D+^ DYlV DYl DZl FM~ Y GH- N^ V E9 Zp [*5 ] g$ i8: j  nO r& { P P P 69e q b6Y ^g ^ ^X ^b 1 ] 8A t;[ Y ? / ¦e %h#+ <VD <` <8 <s <] < ǁA˯ u t S Sn S إT Y _2 @ 0<v 43 SK +MN]]>/` \V    s.JS JqJzJ1u .!<*Mb#'A1(o(T1Y225J3FG3 rI,KOL N|PTcCWG/>W>D\28diGjkJmS3pqn<rwsAHsD%<7u(puFJ'mP>$[y1H{zVz:a9&D`1'-C:; 3& 3s 3* * z1rCZyZŽ}l4!*֊،R?Zϝ3{r DB2LK_4j& . ǓU  ED i!2H1M55505Psj=NAVs.ϓ#סxv&3Q4&#62B;1?,^B7I9tJKPnQHtVvXN]A(`E$~`~ia*(aN!bOӳhhг-jMnkQ(mSv>tv*|uKmUh~a"7F N@`.)oT~P2,eeY*[$] f gHn] a%Љu;5A\+1Azzi~[V^ky-zԄwֈґ֣\=֣\g֣\ ֣\ +xG'JDyٶtt1]5"a,֌@iU (BUILD_NUM) AboutWidget... AboutWidget 0.0.00.0.0 AboutWidgetOver pgModelerAbout pgModeler AboutWidget$Verberg dit widgetHide this widget AboutWidgetLicensieLicense AboutWidget|Een Open Source data modeleer tool ontworpen voor PostgreSQL. Met pgModeler hoef je niet langer zelf je DDL commando's schrijven, laat dit over aan pgModeler! Deze software brengt de concepten van Entity-Relationship diagrammen samen met de features die PostgreSQL implementeerd als uitbreidingen van de SQL standaard.Open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand, let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards.  AboutWidget6PostgreSQL Database ModelerPostgreSQL Database Modeler AboutWidgetTpgModeler is trotse braziliaanse software!*pgModeler is proudly a brazilian software! AboutWidgetJEen aggregatie-funtie die de types <em><strong>typeA</strong></em> en <em><strong>typeB</strong></em> als invoer aanvaardt en waarvan het status-type <em><strong>status_type</strong></em> is. De volgende regels moeten voldaan zijn: <br/><br/> <strong>&nbsp;&nbsp;&nbsp; " Finale Functie:</strong> <em>void finale_functie(<strong>status_type</strong>)</em><br/> <strong>&nbsp;&nbsp;&nbsp; " Overgangsfunctie:</strong> <em><strong>status_type</strong> transitie_functie(<strong>status_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em>%An aggregate function that accepts the types typeA and typeB as input types and which type of state is state_type, must obey the following rules:

   • Final Function: void final_function(state_type)
   • Transition Function: state_type transition_function(state_type, typeA, typeB)AggregateWidgetFinale functie:Final Function:AggregateWidgetFunctie StaatFunction StateAggregateWidgetFunctie InvoerFuntion InputsAggregateWidget$Initile Vereiste:Initial Condition:AggregateWidget Invoer Data TypeInput Data TypeAggregateWidget"Sorteer-operator:Sort Operator:AggregateWidget Status Data TypeState Data TypeAggregateWidget"Overgangsfunctie:Transition Func.:AggregateWidget pt ptAppearanceConfigWidgetVetBoldAppearanceConfigWidgetKleuren:Colors:AppearanceConfigWidget,Kolom (fk): Kolom naamColumn (fk): Column nameAppearanceConfigWidget0Kolom (fk): BeschrijvingColumn (fk): DescriptorAppearanceConfigWidget,Kolom (nn): Kolom naamColumn (nn): Column nameAppearanceConfigWidget0Kolom (nn): BeschrijvingColumn (nn): DescriptorAppearanceConfigWidget,Kolom (pk): Kolom naamColumn (pk): Column nameAppearanceConfigWidget0Kolom (pk): BeschrijvingColumn (pk): DescriptorAppearanceConfigWidget,Kolom (uq): Kolom naamColumn (uq): Column nameAppearanceConfigWidget0Kolom (uq): BeschrijvingColumn (uq): DescriptorAppearanceConfigWidget"Kolom: Kolom naamColumn: Column nameAppearanceConfigWidget&Kolom: BeschrijvingColumn: DescriptorAppearanceConfigWidgetTKolom: Ingesloten / Overgerfd via relatie,Column: Included / Inherited by relationshipAppearanceConfigWidget Kolom: BeschermdColumn: ProtectedAppearanceConfigWidgetElement:Element:AppearanceConfigWidgetLettertype:Font:AppearanceConfigWidgetVensterFormAppearanceConfigWidgetDAlgemeen: Constraints beschrijvingGlobal: Constraints descriptorAppearanceConfigWidget(Algemeen: LettertypeGlobal: Font styleAppearanceConfigWidget$Algemeen: Lock arcGlobal: Lock arcAppearanceConfigWidget&Algemeen: Lock bodyGlobal: Lock bodyAppearanceConfigWidget2Algemeen: Object selectieGlobal: Object selectionAppearanceConfigWidget*Algemeen: Object-typeGlobal: Objects typeAppearanceConfigWidget4Algemeen: Positie hint boxGlobal: Position hint boxAppearanceConfigWidget8Algemeen: Positie hint tekstGlobal: Position hint textAppearanceConfigWidget&Index: BeschrijvingIndex: DescriptorAppearanceConfigWidgetIndex: Naam Index: NameAppearanceConfigWidgetCursiefItalicAppearanceConfigWidget>Relatie: Attribuut beschrijving"Relationship: Attribute descriptorAppearanceConfigWidget0Relatie: Attribuut tekstRelationship: Attribute textAppearanceConfigWidget*Relatie: BeschrijvingRelationship: DescriptorAppearanceConfigWidget$Relatie: Label boxRelationship: Label boxAppearanceConfigWidget(Relatie: Label tekstRelationship: Label textAppearanceConfigWidget&Regel: BeschrijvingRule: DescriptorAppearanceConfigWidgetRegel: Naam Rule: NameAppearanceConfigWidget Tabel: Kolom boxTable: Columns boxAppearanceConfigWidgetBTabel: Uitgebreide attributen boxTable: Extended attributes boxAppearanceConfigWidget"Tabel: SchemanaamTable: Schema nameAppearanceConfigWidget Tabel: TabelnaamTable: Table nameAppearanceConfigWidget Tabel: Titel boxTable: Title boxAppearanceConfigWidgetTag: Inhoud Tag: BodyAppearanceConfigWidgetTag: Naam Tag: NameAppearanceConfigWidget"Tekst box: Inhoud Textbox: BodyAppearanceConfigWidget*Trigger: BeschrijvingTrigger: DescriptorAppearanceConfigWidgetTrigger: Naam Trigger: NameAppearanceConfigWidgetOnderstrepen UnderlineAppearanceConfigWidget@View: Uitgebreide attributen boxView: Extended attributes boxAppearanceConfigWidget8View: ReferentiebeschrijvingView: Reference descriptorAppearanceConfigWidget0View: Gerefereerde kolomView: Referenced columnAppearanceConfigWidget0View: Gerefereerde tabelView: Referenced tableAppearanceConfigWidget*View: Referenties boxView: References boxAppearanceConfigWidget View: SchemanaamView: Schema nameAppearanceConfigWidget2View: Tabel / Kolom aliasView: Table / columns aliasAppearanceConfigWidgetView: Titel boxView: Title boxAppearanceConfigWidgetView: View-naamView: View nameAppearanceConfigWidgetPDe initile configuratie kon niet worden gecreerd in `%1'! Kijk na of de huidige gebruiker schrijf-machtigingen heeft op dit pad en minstens lees-machtigingen op '%2'.Failed to create initial configuration in `%1'! Check if the current user has write permission over that path and at least read permission over `%2'. ApplicationFEen onbekende uitzondering trad op!Unknown exception caught! Application&Toepassen&ApplyBaseForm&Annuleren&CancelBaseForm&Ok&OkBaseFormDialoogvensterDialogBaseFormAggregator Aggregate BaseObjectBasisrelatieBasic Relationship BaseObjectCastCast BaseObjectSortering Collation BaseObject KolomColumn BaseObjectConstraint Constraint BaseObjectConversie Conversion BaseObjectDatabaseDatabase BaseObject DomeinDomain BaseObjectEvent Trigger Event Trigger BaseObjectUitbreiding Extension BaseObjectFunctieFunction BaseObject IndexIndex BaseObjectTaalLanguage BaseObjectOperatorOperator BaseObjectOperator KlasseOperator Class BaseObject Operator FamilieOperator Family BaseObjectParameter Parameter BaseObjectMachtiging Permission BaseObjectRelatie Relationship BaseObjectRolRole BaseObject RegelRule BaseObject SchemaSchema BaseObjectSequentieSequence BaseObject TabelTable BaseObjectTablespace Tablespace BaseObjectTagTag BaseObjectTekst boxTextbox BaseObjectTriggerTrigger BaseObjectTypeType BaseObjectType AttribuutType Attribute BaseObjectViewView BaseObjectnieuw_objectnieuwe_objecten new_object BaseObjectSQL uitSQL offBaseObjectViewzVoeg SQL commando toe voor of na de definitie van het object.CAppend or prepend a set of SQL commands to the object's definition.BaseObjectWidgetSortering: Collation:BaseObjectWidgetCommentaar:Comment:BaseObjectWidgetAangepaste SQL Custom SQLBaseObjectWidget2Niet-uitvoerbare SQL codeDisable SQL codeBaseObjectWidgetRMaakt de gegenereerde SQL code onuitvoerbaar via comment-tokens (--). Dit zorgt ervoor dat de code voor alle kinder-objecten en refererende objecten wordt uitgeschakeld.xDisables the generated SQL code using comment tokens (--). This will disable the code of all child and referrer objects.BaseObjectWidgetJMachtiginen voor dit object aanpassenEdit object's permissionsBaseObjectWidget,Machtigingen aanpassenEdit permissionsBaseObjectWidgetID:ID:BaseObjectWidget Naam:Name:BaseObjectWidgetEigenaar:Owner:BaseObjectWidgetrVereist veld. Dit veld leeglaten leidt tot foutmeldingen!5Required field. Leaving this empty will raise errors!BaseObjectWidgetSchema:Schema:BaseObjectWidgetTablespace: Tablespace:BaseObjectWidgetDit object is beschermd en dus worden vorm-aanpassingen niet toegepast.FThis object is protected thus no change in form will be applied to it.BaseObjectWidgetWaarde(s)Value(s)BaseObjectWidget VersieVersionBaseObjectWidget iconeiconeBaseObjectWidgetrel_%1_%2 rel_%1_%2BaseRelationship,Verbonden relaties: %1Connected rels: %1 BaseTableView&Annuleren&Cancel BugReportForm...... BugReportForm<html><head/><body><p>Indien u wenst kan u bugs ook rapporten via pgModeler's project repository op <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html>

If you prefer it's possible to report this issue anytime on pgModeler's project repository at GitHub.

 BugReportFormBVoeg een ander database model toe!Attach a different database model BugReportForm~Voeg het database model waarmee het probleem zich voordoet toe.4Attach the below database model file to be debugged. BugReportFormBug Rapport Bug Report BugReportFormBug rapport Bug report BugReportFormfHet bug rapport werd gegeneerd! Gelieve het bestand <strong>%1</strong> naar <em>%2</em> te sturen zodat het kan worden gebruikt bij het debuggen. Hartelijk dank voor je bijdrage!Bug report successfuly generated! Please, send the file %1 to %2 in order be analyzed. Thank you for the collaboration! BugReportFormVersturenCreate BugReportFormDatabase ModelDatabase Model BugReportFormXDatabase model (*.dbm);;Alle bestanden (*.*)'Database model (*.dbm);;All files (*.*) BugReportForm$Probleeminformatie Issue details BugReportFormLaad model Load model BugReportFormOutput:Output: BugReportFormRapportReport BugReportForm@Selecteer de rapport-uitvoer mapSelect report output folder BugReportFormPSelecteer de output-map voor het rapport!Select the report's output folder BugReportForm.Gebruik dit formulier om een volledig bug rapport aan te maken. Gelieve zo volledig en duidelijk mogelijk de actie die tot de bug leidden, te beschrijven. Indien mogelijk, voeg een voorbeeld database model toe aan dit rapport zodat de bug snel gevonden en gecorigeerd kan worden!Use the form below to generate a complete bug report. Please, try to be as clear as possible when describing the actions that can reproduce the bug. Additionally, it's important to attach a sample database model so that the bug can be quickly discovered and fixed! BugReportFormToewijzing Assignment CastWidgetCast Type: Cast Type: CastWidget$Conversie-functie:Conversion Func.: CastWidget Invoer / UitvoerInput / Output CastWidgetBron data typeSource data type CastWidgetDoel data typeTarget data type CastWidgetDe functie die wordt gebruikt bij den cast van <em><strong>typeA</strong></em> naar <em><strong>typeB</strong></em> moet de volgende signature hebben:: <em><strong>typeB</strong> functie(<strong>typeA</strong>, integer, boolean)</em>.The function to be assigned to a cast from typeA to typeB must have the following signature: typeB function(typeA, integer, boolean). CastWidget,(geen items gevonden.)(no items found.)CodeCompletionWidgetZorgt ervoor dat widgets enkel kunnen worden gesloten via de ESC toets of via een muisklik op andere controls.KMakes the widget closable only by ESC key or mouse click on other controls.CodeCompletionWidget SQL Sleutelwoord SQL KeywordCodeCompletionWidgetCodering: Encoding:CollationWidget LC_COLLATE:CollationWidget LC_CTYPE:CollationWidgetLocale:Locale:CollationWidget"Niet gedefinieerd Not definedCollationWidgetDe velden <strong><em>Sortering</em></strong>, <strong><em>Locale</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> zijn onderling uitsluitend, om een sortering correct te gebruiken hoeft u slechts n van deze velden in te stellen.The fields Collation, Locale, LC_COLLATE & LC_CTYPE are mutually exclusive, so you have to set only one of them in order to properly handle a collation.CollationWidget Alt+RAlt+RColorPickerWidgetVensterFormColorPickerWidget>Genereer willekeurige kleur(en)Generate random color(s)ColorPickerWidgetSelecteer kleur Select colorColorPickerWidget Standaardwaarde:Default Value: ColumnWidget&Toepassen&ApplyConfigurationForm&Annuleren&CancelConfigurationFormDe waarden in de huidige sectie zullen worden overschreven! Bent u er zeker van dat u de standaard waarden wilt instellen?tAny modification made until now in the current section will be lost! Do you really want to restore default settings?ConfigurationFormVoorkomen AppearanceConfigurationFormVerbindingen ConnectionsConfigurationForm"Standaard waardenDefaultsConfigurationFormAlgemeenGeneralConfigurationFormPlug-insPlug-insConfigurationFormRelaties RelationshipsConfigurationFormSnippetsSnippetsConfigurationForm,pgModeler ConfiguratiepgModeler ConfigurationConfigurationFormAC verificatieAC verificationConnectionsConfigWidgetToevoegenAddConnectionsConfigWidgetToegelatenAllowConnectionsConfigWidget Auto browseConnectionsConfigWidget"Bladert automatisch door de genoemde database wanneer deze verbinding wordt gebruikt om databases te beheren via de <strong>Beheer</strong> view.xAutomatically browses the named database when using this connection to manage databases on Manage view.ConnectionsConfigWidget*Annuleer aanpassingenCancel editionConnectionsConfigWidget&Client Certificaat:Client Certificate:ConnectionsConfigWidgetClient Sleutel: Client Key:ConnectionsConfigWidget"Verbindingsalias:Connection Alias:ConnectionsConfigWidgetVerbinding DB:Connection DB:ConnectionsConfigWidgetVerbindingen: Connections:ConnectionsConfigWidget4Maak een nieuwe verbindingCreate new connectionConnectionsConfigWidgetJVerwijder de geselecteerde verbindingDelete selected connectionConnectionsConfigWidgetDiffDiffConnectionsConfigWidgetUitDisableConnectionsConfigWidgetJDupliceer de geselecteerde verbinding!Duplicate the selected connectionConnectionsConfigWidgetFPas de geselecteerde verbinding aanEdit selected connectionConnectionsConfigWidgetExporteerExportConnectionsConfigWidgetForceer GSSAPI Force GSSAPIConnectionsConfigWidget4%1 verbinding(en) gevondenFound %1 connection(s)ConnectionsConfigWidget*Volledige verificatieFull verificationConnectionsConfigWidgetAlgemeenGeneralConnectionsConfigWidgetHost/Poort: Host/Port:ConnectionsConfigWidgetImporterenImportConnectionsConfigWidget4Geen verbindingen gevondenNo connections foundConnectionsConfigWidgetWachtwoord: Password:ConnectionsConfigWidgetVereistRequireConnectionsConfigWidget Herroepen Certs:Revoked Certs.:ConnectionsConfigWidget"Root Certificaat:Root Certificate:ConnectionsConfigWidgetSSL Modus: SSL Mode:ConnectionsConfigWidgetSuccessSuccessConnectionsConfigWidgetTestTestConnectionsConfigWidgetWenst u de nieuwe of aan te passen verbinding op te slaan vooraleer verder te gaan?FThere is a connection being created or edited! Do you want to save it?ConnectionsConfigWidgetTimeout:Timeout:ConnectionsConfigWidgetUpdatenUpdateConnectionsConfigWidgetGebruiker:User:ConnectionsConfigWidgetSecond(en) second(s)ConnectionsConfigWidget~/.postgresql/postgresql.crtConnectionsConfigWidget~/.postgresql/postgresql.keyConnectionsConfigWidget~/.postgresql/root.crlConnectionsConfigWidget~/.postgresql/root.crtConnectionsConfigWidget KolomColumnConstraintWidget Kolom:Column:ConstraintWidgetKolommenColumnsConstraintWidget Kolommen die werden ingesloten via relaties kunnen niet manueel worden toegevoegd aan of verwijderd uit de primaire sleutel. Dit soort aanpassingen kan tot fouten leiden. Om een primaire sleutel aan te maken via kolommen die werden ingesloten door relaties, gebruik de volgende opties: identifier veld, attributen & constraints tab-blad of primaire sleutel tab=blad in het relatie-venster.EColumns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form.ConstraintWidget Constraint Type:Constraint Type:ConstraintWidgetUitstelbaar: Deferrable:ConstraintWidgetUitstel: Deferral:ConstraintWidget(Elementen UitsluitenExclude ElementsConstraintWidgetExpressie: Expression:ConstraintWidgetVul-factor: Fill Factor:ConstraintWidgetIndexering: Indexing:ConstraintWidgetEvenaar:Match:ConstraintWidget Geen overerving: No inherit:ConstraintWidget ON DELETE:ConstraintWidget ON UPDATE:ConstraintWidget*Gerefereerde KolommenReferenced ColumnsConstraintWidget Tabel:Table:ConstraintWidgetDit attribuut kan niet worden aangepast eens het object is aangemaakt.void functie(integer, integer, cstring, internal, integet)</em>.The function to be assigned to an encoding conversion must have the following signature: void function(integer, integer, cstring, internal, integer).ConversionWidgetRBug rapport analyze modus is geactiveerd.#Bug report analysis mode activated.CrashHandlerFormCrash Handler Crash HandlerCrashHandlerFormCrash Handler Crash handlerCrashHandlerFormXDatabase model (*.dbm);;Alle bestanden (*.*)'Database model (*.dbm);;All files (*.*)CrashHandlerFormInvoer:Input:CrashHandlerFormLaad rapport Load reportCrashHandlerFormBLaad rapport bestand voor analyzeLoad report file for analysisCrashHandlerForm0Oeps! pgModeler crashte!Oops! pgModeler just crashed!CrashHandlerFormBewaar model Save modelCrashHandlerFormvBewaar het ingevoegde model bestaand op het bestandssysteem.Save the attached model file on the filesystemCrashHandlerFormStack trace Stack traceCrashHandlerForm^We verontschuldigen ons voor wat net gebeurde! Het is overduidelijk dat een ernstige bug dit veroorzaakte. Gelieve het formuleer hieronder in te vullen met een beschrijving van wat u deed vooraleer pgModeler onverwachts afsloot. Dit zal ons helpen om deze bug te corrigeren en de software te verbeteren.We apologize for what happened! It is clear that a nasty bug caused that. Please fill out the form below describing your actions before pgModeler quit unexpectedly. This will help on bug extermination and improve the software.CrashHandlerFormfpgModeler bug rapport (*.bug);;Alle bestanden (*.*)-pgModeler bug report (*.bug);;All files (*.*)CrashHandlerForm...... CsvLoadWidgetVensterForm CsvLoadWidget LadenLoad CsvLoadWidget0Selecteer uitvoerbestandSelect output file CsvLoadWidget SpatieSpace CsvLoadWidget&Leegmaken&ClearCustomSQLWidget&DELETE&DELETECustomSQLWidget&INSERT&INSERTCustomSQLWidget&SELECT&SELECTCustomSQLWidget&UPDATE&UPDATECustomSQLWidget<html><head/><body><p>Wees voorzichtig bij het gebruik van aangepaste SQL. Dit kan leiden tot een verandering van de betekenis van het volledige model wanneer SQL validatie wordt uigevoerd of wanneer het model wordt gexporteerd. Het is ook mogelijk, afhankelijk van de hoeveelheid commando's, dat de prestaties van deze processen voelbaar en negatief kunnen worden benvloed.</p></body></html>-

Use custom commands with extreme caution because you can change the semantics of the entire model when running SQL validation or export processes. Additionally, depending on the amount of commands, those processes can have their performance sensibly degradated.

CustomSQLWidgetNagevoegde SQL Append SQLCustomSQLWidgetZVoeg toe aan het einde van de modeldefinitie."Append at end of model definition.CustomSQLWidget&Plaats de SQL code op het einde van de modeldefinitie. Deze optie afvinken zorgt ervoor dat de SQL wordt ingevoegd na het CREATE DATABASE commando.Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command.CustomSQLWidget4Sluit serile kolommen uitExclude serial columnsCustomSQLWidget"Generische DELETEGeneric DELETECustomSQLWidget"Generische INSERTGeneric INSERTCustomSQLWidget"Generische SELECTGeneric SELECTCustomSQLWidget"Generische UPDATEGeneric UPDATECustomSQLWidget2Sluit serile kolommen inInclude serial columnsCustomSQLWidget Voorgevoegde SQL Prepend SQLCustomSQLWidgetZVoeg toe aan het begin van de modeldefinitie.)Prepend at beginning of model definition.CustomSQLWidgetPlaatst een DELETE commando-sjabloon op de huidige positie van de cursor.;Puts an DELETE command template at current cursor position.CustomSQLWidgetPlaatst een INSERT commando-sjabloon op de huidige positie van de cursor.;Puts an INSERT command template at current cursor position.CustomSQLWidgetPlaatst een SELECT commando-sjabloon op de huidige positie van de cursor.;Puts an SELECT command template at current cursor position.CustomSQLWidgetPlaatst een UPDATE commando-sjabloon op de huidige positie van de cursor.;Puts an UPDATE command template at current cursor position.CustomSQLWidgetSQL codeSQL codeCustomSQLWidgetTabel DELETE Table DELETECustomSQLWidgetTabel SELECT Table SELECTCustomSQLWidgetTabel UPDATE Table UPDATECustomSQLWidget&Sluiten&CloseDataManipulationFormL<em>(Limiet: <strong>%1</strong>)</em>%(Limit: %1)DataManipulationForm<strong>OPGEPAST: </strong> Eens toegepast is het niet langer mogelijk om aanpassingen ongedaan te maken! Bent u zeker dat u wilt opslaan?bWARNING: Once commited its not possible to undo the changes! Proceed with saving?DataManipulationFormASCASCDataManipulationFormItem ToevoegenAdd ItemDataManipulationFormDMaak de sorterings-kolomlijst leegClear the order by columns listDataManipulationForm KolomColumnDataManipulationForm Kolom:Column:DataManipulationForm Ctrl+ECtrl+EDataManipulationForm Ctrl+SCtrl+SDataManipulationForm Ctrl+VCtrl+VDataManipulationForm Ctrl+XCtrl+XDataManipulationForm Ctrl+ZCtrl+ZDataManipulationFormDESCDESCDataManipulationFormDatamanipulatieData ManipulationDataManipulationFormDelDelDataManipulationFormXExporteer de resultaten naar een CSV bestandExport results to CSV fileDataManipulationFormF5F5DataManipulationFormFilterexpressieFilter expressionDataManipulationForm(Filter de resultatenFilter the result setDataManipulationForm,%1 object(en) gevondenFound %1 object(s)DataManipulationFormVerberg views Hide viewsDataManipulationFormInsInsDataManipulationFormLimiet in: Limit in:DataManipulationFormbMarkeer de geselecteerde rij als 'te verwijderen'$Mark the selected rows to be deletedDataManipulationFormZVerplaats het geselecteerde item naar benedenMove selected item downDataManipulationFormVVerplaats het geselecteerde item naar bovenMove selected item upDataManipulationForm,Geen objecten gevondenNo objects foundDataManipulationForm&Sortering && LimietOrder && LimitDataManipulationForm0De lijst wordt vernieuwdRefresh listingDataManipulationForm Item Verwijderen Remove ItemDataManipulationForm(Aanpassingen opslaan Save changesDataManipulationFormSchema:Schema:DataManipulationForm Tabel:Table:DataManipulationFormDe geselecteerde tabel bevat geen primary key! Update en delete commando's worden uitgevoerd door alle kolommen als primary key te beschouwen. <strong>OPGEPAST</strong> deze acties kunnen meer dan n rij benvloeden.The selected table doesn't owns a primary key! Updates and deletes will be performed by considering all columns as primary key. WARNING: those operations can affect more than one row.DataManipulationForm<Deze rij is als %1 gemarkeerd.This row is marked to be %1DataManipulationForm6Aanpassingen ongedaan makenUndo modificationsDataManipulationFormData van views kan niet worden aangepast via dit raster, alle operaties zijn uitgeschakeld.]Views can't have their data handled through this grid, this way, all operations are disabled.DataManipulationForm[binaire data] [binary data]DataManipulationForm deletedeleteDataManipulationFormverwijderddeletedDataManipulationForminin DataManipulationForm insertinsertDataManipulationFormingevoegdinsertedDataManipulationForm updateupdateDataManipulationFormaangepastupdatedDataManipulationForm0(niet gevonden, OID: %1)(not found, OID: %1)DatabaseExplorerWidget......DatabaseExplorerWidgetV<strong>PAS OP:</strong> U staat op het punt om de volledige database <strong>%1</strong> te verwijderen! Alle data zal verloren gaan. Bent u zeker dat u verder wilt gaan?CAUTION: You are about to drop the entire database %1! All data will be completely wiped out. Do you really want to proceed?DatabaseExplorerWidgetAdmin. rollen Admin. rolesDatabaseExplorerWidgetUitlijning AlignmentDatabaseExplorerWidget Alt+GAlt+GDatabaseExplorerWidgetAnalyzeer func. Analyze func.DatabaseExplorerWidget"Aantal Argumenten Arg. countDatabaseExplorerWidget2Standaard aantal argumentArg. default countDatabaseExplorerWidget&Standaardargumenten Arg. defaultsDatabaseExplorerWidgetArgumentenmodus Arg. modesDatabaseExplorerWidgetArgumentennamen Arg. namesDatabaseExplorerWidgetArgumententypes Arg. typesDatabaseExplorerWidgetArgumenten ArgumentsDatabaseExplorerWidgetAttribuut AttributeDatabaseExplorerWidgetGedragstype Behavior typeDatabaseExplorerWidgetPer OIDBy OIDDatabaseExplorerWidgetPer waardeBy valueDatabaseExplorerWidgetCachewaarde Cache valueDatabaseExplorerWidgetKan inloggen Can loginDatabaseExplorerWidget Canonische func.Canonical func.DatabaseExplorerWidgetCast type Cast typeDatabaseExplorerWidgetCategorieCategoryDatabaseExplorerWidget(Alle items inklappenCollapses all itemsDatabaseExplorerWidgetSorteerbaar CollatableDatabaseExplorerWidgetSortering CollationDatabaseExplorerWidgetSorteringen CollationsDatabaseExplorerWidgetKolommenColumnsDatabaseExplorerWidgetCommando'sCommandsDatabaseExplorerWidgetCommentaarCommentDatabaseExplorerWidgetCommutator Op.Commutator Op.DatabaseExplorerWidget"VergelijkingstypeComparison typeDatabaseExplorerWidgetVoorwaarde ConditionDatabaseExplorerWidgetConfiguratie ConfigurationDatabaseExplorerWidget"Verbindingslimiet Conn. limitDatabaseExplorerWidgetConstraint ConstraintDatabaseExplorerWidgetMaak DB aan Create DBDatabaseExplorerWidgetMaak rol aan Create roleDatabaseExplorerWidgetCtrl+F6Ctrl+F6DatabaseExplorerWidgetHuidige versie Curr. versionDatabaseExplorerWidget CyclusCycleDatabaseExplorerWidgetData &Grid Data &GridDatabaseExplorerWidgetStandaardDefaultDatabaseExplorerWidgetStandaardwaarde Default valueDatabaseExplorerWidgetUitstel DefermentDatabaseExplorerWidgetUitstelbaar DeferrableDatabaseExplorerWidgetDefinitie DefinitionDatabaseExplorerWidgetDelimiter DelimiterDatabaseExplorerWidgetDoelcoderingDest. encodingDatabaseExplorerWidgetDoeltype Dest. typeDatabaseExplorerWidgetDimensie DimensionDatabaseExplorerWidgetMap DirectoryDatabaseExplorerWidgetBent u er zeker van dat u het object &lt;strong&gt;%1&lt;/strong&gt; &lt;em&gt;(%2)&lt;/em&gt; via &lt;strong&gt;cascade&lt;/strong&gt; wilt verwijderen? Deze actie verwijdert ook alle objecten die afhankelijk zijn van dit object.Do you really want to cascade drop the object %1 (%2)? This action will drop all the other objects that depends on it.DatabaseExplorerWidgetBent u er zeker van dat u de tabel <strong>%1</strong> <em>(%2)</em> via <strong>cascade</strong> wilt verwijderen? Deze actie verwijdert ook alle tabellen die afhankelijk zijn van deze tabel.Do you really want to cascade truncate the table %1? This action will truncate all the tables that depends on it?DatabaseExplorerWidgetBent u zeker dat u het object <strong>%1</strong> <em>%2</em> wilt verwijderen?HDo you really want to drop the object %1 (%2)?DatabaseExplorerWidget|Bent u zeker dat u de tabel <strong>%1</strong> wil truncaten?=Do you really want to truncate the table %1?DatabaseExplorerWidget"Verwijder cascade Drop cascadeDatabaseExplorerWidget Verwijder object Drop objectDatabaseExplorerWidget.Verwijder deze databaseDrop this databaseDatabaseExplorerWidgetElementElementDatabaseExplorerWidgetCoderingEncodingDatabaseExplorerWidgetGencrypteerd EncryptedDatabaseExplorerWidgetEnumeraties EnumerationsDatabaseExplorerWidget EventEventDatabaseExplorerWidgetUitvoeringskost Exec. costDatabaseExplorerWidget UitvoeringsmodusExecution modeDatabaseExplorerWidget*Alle items uitklappenExpands all itemsDatabaseExplorerWidgetExpressie ExpressionDatabaseExplorerWidgetExpressies ExpressionsDatabaseExplorerWidgetVulfactor Fill factorDatabaseExplorerWidgetFilter:Filter:DatabaseExplorerWidgetFinale functie Final func.DatabaseExplorerWidgetAfvuringFiringDatabaseExplorerWidgetVoor elke rij For each rowDatabaseExplorerWidgetVensterFormDatabaseExplorerWidgetFunctietype Func. typeDatabaseExplorerWidgetFunctieFunctionDatabaseExplorerWidget(Behandelende Functie Handler func.DatabaseExplorerWidgetBehandelt type Handles typeDatabaseExplorerWidget HashesHashesDatabaseExplorerWidgetI/O castI/O castDatabaseExplorerWidgetToename IncrementDatabaseExplorerWidgetIndextype Index typeDatabaseExplorerWidgetErft overInheritDatabaseExplorerWidgetOvergerfd InheritedDatabaseExplorerWidget$Initile Vereiste:Ini. conditionDatabaseExplorerWidgetInline Functie Inline func.DatabaseExplorerWidgetInvoerfunctie Input func.DatabaseExplorerWidgetInterne lengteInternal lengthDatabaseExplorerWidgetIntervalstype Interval typeDatabaseExplorerWidgetJoin func. Join func.DatabaseExplorerWidgetLC COLLATE LC COLLATEDatabaseExplorerWidgetLC CTYPELC CTYPEDatabaseExplorerWidgetTaalLanguageDatabaseExplorerWidgetLaatste waarde Last valueDatabaseExplorerWidgetLekdicht Leak proofDatabaseExplorerWidgetLinkse type Left typeDatabaseExplorerWidget LengteLengthDatabaseExplorerWidgetBibliotheekLibraryDatabaseExplorerWidget Gematerialiseerd MaterializedDatabaseExplorerWidgetMax. waarde Max. valueDatabaseExplorerWidgetLid-rollen Member rolesDatabaseExplorerWidgetSamenvoegingenMergesDatabaseExplorerWidgetMin. waarde Min. valueDatabaseExplorerWidgetNaamNameDatabaseExplorerWidgetNegator op. Negator op.DatabaseExplorerWidgetGeen overerving No inheritDatabaseExplorerWidgetNiet nullNot nullDatabaseExplorerWidgetOIDOIDDatabaseExplorerWidgetObjecttype Object typeDatabaseExplorerWidgetOude versie Old versionDatabaseExplorerWidgetBij delete On deleteDatabaseExplorerWidgetBij insert On insertDatabaseExplorerWidgetBij truncate On truncateDatabaseExplorerWidgetBij update On updateDatabaseExplorerWidgetOp. klasse Op. classDatabaseExplorerWidgetOp. klasses Op. classesDatabaseExplorerWidget Operator Familie Op. familyDatabaseExplorerWidgetOperatorOperatorDatabaseExplorerWidget Operator functieOperator func.DatabaseExplorerWidgetOperators OperatorsDatabaseExplorerWidgetUitvoerfunctie Output func.DatabaseExplorerWidgetEigenaarOwnerDatabaseExplorerWidget Bezittende kolom Owner columnDatabaseExplorerWidget OudersParentsDatabaseExplorerWidgetWachtwoordPasswordDatabaseExplorerWidgetMachtigingen PermissionsDatabaseExplorerWidgetPositiePositionDatabaseExplorerWidgetPrecisie PrecisionDatabaseExplorerWidgetPredicaat PredicateDatabaseExplorerWidgetVoorkeur PreferredDatabaseExplorerWidget"OmvangsattributenRange attributesDatabaseExplorerWidget"Ontvangersfunctie Receive func.DatabaseExplorerWidgetRef. columns Ref. columnsDatabaseExplorerWidgetRef. rollen Ref. rolesDatabaseExplorerWidgetRef. tabel Ref. tableDatabaseExplorerWidget,Eigenschappen herladenReload propertiesDatabaseExplorerWidgetHernoemRenameDatabaseExplorerWidgetReplicatie ReplicationDatabaseExplorerWidget&BelemmeringsfunctieRestriction func.DatabaseExplorerWidgetResultaatstype Return typeDatabaseExplorerWidget"Geeft SETOF terug Returns SETOFDatabaseExplorerWidgetRechtse type Right typeDatabaseExplorerWidget RollenRolesDatabaseExplorerWidgetAantal rijen Rows amountDatabaseExplorerWidget SchemaSchemaDatabaseExplorerWidget Beveiligingstype Security typeDatabaseExplorerWidgetZendfunctie Send func.DatabaseExplorerWidgetToon data Show dataDatabaseExplorerWidgetSnippetsSnippetsDatabaseExplorerWidgetSorteeroperatoSort op.DatabaseExplorerWidgetBroncode Source codeDatabaseExplorerWidgetBrontype Source typeDatabaseExplorerWidgetBroncodering Src. encodingDatabaseExplorerWidgetStartwaarde Start valueDatabaseExplorerWidgetStatustype State typeDatabaseExplorerWidget OpslagStorageDatabaseExplorerWidgetSubtypeSubtypeDatabaseExplorerWidget$Subtype diff func.Subtype diff func.DatabaseExplorerWidgetSuperuser SuperuserDatabaseExplorerWidget TabelTableDatabaseExplorerWidgetTablespace TablespaceDatabaseExplorerWidget TransitiefunctieTransition func.DatabaseExplorerWidgetTrigger func. Trigger func.DatabaseExplorerWidgetTrunc. cascadeTrunc. cascadeDatabaseExplorerWidgetTruncateTruncateDatabaseExplorerWidgetVertrouwdTrustedDatabaseExplorerWidgetTypeTypeDatabaseExplorerWidgetTypeattribuutType attributeDatabaseExplorerWidget(Type mod. in functieType mod. in func.DatabaseExplorerWidget0Type mod. buiten functieType mod. out func.DatabaseExplorerWidget TypesTypesDatabaseExplorerWidget UniekUniqueDatabaseExplorerWidgetNiet geloggedUnloggedDatabaseExplorerWidgetUpdatenUpdateDatabaseExplorerWidget ValidatiefunctieValidator func.DatabaseExplorerWidgetGeldigheidValidityDatabaseExplorerWidget WaardeValueDatabaseExplorerWidgetOpgepastWarningDatabaseExplorerWidgetWindowing func. Windows func.DatabaseExplorerWidgetMet OIDs With OIDsDatabaseExplorerWidgetDit is een demonstratie-versie. De data manipulatie functionaliteit is enkel beschikbaar in de volledige versie!lYou're running a demonstration version! The data manipulation feature is available only in the full version!DatabaseExplorerWidget onwaarfalseDatabaseExplorerWidgetwaartrueDatabaseExplorerWidget&Sluiten&CloseDatabaseImportForm&ImportDatabaseImportForm......DatabaseImportForm<strong>OPGEPAST:</strong> U staat op het punt om objecten te importeren in het huidige model! Deze actie zal onherroepbare verandering teweegbrengen, zelfs wanneer kritische problemen opduiken gedurende dit proces. Bent u zeker dat u verder wilt gaan?ATTENTION: You are about to import objects to the current working model! This action will cause irreversible changes to it even in case of critical errors during the process. Do you want to proceed?DatabaseImportFormAlle catalogusqueries plus the broncode van de aangemaakte objecten wordt naar de standaard output (stdout) geprint.eAll catalog queries as well the created objects' source code are printed to standard output (stdout).DatabaseImportFormFLos afhankelijkheden automatisch op"Automatically resolve dependenciesDatabaseImportFormPer OIDBy OIDDatabaseImportFormAnnulerenCancelDatabaseImportForm>Maak de objectselectie ongedaanClear object selectionDatabaseImportForm(Alle items inklappenCollapses all itemsDatabaseImportFormVerbinding: Connection:DatabaseImportFormMaak alle gemporteerde objecten aan in het huidige model en maak geen nieuw model aan.UCreate all imported objects in the current working model instead of create a new one.DatabaseImportFormDatabaseDatabaseDatabaseImportFormDebugmodus Debug modeDatabaseImportFormActiveert het importeren van objecten die werden aangemaakt door uitbreidingen. Algemeen gezien is er geen nood om deze optie aan te vinken tenzij er objecten in de databse leven die onmiddellijk naar objecten van deze categorie refereren.Enables the import of objects created by extensions. Generally there is no need to check this option but if there are objects in the database that directly references this category of objects this mode must be enabled.DatabaseImportFormActiveert het importeren van ingebouwde systeemobjecten. Het is aangeraden om enkel objecten te importeren waarnaar onmiddellijk worden gerefereerd. PAS OP: grote hoeveelheden systeemobjecten importeren kan leiden tot een opgezwollen resultaatsmodel of kan zelfs pgModeler tot een crash leiden omwillen van geheugen- of processor-uitputting.Enables the import of system built-in objects. It's recommend to select only those objects that are directly referenced by the ones to be imported. WARNING: Try to import a huge set of system objects can bloat the resultant model or even crash pgModeler due to memory/cpu overuse.DatabaseImportForm*Alle items uitklappenExpands all itemsDatabaseImportForm6Filter objecten per hun OIDFilter object by it's OIDDatabaseImportFormFilter:Filter:DatabaseImportFormFEr werd(en) %1 database(s) gevondenFound %1 database(s)DatabaseImportForm,Negeer importeerfoutenIgnore import errorsDatabaseImportForm<Importeer uitbreidingsobjectenImport extension objectsDatabaseImportFormTImporteer de objecten in het huidige model#Import objects to the working modelDatabaseImportForm2Importeer systeemobjectenImport system objectsDatabaseImportFormDHet import proces werd afgebroken!Importing process aborted!DatabaseImportFormjHet import proces werd geannuleerd door de gebruiker!#Importing process canceled by user!DatabaseImportFormVHet import proces werd succesvol beindigt!#Importing process sucessfuly ended!DatabaseImportForm2Er werd database gevondenNo databases foundDatabaseImportForm OptiesOptionsDatabaseImportFormUitvoerOutputDatabaseImportForm(Vooruitgangslabel...Progress label...DatabaseImportFormDWillekeurige kleuren voor relatiesRandom colors for relationshipsDatabaseImportForm^Om de identificatie van de links tussen tabellen in grote modellen makkelijker te maken zullen willekeurige kleuren worden gebruikt om de gemporteerde relaties aan te duiden.Random colors will be assigned to imported relationships facilitating the identification of links between tables mainly in large models.DatabaseImportFormbDe objecten op cluster-niveau worden opgehaald...#Retrieving cluster level objects...DatabaseImportForm^De objecten worden van de database opgehaald...#Retrieving objects from database...DatabaseImportForm^De objecten uit schema `%1' worden opgehaald...$Retrieving objects of schema `%1'...DatabaseImportForm.Selecteer alle objectenSelect all objectsDatabaseImportFormInstellingenSettingsDatabaseImportFormDit is een ingebouwd type van PostgreSQL en kan niet worden gemporteerd.?This is a PostgreSQL built-in data type and cannot be imported.DatabaseImportFormDit is een ingebouwd object van pgModeler. Dit object wordt genegeerd indien aangevinkt door de gebruiker.MThis is a pgModeler's built-in object. It will be ignored if checked by user.DatabaseImportForm@pgModeler negeert importeerfouten en zal pogen om zoveel mogelijk objecten aan te maken. Door deze optie aan te vinken zal de importeer-taak niet afbreken bij een fout maar zal een onvolledig model worden aangemaakt. Deze optie creert een log bestand in de tijdelijke map voor pgModeler.pgModeler ignores import errors and will try to create as many as possible objects. By checking this option the import operation will be not aborted but an incomplete model will be constructed. This option generates a log file on pgModeler's temp directory.DatabaseImportForm:Kolommachtigingen aanmaken...Creating columns permissions...DatabaseImportHelper8Object aanmaken `%1' (%2)...Creating object `%1' (%2)...DatabaseImportHelper\Machtigingen aanmaken voor object `%1' (%2)...,Creating permissions for object `%1' (%2)...DatabaseImportHelperNTabel-overervingen worden aangemaakt...Creating table inheritances...DatabaseImportHelperXDe vrijstaande kolommen worden verwijderd...%Destroying unused detached columns...DatabaseImportHelperHet importeren faalde na `%1' pogingen om sommige objecten te her-creeren.5Import failed to recreate some objects in `%1' tries.DatabaseImportHelper0Objecten ophalen... `%1'Retrieving objects... `%1'DatabaseImportHelper>Systeemobjecten ophalen... `%1'!Retrieving system objects... `%1'DatabaseImportHelperHet importeren van de database is voltooid maar er werden enkele fouten gegenereerd, deze werden opgeslagen in het log-bestand `%1'. Dit bestand zal worden verwijderd wanneer u pgModeler afsluit.The database import ended but some errors were generated and saved into the log file `%1'. This file will last until pgModeler quit.DatabaseImportHelperRUpdaten van de relaties voor `%1' (%2)...&Updating relationships of `%1' (%2)...DatabaseImportHelperDObject `%1' (%2) wordt aangemaakt.Creating object `%1' (%2) DatabaseModel4Bezig met laden: `%1' (%2)Loading: `%1' (%2) DatabaseModelU kan slechts `%1' instancies per object type aanmaken in demonstratie-versies! U heeft deze limiet bereikt voor het type `%2'xThe demonstration version can create only `%1' instances of each object type! You've reach this limit for the type: `%2' DatabaseModelAttributen AttributesDatabaseWidgetSortering: Collation:DatabaseWidgetVerbindingen: Connections:DatabaseWidgetStandaardDefaultDatabaseWidget"StandaardobjectenDefault ObjectsDatabaseWidgetCodering: Encoding:DatabaseWidget LC_COLLATE:DatabaseWidget LC_CTYPE:DatabaseWidgetModelauteur: Model Author:DatabaseWidgetOpties:Options:DatabaseWidgetEigenaar:Owner:DatabaseWidgetSchema:Schema:DatabaseWidgetTablespace: Tablespace:DatabaseWidgetSjabloon DB: Template DB:DatabaseWidgetDe velden <strong>LC_COLLATE</strong> en <strong>LC_CTYPE</strong> hebben voorgedefinieerde waarden gebasseerd op het lopende systeem. Deze waarden kunnen vrij worden aangepast indien u dit model naar een andere host wenst te exporteren.The fields LC_COLLATE and LC_CTYPE have pre-configured values based upon the running system. You can freely modify those values if you intend to export the model to another host.DatabaseWidgetGebruik de velden hierboven om de waarden voor standaard attributen die aan nieuwe objecten worden toegewezen, te specifieren. Het veld leeglaten zorgt ervoor dat PostgreSQL zijn standaardwaarden gebruikt bij het exporteren.Use the above fields to specify the default attributes assigned to new objects created on the database model. Leaving a field empty will cause PostgreSQL to use the default values when exporting the model.DatabaseWidgetAttributen Attributes DomainWidget Standaardwaarde:Default Value: DomainWidgetExpressie Expression DomainWidgetExpressie: Expression: DomainWidgetNaamName DomainWidget Naam:Name: DomainWidgetNiet nullNot null DomainWidget...... DonateWidgetr<html><head/><body><p>pgModeler komt tot stand dankzij <span style=" font-style:italic;">een grote inzet om een kwaliteitsvol product te bezorgen</span>. Dit project heeft een niveau van volwassenheid bereikt die nooit was voorzien. Dit alles is het resultaat van de samenwerken tussen de auteur(s) en de <span style=" font-weight:600;">Open Source gemeenschap</span>. <br/><br/>Dit product heeft nog een lange weg af te leggen; met uw hulp kunnen we deze uitdaging aan en kunnen we nieuwe verbeteringen en toevoegingen aan dit product blijven publiceren bij elke release. Als u vertrouwd op pgMOdeler en denkt dat u kan bijdragen, gelieve dan een donatie te maken aan pgModeler!</p></body></html>`

pgModeler is brought to you thanks to a great effort to create and distribute a quality product. This project is reaching out levels of maturity never imagined. All this is the result of a joint work between its author and the Open Source community.

This software has a long way to go yet and with your help we'll keep maintaining the good job and bringing new improvements on each release. If you did like pgModeler and thinks it deserves a contribution please make a donation!

 DonateWidget(Doneer aan pgModelerDonate to pgModeler DonateWidgetVensterForm DonateWidget$Verberg dit widgetHide this widget DonateWidgetIk wil helpen!I want to help! DonateWidgetStijgend AscendingElementsWidgetSortering CollationElementsWidgetSortering: Collation:ElementsWidget Kolom:Column:ElementsWidgetAfdalend DescendingElementsWidgetElementElementElementsWidgetExpressie ExpressionElementsWidgetExpressie: Expression:ElementsWidgetVensterFormElementsWidgetNeeNoElementsWidgetNulls eerst Nulls FirstElementsWidgetNulls eerst Nulls firstElementsWidgetOperatorOperatorElementsWidgetOperator KlasseOperator ClassElementsWidget Operator Klasse:Operator Class:ElementsWidgetOperator: Operator:ElementsWidgetSorteringSortingElementsWidgetSortering:Sorting:ElementsWidgetTypeTypeElementsWidgetJaYesElementsWidget Event:Event:EventTriggerWidget FilterFilterEventTriggerWidgetFunctie: Function:EventTriggerWidgetTag commando Tag commandEventTriggerWidgetTag:Tag:EventTriggerWidgetEen foreign key kan niet worden toegevoegd aan een relatie omdat deze automatisch wordt aangemaakt wanneer deze wordt verbonden!iA foreign key can not be added to a relationship because is created automatically when this is connected! ExceptionEen machtiging refereert naar object `%1' (%2) dat niet in het model kon worden teruggevonden!RA permission is referencing the object `%1' (%2) which was not found in the model! ExceptionDe relatie kan enkel worden omgewisseld door een ander object van dezelfde soort!DA relationship can only be swapped by other object of the same kind! ExceptionEen trigger kan niet naar kolommen refereren wanneer deze gebruikt maakt van de INSTEAD OF modus binnen een UPDATE event!WA trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event! ExceptionEen viewreferentie moet minstens in een van de volgende SQL scopes worden gebruikt: View Definitie, SELECT-FROM, FROM_WHERE of Na WHERE!xA view reference must be used in at least one these SQL scopes: View Definition, SELECT-FROM, FROM-WHERE or After WHERE! ExceptionEen view trigger kan niet AFTER/BEFORE zijn wanneer deze voor elke rij wordt uitgevoerd!DA view trigger cannot be AFTER/BEFORE when it executes for each row! ExceptionVAllocatie van een object met ongeldig type!'Allocation of object with invalid type! ExceptionEen attribuut kan niet worden toegevoegd aan een kopie of een generalisatierelatie!GAn attribute can not be added to a copy or generalization relationship! ExceptionToewijzijng van een ongeldig objectnaamspatroon aan de relatie `%1'!GAssignement of an invalid object name pattern to the relationship `%1'! Exception`Toewijzing van een object van een ongeldig type!$Assigning object of an invalid type! ExceptionToewijzing van een kolom aan object `%1' (%2) die geen ouder-tabel heeft!IAssignment of a column which has no parent table to the object `%1' (%2)! ExceptionnToewijzing van een functie waarvan de taal ongeldig is!3Assignment of a function which language is invalid! ExceptionToewijzing van een functie waarvan het aantal parameters ongeldig is voor het object `%1' (%2)!RAssignment of a function which parameter count is invalid to the object `%1' (%2)! ExceptionToewijzing van een functie waarvan het terugkeertype verschilt van `%1'!BAssignment of a function which return type is different from `%1'! ExceptionToewijzing van een functie met ongeldige parametertype(s) aan object `%1' (%2)!OAssignment of a function with invalid parameter(s) type(s) to object `%1' (%2)! ExceptionToewijzing van een functie met een ongeldige terugkeerwaarde aan object `%1' (%2)!FAssignment of a function with invalid return type to object `%1' (%2)! ExceptionToewijzing van een minimumwaarde die groter is dan de maximumwaarde van de sequentie!VAssignment of a minimum value to the sequence which is greater than the maximum value! ExceptionjToewijzen van een naam die ongeldige karakters bevat!7Assignment of a name which contains invalid characters! ExceptionToewijzing van een naam die de maximumlengte van 63 karakters overtreed!GAssignment of a name which length exceeds the maximum of 63 characters! ExceptionToewijzing van een niet-bestaande eigenaarskolom aan de sequentie `%1'!>Assignment of a nonexistent owner column to the sequence `%1'! ExceptionToewijzing van een niet-gealloceerde kolom aan het object `%1' (%2)!9Assignment of a not allocated column to object `%1' (%2)! ExceptionToewijzing van een niet-gealloceerde functie aan het object `%1' (%2)!;Assignment of a not allocated function to object `%1' (%2)! ExceptionToewijzing van een niet-gealloceerde schema aan het object `%1' (%2)!9Assignment of a not allocated schema to object `%1' (%2)! ExceptionnToewijzing van een null-vermeerdering aan de sequentie!5Assignment of a null increment value to the sequence! ExceptionlToewijzing van een null type aan het object `%1' (%2)!.Assignment of a null type to object `%1' (%2)! ExceptionToewijzing van een waarde met grotere precisie dan de toegewezen locatie!>Assignment of a precision greater than the length of the type! ExceptionToewijzing van een primary key aan een tabel die reeds over een primary key beschikt!=Assignment of a primary key to a table which already has one! ExceptionPoging to toewijzing van een pseudo-type als het type van een kolom!6Assignment of a pseudo-type to the type of the column! ExceptionToewijzing van een schema aan de sequentie die verschilt van het schema van de eigenaars-tabel!XAssignment of a schema to the sequence which differs from the schema of the owner table! ExceptiontToewijzing van een tweede definitie-expressie aan de view!9Assignment of a second definition expression to the view! ExceptionToewijzing van een startwaarde aan de sequentie die de omvang extrapoleerd als gedefinieerd door de minimum- en maximumwaarden!sAssignment of a start value to the sequence which is extrapolating the range defined by minimum and maximum values! ExceptionToewijzing van een waarde aan een ongeldige verbindingsparameter!9Assignment of a value to an invalid connection parameter! ExceptionbToewijzing van een lege map aan object `%1' (%2)!5Assignment of an empty directory to object `%1' (%2)! ExceptionlToewijzing van een ongeldige expressie aan het object!2Assignment of an invalid expression to the object! ExceptionToewijzing van een ongeldig object aan `%1' (%2)! Het toegewezen object moet van het type `%3' zijn.WAssignment of an invalid object to `%1' (%2)! The assigned object must be of type `%3'. ExceptionToewijzing van een ongeldige precisie aan het type time, timestamp of interval. De precisie moet in dit geval kleiner dan of gelijk zijn aan 6!Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! ExceptionToewijzing van een ongeldig strategy- of supportnummer aan een operatorklasse element!NAssignment of an invalid strategy/support number to an operator class element! ExceptionToewijzing van een ongeldige waarde aan een van de sequentie-attributen!AAssignment of an invalid value to one of the sequence attributes! ExceptionToewijzing van een object dat reeds aan een andere tabel toehoort!>Assignment of an object that already belongs to another table! ExceptionToewijzing van een operatie wiens inputtypehoeveelheid ongeldig is voor een aggregatiefunctie!RAssignment of an operator which input type count is invalid to aggregate function! ExceptionToewijzing van een operator wiens argumententypes ongeldig zijn!>Assignment of an operator which types of arguments is invalid! ExceptionToewijzing van een eigenaarskolom aan de sequentie `%1' die aan geen enkele tabel gerelateerd is!TAssignment of an owner column to the sequence `%1' that is not related to any table! ExceptionToewijzing van toegevoegde of voorgevoegde SQL aan een ongeldig object!=Assignment of appended or prepended SQL to an invalid object! ExceptionvToewijzing van een sorteringsobject wiens type ongeldig is!5Assignment of collation object which type is invalid! ExceptionRToewijzing van een lege DTD bestandsnaam!"Assignment of empty DTD file name! ExceptionfToewijzingen van een lege XML buffer aan de parser!)Assignment of empty XML buffer to parser! ExceptionXToewijzing van een lege naam aan een object!&Assignment of empty name to an object! ExceptionrToewijzing van een lege naam aan een tabel-terugkeertype!.Assignment of empty name to table return type! ExceptionfToewijzing van een lege naam aan de DTD declaratie!0Assignment of empty name to the DTD declaration! ExceptionjToewijzing van een ongeldig uitlijning aan type `%1'!-Assignment of invalid alignment to type `%1'! ExceptionnToewijzing van een ongeldige configuratie aan het type!0Assignment of invalid configuration to the type! ExceptiondToewijzing van een ongeldig element aan type `%1'!+Assignment of invalid element to type `%1'! ExceptionToewijzing van een ongeldige maximumwaarde aan de operatielijst!5Assignment of invalid maximum size to operation list! ExceptionEen ongeldige naam werd toegewezen aan de tabel gegenereerd op basis van een N-N relatie!HAssignment of invalid name to the table generated from N-N relationship! Exception`Toewijzing van een ongeldig type aan het object!)Assignment of invalid type to the object! ExceptionjToewijzing van een taalobject wiens type ongeldig is!4Assignment of language object which type is invalid! ExceptionvToewijzing van een niet-gealloceerde SQL commandoresultaat!/Assignment of not allocated SQL command result! ExceptionTToewijzing van een niet-gealloceerde taal!%Assignment of not allocated language! ExceptionVToewijzing van een niet-gealloceerd object!#Assignment of not allocated object! ExceptionToewijzing van een niet-gealloceerde tabel aan object `%1' (%2)!6Assignment of not allocated table to object `%1' (%2)! ExceptiondToewijzing van null-cachewaarden aan de sequentie!/Assignment of null cache value to the sequence! ExceptiontToewijzing van een eigenaarsobject wiens type ongeldig is!1Assignment of owner object which type is invalid! ExceptionToewijzing van een eigenaarstabel die niet tot dezelfde eigenaar behoort als de sequentie `%1'!WAssignment of owner table which does not belong to the same owner of the sequence `%1'! ExceptionToewijzing van een eigenaarstabel die zich niet in hetzelfde schema bevindt als de sequentie `%1'!OAssignment of owner table which is not in the same schema as the sequence `%1'! ExceptionhToewijzing van een eigenaar aan een ongeldig object!)Assignment of owner to an invalid object! ExceptionToewijzing van een machtiging die niet compatibel is met het type waarnaar wordt verwezen door de machtiging!VAssignment of privilege incompatible with the type of object referenced by permission! ExceptionnToewijzing van een schemaobject wiens type ongeldig is!2Assignment of schema object which type is invalid! ExceptionToewijzing van een systeem-gereserveerde naam aan het object `%1' (%2)!;Assignment of system reserved name to the object `%1' (%2)! ExceptiontToewijzing van een tablespaceobject met een ongeldig type!2Assignment of tablespace object with invalid type! ExceptionRToewijzing van een tablespace aan een constraint wiens type ongeldig is! Om tot een tablespace te behoren moet een constraint een primary key of een unieke sleutel zijn!Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique! ExceptionlToewijzing van een tablespace aan een ongeldig object!.Assignment of tablespace to an invalid object! ExceptionToewijzing van een waarde aan een ongeldig optietype van een rol!6Assignment of value to an invalid option type on role! ExceptionROp dit moment ondersteunt pgModeler de aanmaak van primary keys waarvan sommige kolomen door relatie-verbindingen worden gegenereerd nog niet. Om primary keys met dit feature aan te maken kan u gebruik maken van het veld 'Identifier' of het 'Primary key' tab-blad in het relatie-bewerkingsvenster!At the moment pgModeler does not support the creation of primary keys which some columns were generated by relationship connection. To create primary keys with this feature you can use the field `Identifier' or the tab `Primary key' on relationship editing form! ExceptionPoging tot verbinden zonder dat de configuratieparameters zijn gedefinieerd!;Attempt to connect without define configuration parameters! ExceptionPoging tot het starten van een verbinding die reeds verbonden is!1Attempt to start a connection already stablished! ExceptionSorteringsmethodes moeten worden aangemaakt en minstens LC_COLLATE en LC_CTYPE gedefinieerd hebben!TCollations must be created at least with attributes LC_COLLATE and LC_CTYPE defined! ExceptionConstraint triggers kunnen enkel worden uitgevoerd NA events en voor elke rij!JConstraint triggers can only be executed on AFTER events and for each row! ExceptionNConstraints zoals primary key, foreign key of unique key moeten minstens een kolom bevatten! Voor foreign keys moeten ook de gerefereerde kolommen worden geselecteerd!Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns! ExceptionjDe kopie-relatie tussen tabellen `%1' en `%2' kan niet worden aangemaakt omdat de eerste reeds attributen kopieert van `%3'! Tabellen kunnen over slechts een kopie-tabel beschikken!Copy relationship between tables `%1' and `%2' cannot be done because the first one already copies attributes from `%3'! Tables can have only one copy table! ExceptionDe variabele `%1' kon niet worden toegewezen aan de filter van de event trigger! Op dit moment ondersteunt PostgreSQL enkel de `TAG' variabele!uCould not assign the variable `%1' to event trigger's filter. Currently, PostgreSQL supports only the `TAG' variable! ExceptionEr kon geen verbinding worden gemaakt met de database. Het bericht is: `%1'9Could not connect to the database. Message returned: `%1' ExceptionHet SQL commando kon niet worden uitgevoerd. Het teruggekeerde bericht is: `%1':Could not execute the SQL command. Message returned: `%1' Exception:Het standaardinstellingsbestand `%1' kon niet worden gevonden. Kijk na of dit bestand bestaat om de standaardinstellingen terug te zetten en probeer opnieuw!yCould not find the default settings file `%1'! To restore default settings check the existence of the file and try again! ExceptionHet datababase modelbestand `%1' kon niet worden geladen. Kijk de foutenstack na voor meer details. Probeer `pgmodeler-cli --fix-model' uit te voeren op het model om de bestandsstructuur te corigeren indien dit nodig zou zijn.Could not load the database model file `%1'. Check the error stack to see details. Try to run `pgmodeler-cli --fix-model' in order to correct the structure of the file if that is the case. ExceptionDe plugin `%1' kon niet worden geladen van de bibliotheek `%2'! De plugin manager antwoordde met: `%3'^Could not load the plugin `%1' from the library `%2'! Message returned by plugin manager: `%3' Exception,De operatie `%1' op `%2' kon niet worden voltooid met de data op rij `%3'! Alle aanpassingen werden ongedaan gemaakt. ** Gerapporteerde fout ** %4Could not perform the `%1' operation on `%2' using the data on row `%3'! All changes were rolled back. ** Returned error ** %4 ExceptionEr trad een fout op tijdens het interpreteren van de XML buffer op lijn %1, kolom %2. De parser antwoordde met: %3. %4aError while interpreting XML buffer at line %1 column %2. Message generated by the parser: %3. %4 ExceptionEvent triggerfunctie moet geschreven zijn in een taal die verschilt van SQL!DEvent trigger function must be coded in any language other than SQL! ExceptionDe identifier-relatie kan niet worden aangemaakt voor een zelf-relatie, relaties van het type n-n, kopie or generalisatie!zIdentifier relationship can not be created for a self relationship, relationships of the type n-n, copy or generalization! ExceptionInvoegen van een rol die reeds in de rollenlijst van de machtiging aanwezig is!LInsertion of a role which already exists in the role list of the permission! ExceptionInvoegen van een element dat reeds bestaat in de elementenlijst!>Insertion of element which already exists in the element list! ExceptionZInvoeging van een leeg commando aan de regel!'Insertion of empty command to the rule! ExceptionInvoegen van een ongeldig item in de attributenlijst van het type!=Insertion of invalid item in the attributes list of the type! ExceptionInvoegen van een ongeldig item in de enumeratielijst van het type!?Insertion of invalid item in the enumerations list of the type! ExceptionInvoegen van een item dat reeds bestaat in de attributenlijst van het type!JInsertion of item which already exists in the attributes list of the type! ExceptionInvoegen van een item dat reeds bestaat in de enumeratielijst van het type!LInsertion of item which already exists in the enumarations list of the type! ExceptionOngeldige object id wissel-operatie! De database zelf, tablespaces en rollen kunnen geen ids omwisselen!lInvalid object id swapping operation! The database itself, tablespaces or roles cannot have the ids swapped! ExceptionOngeldige object id wissel-operatie! De betrokken objecten zijn dezelfde!HInvalid object id swapping operation! The objects involved are the same! ExceptionOngeldig gebruik van een view-referentie als volledige SQL definitie! De toegewezen referentie moet een expressie zijn!fInvalid use of a view reference as whole SQL definition! The assigned reference must be an expression! Exception"Het is onmodelijk om een zelf-generalisatie/kopieer-relatie aan te maken! De tabel kan niet van zichzelf erven of zijn eigen attributen kopieren!zIs not possible to create a self generalization/copy relationship! The table can not inherit or copy their own attributes! ExceptionGewone referenties (SELECT-FROM, FROM-WHERE, Na WHERE) kunnen niet worden gemixt met referenties die gebruikt worden als SQL definitie!~It is not possible mix ordinary references (SELECT-FROM, FROM-WHERE, After WHERE) with references used as view SQL definition! ExceptionHet is niet mogelijk om arrays van domeinen of sequenties (dimensie >= 1) aan te maken! Dit feature is nog niet aanwezig in PostgreSQL!}It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! ExceptionxIncorrect gevormde un-escape waarde op rij `%1', kolom `%2'!2Malformed unescaped value on row `%1' column `%2'! Exception^Mixen van niet-compatibele DBMS export-modussen: `negeer object duplicaten', `verwijder database' of `verwijder objecten' kan niet samen worden gebruikt met `simuleer export'!Mixing incompatibles DBMS export modes: `ignore object duplications', `drop database' or `drop objects' cannot be used with `simulate export'! ExceptionMixen van niet-compatibele DROP opties: `verwijder database' en `verwijder objecten' kunnen niet samen worden gebruikt!fMixing incompatibles DROP options: `drop database' and `drop objects' cannot be used at the same time! Exception\Het verkregen object is van een ongeldig type!'Obtaining an object of an invalid type! ExceptionTTypes met ongeldige hoeveelheid verkregen!&Obtaining types with invalid quantity! ExceptionEen functie met ongeldige configuratie wordt gebruikt door het object `%1' (%2)!MOne function with invalid configuration is been used by the object `%1' (%2)! Exception,Een of meerdere objecten werden als ongeldig gemarkeerd en werde automatisch verwijderd omdat deze naar kolommen refereerden die werden ingesloten door relaties die niet langer bestaan omwille van het ontkoppelen van de relatie of het uitsluiten van zulke gegenereerde kolommen!One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! ExceptionEen of meerdere plugin werden niet geactiveerd omwille van fouten gedurende het laadproces! Kijk de exception stack na voor meer details.|One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. ExceptionEnkel constraint triggers kunnen uitstelbaar zijn of naar andere tabellen refereren!FOnly constraint triggers can be deferrable or reference another table! ExceptionEnkel operator-families die gebruik maken van `btree' als indexeringsmethod kunnen worden aanvaard als operatorklasse element!eOnly operator families which uses `btree' as indexing method are accepted by operator class elements! ExceptionEr werd een operatie uitgevoerd op een niet-verbonden verbinding!(Operation on connection not established! ExceptionEen operatie werd uitgevoerd op een niet-gealloceerd element in de boomstructuur! De XML parser buffer moet eerst worden geladen en geinterpreteerd zodat deze boomstructuur kan worden gegenereerd!Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! ExceptionVOperatie met een ongeldige olement id `%1'!*Operation with an invalid element id `%1'! ExceptionEr werd een operatie uitgevoerd op een element dat niet bestaat in de huidig geladen elementen-boomstructuur!ROperation with element which does not exists in the element tree currently loaded! ExceptionPOperatie op een niet-gealloceerd object!$Operation with object not allocated! Exception\Operatie met object(en) van een ongeldig type!2Operation with object(s) which type(s) is invalid! ExceptionROperatie met een niet-gealloceerd object!(Operation with unallocated tree element! ExceptionReferentieredundantie gedetecteerd doordat de rol `%1' refereert naar rol `%2'!PReference redundancy detected by having the role `%1' referencing the role `%2'! ExceptionReferentie naar een kolom van een tuple dat nog niet werd geinitializeerd (tuple-navigatie nog niet gestart)!^Reference to a column of a tuple which was not yet initialized (tuple navigation not started)! ExceptionEen referentie naar een kolom in de objectentabel met een ongeldige index!>Reference to a column of the objects table with invalid index! ExceptionReferentie naar een kolom van een tuple met een ongeldige index!2Reference to a column of tuple with invalid index! Exception~Referentie naar een kolom van een tuple met een ongeldige naam!1Reference to a column of tuple with invalid name! ExceptionReferentie naar een kolom wiens index buiten de capaciteit van de kolomlijst ligt!LReference to a column which index is out of the capacity of the column list! ExceptionReferentie naar een commando wiens index buiten de limieten van de commandolijst ligt!EReference to a command which index is out of the command list bounds! ExceptionEen referentie naar een functie id die niet compatibel is met de configuratie van het gebruiker gedefinieerde type!YReference to a function id which is incompatible with the user define type configuration! ExceptiondReferentie naar een functie met een ongeldig type!*Reference to a function with invalid type! ExceptionReferentie naar een label wiens index buiten de limieten ligt van de label-lijst!>Reference to a label which index is out of labels list bounds! ExceptionEen referentie naar een parameter met een index die buiten de limieten ligt van de parameterlijst!IReference to a parameter which index is out of the parameter list bounds! ExceptionReferentie naar een rol wiens index buiten de limieten van de rollelijst ligt!;Reference to a role which index is out of role list bounds! ExceptionEen referentie naar een rij in de objectentabel met een ongeldige index!;Reference to a row of the objects table with invalid index! ExceptionReferentie naar een tuple met een ongeldige index of het resultaat is leeg (geen tuples)!NReference to a tuple with an invalid index or the result is empty (no tuples)! ExceptionReferentie naar een argument van de operator met een ongeldig type!;Reference to an argument of the operator with invalid type! ExceptionReferentie naar een argument met een index die buiten de limieten ligt van de argumentenlijst!DReference to an argument which index is out of argument list bounds! ExceptionReferentie naar een attribuut met een index die buiten de limieten van de attributenlijst ligt!KReference to an attribute which index is out of the attributes list bounds! ExceptionReferentie naar een element wiens index buiten de limiet van de elementenlijst valt!BReference to an element which index is out of element list bounds! ExceptionReferentie naar een enumeratie met een index buiten de limieten van de enumeratielijst!OReference to an enumeration which index is out of the enumerations list bounds! Exception|Een referentie naar een event die niet tot de trigger behoort!8Reference to an event which does not belongs to trigger! ExceptionReferentie naar een ongeldige kleuren-id `%1' voor element `%2'!7Reference to an invalid color id `%1' for element `%2'! Exception`Referentie naar een ongeldige kopie-tabel optie!*Reference to an invalid copy table option! ExceptionReferentie naar een ongeldige id van objectnaamspatronen voor de relatie `%1'!HReference to an invalid object name pattern id on the relationship `%1'! ExceptionZReferentie naar een ongeldig machtigingstype!'Reference to an invalid privilege type! ExceptionLReferentie naar een ongeldig rol-type!"Reference to an invalid role type! ExceptionReferentie anar een object wiens index buiten de limiet van de objectenlijst valt!@Reference to an object which index is out of object list bounds! ExceptionfReferentie naar een operator met een ongeldig type!+Reference to an operator with invalid type! ExceptionReferentie naar een gebruikersgedefinieerd type dat niet in het model bestaat!DReference to an user-defined data type that not exists in the model! ExceptionReferentie naar een datatype met een index die buiten de capaciteit van de datatype lijst ligt!MReference to data type with an index outside the capacity of data types list! ExceptionbVerwijzing naar een object van een ongeldig type!&Reference to object with invalid type! ExceptionZVerwijdering van een niet-gealloceerd object!#Removal of an object not allocated! ExceptiondVerwijdering van een object van een ongeldig type!&Removing an object of an invalid type! Exception(De INSTEAD OF modus kan niet worden gebruikt voor triggers die aan tabellen toehoren! Dit is enkel beschikbaar voor triggers die aan views toehoren!pThe INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers! ExceptionDe INSTEAD OF modus kan niet worden gebruikt voor view triggers die voor elk statement worden uitgevoerd!UThe INSTEAD OF mode cannot be used on view triggers that executes for each statement! ExceptionHet TRUNCATE event kan enkel worden gebruikt wanneer de trigger uitvoert voor elk statement en aan een tabel toebehoort!hThe TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table! ExceptionDe kolom `%1' kan niet toegewezen worden aan de trigger `%2' omdat deze tot verschillende ouder-tabellen behoren!gThe column `%1' cannot be assigned to the trigger `%2' because they belongs to different parent tables! ExceptionDe kolom `%1' kan niet naar de oudertabel `%2' als data type verwijzen!EThe column `%1' cannot reference it's parent table `%2' as data type! ExceptionDe configuratie van de relatie `%1' creeert een redundantie tussen de relaties `%2'. Redundanties van identifiers of generalisatie/kopie-relaties zijn niet geldig omdat deze kunnen leiden tot het incorrect verspreiden van kolommen en dit kan het model inconsistent maken!The configuration of the relationship `%1' generates a redundancy between the relationships `%2'. Redundancy on identifier or generalization/copy relationships are not accepted since they result in incorrect column spreading making the model inconsistent! ExceptionHet aanmaken van de relatie `%1' tussen de tabellen `%2' en `%3' kan niet worden voltooid omdat deze geen primary key bevatten. Indien de relatie van het type n-n is, moeten beide tabellen over een primary key beschikken!The creation of the relationship `%1' between the table `%2' and `%3' can not be done because one does not have a primary key. If the relationship is of the type n-n both tables must have primary keys! ExceptionHet exportproces faalde door een fout die werd gegenereerd door PostgreSQL tijdens het uitvoeren van een SQL commando. Voor meer informatie over de fout, gelieve de exception stack na te kijken! ** Uitgevoerde SQL commando: ** %1The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 ExceptionDe uitbreiding `%1' is geregistreerd als een data type, het 'behandeld data type' attribuut kan niet worden aangepast!jThe extension `%1' is registered as a data type and cannot have the attribute `handles datatype' modified! ExceptionDe fk relatie `%1' kan niet worden aangemaakt omdat de foreign key die deze relatie weergeeft niet werd aangemaakt op tabel `%2'!tThe fk relationship `%1' cannot be created because the foreign-key that represents it was not created on table `%2'! ExceptionDe functie `%1' kan enkel symboolattributen en een dynamische bibliotheek configureren waneer de taal is ingesteld als zijnde 'C'. In alle andere gevallen moet u broncode specifieren die de functie definieert in het DBMS!The function `%1' can have the attributes symbol and dynamic library configured only if the language is set to C. For all other cases you must specify a source code that defines it in the DBMS! ExceptionDDe functie `%1' kan geen broncode bevatten als definitie omdat de taal is ingesteld als 'C'. Gebruik het attributensymbool en dynamische bibliotheek in de plaats!The function `%1' can not get a source code as a definition because its language is set to C. Use the attributes symbol and dynamic library instead! ExceptionDe groep `%1' kan niet worden opgebouwd in de groependeclaratie-block (%2)!EThe group `%1' can not be built in the groups declaration block (%2)! ExceptionDe groep `%1' kan niet worden opgebouwd omdat dit reeds werd uitgevoerd in een vorige block!SThe group `%1' can not be built once more because this was done in previous blocks! Exception|De groep `%1' kan niet worden opgebouwd zonder kind-elementen!BThe group `%1' can not be built without possessing child elements! ExceptionZDe groep `%1' werd reeds eerder gedeclareerd!1The group `%1' has already been declared earlier! ExceptionhDe groep `%1' werd gedeclareerd maar niet opgebouwd!/The group `%1' has been declared but not built! ExceptionDe groep `%1' werd opgebouwd maar is niet gedeclareerd in de groependeclaratie-block (%2)!OThe group `%1' was built but not declared in the groups declaration block (%2)! ExceptionHet toevoegen van parameter `%1' is niet mogelijk omdat de functie `%2' reeds een parameter met deze naam bevat!The insertion of the parameter `%1' will not be possible because there is another parameter with same name in the function `%2'! ExceptionHet invoegen van de rol `%1' is onmogelijk omdat deze reeds wordt gerefereerd door rol `%2'!eThe insertion of the role `%1' is not possible because this is already being referenced by role `%2'! ExceptionHet invoegen van tabel-terugkeertype `%1' is niet mogelijk omdat er reeds een terugkeer-type met deze naam bestaat in `%2'!The insertion of the table return type `%1' will not be possible because there is another return type with the same name in the `%2'! ExceptionDe nieuwe configuratie van de functie maakt het object `%1' (%2) niet langer gevalideerd! Om de nieuwe configuratie in voege te doen treden moet u de relatie tussen het beinvloedde object en de functie ongedaan maken.The new configuration of the function invalidates the object `%1' (%2)! In this case it is needed to undo the relationship between the affected object and function in order to the new configuration to take effect! Exception`Het object `%1' (%2) bestaat reeds op `%3' (%4)!1The object `%1' (%2) already exists on `%3' (%4)! ExceptionHet object `%1' (%2) kan niet worden aangemaakt omdat het niet aan een schema is toegewezen!UThe object `%1' (%2) can not be created because its not being assigned to any schema! ExceptionHet object `%1' (%2) kan niet worden verwijderd omdat het beschermd is!@The object `%1' (%2) can not be deleted because it is protected! ExceptionHet object `%1' (%2) kan niet worden bewerkt of verwijderd omdat het automatisch werd ingesloten via een relatie! Indien het object een attribuut of een constraint is moeten de bewerkingen worden uitgevoerd via het Relatie bewerk-venster.The object `%1' (%2) can not be edited or deleted because it was automatically included through a relationship! If the object is an attribute or constraint the modifications must be done on the relationship editing form. ExceptionHHet object `%1' (%2) kan niet worden gemanipuleerd omdat dit een gereserveerd object is in PostgreSQL! Dit object bestaat enkel als referentie in het databasemodel!The object `%1' (%2) can not be manipulated because it is reserved to PostgreSQL! This object is present in the database model only as a reference! ExceptionHet object `%1' (%2) kan niet worden verwijderd omdat object `%3' (%4), dat aan `%5' (%6) toehoort, ernaar verwijst!uThe object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4) that belongs to `%5' (%6)! ExceptionHet object `%1' (%2) kan niet worden verwijderd omdat object `%3' (%4) ernaar verwijst![The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4)! ExceptionHet object `%1' (%2) kan niet worden behandeld omdat sommige nodige velden niet werden ingesteld! Gelieve de verplichte velden in te voeren om het object correct aan te kunnen maken of passen.The object `%1' (%2) can't be handled because some needed fields are not set! Please, make sure to fill at least the requires fields in order to properly create or update the object. ExceptionHet object `%1' (%2) kan niet worden toegewezen omdat het reeds bestaat in het container-object `%3'!eThe object `%1' (%2) cannot be assigned because there is already exists in the container object `%3'! ExceptionHet object `%1' (%2) kan niet naar zichzelf verwijzen! Deze operatie is niet toegelaten voor dit type object!fThe object `%1' (%2) cannot reference itself! This operation is not permitted for this kind of object! Exceptionhet object `%1' (%2) heeft een inconsistente SQL of XML definitie!Hide the object which represents the tag assigned to the tableGeneralConfigWidgetVerberg het tabel-gedeelte dat triggers, indexes en regels voorsteltEHide the portion of table which represent triggers, indexes and rulesGeneralConfigWidgetPLicht de huidige lijn onder de cursor op$Highlight lines at cursor's positionGeneralConfigWidgetUitlichtkleurHighlighted line colorGeneralConfigWidget InchesInchesGeneralConfigWidgetLandschap LandscapeGeneralConfigWidgetLedger (432 x 279 mm)GeneralConfigWidgetLinkermarge Left marginGeneralConfigWidget Links:Left:GeneralConfigWidgetLegal (216 x 356 mm)GeneralConfigWidgetLetter (216 x 279 mm)GeneralConfigWidget@Achtergrondkleur van lijnnummersLine numbers' background colorGeneralConfigWidget>Lettertypekleur van lijnnummersLine numbers' font colorGeneralConfigWidgetMilimeters MilimetersGeneralConfigWidgetLVerplaats canvas bij muis in de hoeken$Move canvas by keep mouse on cornersGeneralConfigWidget,Open in bestandsbeheerOpen in file managerGeneralConfigWidget"Taakgeschiedenis:Operation history:GeneralConfigWidgetOpties:Options:GeneralConfigWidgetOrintatie: Orientation:GeneralConfigWidgetPaginamarges: Page Margins:GeneralConfigWidgetPapier:Paper:GeneralConfigWidget PixelsPixelsGeneralConfigWidgetPortretPortraitGeneralConfigWidgetPrint raster Print gridGeneralConfigWidget&Print paginanummersPrint page numbersGeneralConfigWidgetPrintenPrintingGeneralConfigWidgetPrinten && CodePrinting && CodeGeneralConfigWidgetRechtermarge Right marginGeneralConfigWidgetRechts:Right:GeneralConfigWidgetBBehoud de laatste positie en zoom'Save and restore last position and zoomGeneralConfigWidgetPVersimpel creatie van grafische objecten&Simplify creation of graphical objectsGeneralConfigWidgetGrootte:Size:GeneralConfigWidgetVerplaatst het canvas wanneer de cursor zich op de rand van het canvas bevindt<br/> <strong>Handler Functie:</strong> <em>taal_handler_functie()</em><br/> <strong>Validatie Functie:</strong> <em>void functie(oid)</em><br/> <strong>Inline Functie:</strong> <em>void functie(internal)</em>DThe functions to be assigned to the language should have, respectively, the following signatures:

Handler Function: language_handler function()
Validator Function: void function(oid)
Inline Function: void function(internal)LanguageWidgetVertrouwd:Trusted:LanguageWidget"Validatiefunctie:Validator Func.:LanguageWidget (Demo) (Demo) MainWindow <strong>PAS OP:</strong> Het model <strong>%1</strong> is niet gevalideerd! Het is aangeradem om het model te valideren vooraleer u het diff process start. Dit zorgt voor een correcte analyse en het correct genereren van de diff tussen het model en de database! WARNING: The model %1 is invalidated! Before run the diff process it's recommended to validate in order to correctly analyze and generate the difference between the model and a database! MainWindow <strong>PAS OP:</strong> Het model <strong>%1</strong> is niet gevalideerd! Vooraleer u het export proces start is het aangeraden om de validatie uit te voeren. Dit zorgt ervoor dat de objecten correct op de database server kunnen worden aangemaakt! WARNING: The model %1 is invalidated! Before run the export process it's recommended to validate in order to correctly create the objects on database server! MainWindow <strong>PAS OP: </strong> Het model <strong>%1</strong> is niet gevalideerd! Het is aangeraden om het model te valideren vooraleer dit op te slaan om ervoor te zorgen dat u een consistent model behoudt, anders is het modelijk dat het gegenereerde bestand onvolledig is en manuele correcties zal vereissen om het opnieuw te kunnen laden! WARNING: The model %1 is invalidated! It's recommended to validate it before save in order to create a consistent model otherwise the generated file will be broken demanding manual fixes to be loadable again! MainWindow&Sluiten&Close MainWindow&Bewerken&Edit MainWindow&Exporteer&Export MainWindow&Bestand&File MainWindow &Laden&Load MainWindow&Operaties &Operations MainWindowOp&slaan&Save MainWindow&Weergave&Show MainWindow&Validatie &Validation MainWindow6(geen voorbeelden gevonden)(no samples found) MainWindowFBekijk de lijst van geladen plugins!Access the list of loaded plugins MainWindow>Lijn objecten uit op het rasterAlign objects position to grid MainWindow Alt+BAlt+B MainWindow Alt+OAlt+O MainWindow Alt+VAlt+V MainWindowAnnulerenCancel MainWindowdEr werden veranderingen gedetecteerd tussen de papier- en margedefinities van het model die ertoe kunnen leiden dat de objectenn foutief worden geprint. Wenst u te printen met deze nieuwe instellingen? Om de standaardinstellingen te gebruiken, klik op 'Nee' of klik 'Annuleren' om het printen af te breken.Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. MainWindowMenu leegmaken Clear Menu MainWindowSluit dit modelClose current model MainWindowBevestiging Confirmation MainWindowControlsControls MainWindowZHet database modelbestand `%1' kon niet worden geladen. Kijk de error stack na voor details. U kan proberen het probleem te corrigeren om het bestand weer laadbaar te maken.Could not load the database model file `%1'. Check the error stack to see details. You can try to fix it in order to make it loadable again. MainWindow Ctrl+-Ctrl+- MainWindow Ctrl+0Ctrl+0 MainWindow Ctrl+=Ctrl+= MainWindow Ctrl+FCtrl+F MainWindow Ctrl+GCtrl+G MainWindow Ctrl+HCtrl+H MainWindow Ctrl+LCtrl+L MainWindowCtrl+N MainWindow Ctrl+OCtrl+O MainWindow Ctrl+PCtrl+P MainWindow Ctrl+QCtrl+Q MainWindow Ctrl+SCtrl+S MainWindowCtrl+Shift+H Ctrl+Shift+H MainWindowCtrl+Shift+I Ctrl+Shift+I MainWindowCtrl+Shift+S Ctrl+Shift+S MainWindow Ctrl+WCtrl+W MainWindow Ctrl+YCtrl+Y MainWindow Ctrl+ZCtrl+Z MainWindowXDatabase model (*.dbm);;Alle bestanden (*.*)'Database model (*.dbm);;All files (*.*) MainWindow*Databasemodel printenDatabase model printing MainWindow DesignDesign MainWindow.Design databasemodellenDesign database models MainWindow$Voer diff toch uit Diff anyway MainWindow DoneerDonate MainWindow@Bewerk de pgModeler instellingenEdit pgModeler settings MainWindow^De uitvoer wacht op <strong>%1</strong> taak...2Executing pending %1 operation... MainWindowTKlapt het hoofdmenu uit in klassieke modus+Expands the main menu bar in classical mode MainWindowToch exporteren Export anyway MainWindowzExporteer het huidig geopende model in verschillende modussen2Export the current opened model in different modes MainWindowF1F1 MainWindowF10F10 MainWindowF12F12 MainWindowF4F4 MainWindowZoek Object Find Object MainWindowCorrigeer model Fix model MainWindowAlgemeenGeneral MainWindow8Help pgModeler via donering!Help pgModeler by donating! MainWindow"Verberg hoofdmenuHide main menu MainWindowVerbergt de hoofdmenu en verplaats de actie naar een afgescheiden actie@Hides the main menu bar and put the action on a separated action MainWindowImporteert een bestaande database in een nieuw model (Reverse Engineering);Import existing database to new model (reverse engineering) MainWindowLaad model Load model MainWindow2Laad recent geopend modelLoad recently opened model MainWindowHoofdmenu Main menu MainWindow BeheerManage MainWindow4Beheer bestaande databasesManage existent databases MainWindow NieuwNew MainWindowNieuw model New model MainWindowHEr is een nieuwe versie beschikbaar!New version found! MainWindowO&bjectenO&bjects MainWindowPluginsPlugins MainWindow$Rapporteer een bug Report a bug MainWindow$Sla '%1' op als...Save '%1' as... MainWindowAlles opslaanSave all MainWindowToch opslaan Save anyway MainWindowModel opslaan Save model MainWindow6Tijdelijke modellen opslaanSaving temp. models MainWindowToon uitgeklapt Show expanded MainWindowRaster tonen Show grid MainWindow&Toon modeloverzichtShow the model overview MainWindow,Toon pagina-delimitersShow the page delimiters MainWindowDe demonstratieversie kan slechts n databasemodel instantie aanmaken!KThe demonstration version can create only `one' instance of database model! MainWindownDeze actie opent een browservenster! Wilt u verdergaan?PAS OP:</strong> De gegenereerde diff is klaar om gexporteerd te worden! Eens gestart zal dit proces onherroepelijke veranderingen aanbrengen aan de database. Bent u zeker dat u wilt verdergaan? WARNING: The generated diff is ready to be exported! Once started this process will cause irreversible changes on the database. Do you really want to proceed?ModelDatabaseDiffFormDiff &Toepassen &Apply diffModelDatabaseDiffForm&Sluiten&CloseModelDatabaseDiffForm&Genereer &GenerateModelDatabaseDiffForm-- Er werden geen verschillen gedetecteerd tussen het model en de database. -->-- No differences were detected between model and database. --ModelDatabaseDiffForm......ModelDatabaseDiffForm00ModelDatabaseDiffFormx<html><head/><body><p>Objecten die zijn aangeduid met <span style=" font-weight:600;">ALTER</span> kunnen mogelijkerwijs niet worden aangepast tenzij de gedetecteerde verschillen in de attribute liggen die kunnen worden aangepast via een ALTER commando; in alle andere gevallen zal geen actie worden ondernomen of, indien 'Forceer het heraanmaken van objecten' is aangevinkt, zal het object worden verwijderd en heraangemaakt.</p></body></html>k

Objects marked with an ALTER may not be effectively changed unless that the differences detected are in attributes that can be modified through ALTER commands otherwise no operationwill be performed or, if the force recreation is checked, the object will be dropped and created again.

ModelDatabaseDiffFormDiff toepassen Apply diffModelDatabaseDiffFormAnnulerenCancelModelDatabaseDiffFormAanpassingen:Changes:ModelDatabaseDiffFormzVergelijkt het model met de invoerdatabase en genereerd een diff die op die laatste wordt toegepast. <strong>PAS OP:</strong> deze modus veroorzaakt onherroepelijke veranderingen in de database en in geval van falen wordt de originele structuur niet hersteld, zorg ervoor dat u een backup hebt vooraleer u verdergaat. Compares the model and the input database generating a diff and applying it directly to the latter. WARNING: this mode causes irreversible changes on the database and in case of failure the original structure is not restored, so make sure to have a backup before proceed.ModelDatabaseDiffFormVergelijkt het model en de invoerdatabase en slaat het verschil op in een SQL bestand voor later gebruik.YCompares the model and the input database storing the diff in a SQL file for later usage.ModelDatabaseDiffFormBevestiging ConfirmationModelDatabaseDiffFormVerbinding: Connection:ModelDatabaseDiffFormDatabase cluster-niveau objecten zoals rollen en tablespaces zullen niet worden verwijderd.NDatabase cluster level objects like roles and tablespaces will not be dropped.ModelDatabaseDiffFormDatabase: Database:ModelDatabaseDiffFormDiffDiffModelDatabaseDiffFormDiff voorbeeld Diff PreviewModelDatabaseDiffFormDiff modus Diff modeModelDatabaseDiffFormHet diff proces is gepauzeerd. Wachten op een actie van de gebruiker...+Diff process paused. Waiting user action...ModelDatabaseDiffFormRHet diff proces werd succesvol beindigd!Diff process sucessfully ended!ModelDatabaseDiffFormBDrop of trunceer in cascade modus Drop or truncate in cascade modeModelDatabaseDiffFormFoutencode <strong>%1</strong> trad op en werd genegeerd. De export gaat voort.IError code %1 found and ignored. Proceeding with export.ModelDatabaseDiffFormExporteerExportModelDatabaseDiffFormBestand:File:ModelDatabaseDiffFormVoor DROP commando's worden objecten die afhankelijk zijn van het object dat verwijderd wordt, ook verwijderd. Voor het TRUNCATE commando worden tabellen die gelinkt zijn aan de te trunceren tabel ook getrunceerd. <strong>LET OP:</strong> deze optie kan objecten benvloeden die niet in het uitvoer- of diff-voorbeeld opgenomen zijn."For DROP command, the objects that depends on an object to be dropped will be deleted as well. For TRUNCATE command, tables that are linked to a table to be truncated will be truncate too. NOTE: this option can affect more objects than listed in the output or diff preview.ModelDatabaseDiffFormHForceer het heraanmaken van objectenForce recreation of objectsModelDatabaseDiffFormHNegeer fouten omwille van duplicatenIgnore duplicity errorsModelDatabaseDiffForm,Negeer importeerfoutenIgnore import errorsModelDatabaseDiffFormGenegeerde objecten (systeemobjecten of objecten waarvan SQL is uitgeschakeld)2Ignored objects (system ones or with sql disabled)ModelDatabaseDiffFormNegeer fouten die worden gegenereerd door duplicate objecten gedurende het exporteren van de diff naar de database.SIgnores errors generated by duplicated objects when exporting the diff to database.ModelDatabaseDiffFormImporterenImportModelDatabaseDiffForm<Importeer uitbreidingsobjectenImport extension objectsModelDatabaseDiffForm2Importeer systeemobjectenImport system objectsModelDatabaseDiffForm.Behoudt clusterobjectenKeep cluster objectsModelDatabaseDiffFormLBehoudt de machtigingen van het objectKeep object's permissionsModelDatabaseDiffFormBehoudt de naam van de doeldatabase wanneer deze verschilt van de databasenaam in het model.pNo command to rename the destination database will be generated even the model's name differ from database name.ModelDatabaseDiffForm8Er zijn geen operaties meer.No operations left.ModelDatabaseDiffFormJObjecten die aangemaakt moeten wordenObjects to be createdModelDatabaseDiffFormJObjecten die verwijderd moeten wordenObjects to be droppedModelDatabaseDiffForm`De operatie werd geannulleerd door de gebruiker. Operation cancelled by the user.ModelDatabaseDiffFormUitvoerOutputModelDatabaseDiffFormZet de versie waarvoor de diff wordt gegenereerd expliciet zelf. Standaard wordt dezelfde versie gebruikt als de invoerdatabase.wOverride the PostgreSQL version when generating the diff. The default is to use the same version as the input database.ModelDatabaseDiffFormdMachtigingen die reeds op databaseobjecten zijn toegepast zullen behouden blijven. De machtigingen die door het model worden gespecifieerd zullen worden toegepast op de database.zPermissions already set on database objects will be kept.The ones configured on the model will be applied to the database.ModelDatabaseDiffFormfObjecten die mogelijkerwijs aangepast moeten wordenPossible objects to be changedModelDatabaseDiffForm(Behoudt databasenaamPreserve database nameModelDatabaseDiffFormDiff belijken Preview diffModelDatabaseDiffForm\Het proces werd afgebroken omwille van fouten!Process aborted due to errors!ModelDatabaseDiffForm(Vooruitgangslabel...Progress label...ModelDatabaseDiffFormPHercreeer enkel niet-aanpasbare objecten"Recreate only unmodifiable objectsModelDatabaseDiffFormRHergebruik sequenties op serile kolommen!Reuse sequences on serial columnsModelDatabaseDiffFormLSQL Code (*.sql);;Alle bestanden (*.*)!SQL code (*.sql);;All files (*.*)ModelDatabaseDiffForm$Sla diff op als...Save diff as...ModelDatabaseDiffFormvDe diff wordt opgeslagen in het bestand <strong>%1</strong>'Saving diff to file %1ModelDatabaseDiffForm0Selecteer uitvoerbestandSelect output fileModelDatabaseDiffFormSerile kolommen worden geconverteerd naar integers en hun standaardwaarde wordt ingesteld als een functieaanroep naar <strong>nextval(sequentie)</strong>. Normaal gezien wordt een nieuwe sequentie aangemaakt voor elke serile kolom maar deze optie aanvinken zorgt ervoor dat sequenties die de naam van de kolom gebruiken worden hergebruikt in plaats van verwijderd.6Serial columns are converted to integer and having the default value changed to nextval(sequence) function call. By default, a new sequence is created for each serial column but checking this option sequences matching the name on column's default value will be reused and will not be dropped.ModelDatabaseDiffFormInstellingenSettingsModelDatabaseDiffFormStaplabel... Step label...ModelDatabaseDiffForm(Gebruikt PostgreSQL:Use PostgreSQL:ModelDatabaseDiffFormJWachten op het starten van de taak...Waiting process to start...ModelDatabaseDiffForm&Sluiten&CloseModelExportForm&Exporteer&ExportModelExportForm......ModelExportFormAnnulerenCancelModelExportFormVerbinding: Connection:ModelExportFormDBDBModelExportFormDatabase serverDatabase serverModelExportFormVerwijder:Drop:ModelExportFormFoutencode <strong>%1</strong> trad op en werd genegeerd. De export gaat voort.IError code %1 found and ignored. Proceeding with export.ModelExportFormExporteer model Export modelModelExportForm,Exporteer model als...Export model as...ModelExportFormDHet export proces werd afgebroken!Exporting process aborted!ModelExportFormjHet export proces werd geannuleerd door de gebruiker!#Exporting process canceled by user!ModelExportFormVHet export proces werd succesvol beindigt!#Exporting process sucessfuly ended!ModelExportFormHet model pagina per pagina exportern genereert bestanden met de suffix <strong>_p[n]</strong> waarbij <strong>n</strong> de pagina id is. Zorg ervoor dat de huidige gebruiker schrijf-machtiging heeft in de uitvoermap.Exporting the model page by page will generate files with a _p[n] suffix where n is the page id. Check if the current user has write permission on output folder.ModelExportFormBestand:File:ModelExportFormIndien <strong>DB</strong> aangevinkt is, zal pgModeler de database verwijderen indien deze reeds in de server bestaat. Indien <strong>Objecten</string> is aangevinkt zal pgModeler DROP commando's toevoegen aan de objecten waarvoor SQL is ingeschakeld. <strong>PAS OP:</strong> deze optie kan tot dataverlies leiden, zorg ervoor dat u een recente backup kan terugplaatsen.6If DB is checked pgModeler will destroy the database if already exists on the server. When Objects is checked pgModeler will execute the DROP command attached to SQL-enabled objects. WARNING: this option leads to data loss so make sure to have a backup first.ModelExportForm0Negeer object-duplicatenIgnore object duplicityModelExportFormJModel export wordt genitialiseerd...Initializing model export...ModelExportFormUitvoerOutputModelExportForm"Pagina per pagina Page by pageModelExportForm|De PostgreSQL versie waarvoor SQL code moet worden gegenereerdPostgreSQL `%1' server ontdekt. PostgreSQL `%1' server detected.ModelExportHelperPostgreSQL versie-detectie werd overschreven. Versie `%1' wordt gebruikt.De export naar het DBMS begint.Starting export to DBMS.ModelExportHelperRProberen om database `%1' te verwijderen.Trying to drop database `%1'.ModelExportHelper&Sluiten&Close ModelFixForm&Correctie&Fix ModelFixForm...... ModelFixForm<html><head/><body><p>[pgmodeler-cli kon niet worden gevonden]</p></body></html>G

[pgmodeler-cli not found error]

 ModelFixForm<Blader naar pgmodeler-cli toolBrowse for pgmodeler-cli tool ModelFixFormHet tool <strong>%1</strong> kon niet worden gevonden in <strong>%2</strong>. Het correctieprocess kan niet verder gaan! Gelieve uw pgModeler installatie na te kijken of het pad naar het tool manueel in te stellen.Could not locate %1 tool on %2. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below. ModelFixForm,Corrigeer modelbestandFix model file ModelFixForm$Correctiepogingen: Fix tries: ModelFixFormIn sommige gevallen kan het correctieproces niet alle objecten herstellen en zijn manuele correcties via een tekstverwerker vereist. <strong>LET OP:</strong> relaties kunnen mogelijkerwijs hun configuratie verliezen, zoals aangepaste punten- en lijn-kleur.In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. NOTE: relationships may lost their graphical configuration like custom points and line color. ModelFixFormInvoerbestand: Input file: ModelFixFormJLaad gecorrigeerde model na voltoongLoad fixed model when finish ModelFixForm*ModelcorrectiebestandModel file fix ModelFixFormUitvoerbestand: Output file: ModelFixForm.Selecteer invoerbestandSelect input file ModelFixForm0Selecteer uitvoerbestandSelect output file ModelFixFormHet gespecifieerde bestand is niet het pgModeler command line tool (pgmodeler-cli).JThe specified file is not the pgModeler command line tool (pgmodeler-cli). ModelFixFormJWachten op het starten van de taak...Waiting process to start... ModelFixForm@pgModeler command line tool (%1) pgModeler command line tool (%1) ModelFixFormpgmodeler-cli:pgmodeler-cli: ModelFixFormH(het model werd nog niet opgeslagen)(model not saved yet)ModelNavigationWidget......ModelNavigationWidgetSluit model Close modelModelNavigationWidgetVensterFormModelNavigationWidgetVolgende model Next modelModelNavigationWidgetVorige modelPrevious modelModelNavigationWidget......ModelObjectsWidget11ModelObjectsWidgetVolgens IDBy IDModelObjectsWidgetAnnulerenCancelModelObjectsWidgetAlles Wissen Clear AllModelObjectsWidget(Alle items inklappenCollapses all itemsModelObjectsWidgetEscEscModelObjectsWidget*Alle items uitklappenExpands all itemsModelObjectsWidgetFilter:Filter:ModelObjectsWidget$Verberg dit widgetHide this widgetModelObjectsWidgetIDIDModelObjectsWidget Lijst List viewModelObjectsWidgetModelobjecten Model ObjectsModelObjectsWidget NieuwNewModelObjectsWidget ObjectObjectModelObjectsWidget:Object-overzichtsconfiguratieObjects view configurationModelObjectsWidgetOuder Object Parent ObjectModelObjectsWidgetOuder Type Parent TypeModelObjectsWidgetKeer terugReturnModelObjectsWidgetSelecteerSelectModelObjectsWidgetSelecteer Alles Select AllModelObjectsWidgetBoomstructuur Tree viewModelObjectsWidgetTypeTypeModelObjectsWidgetModeloverzichtModel overviewModelOverviewWidget&Annuleer&CancelModelRestorationForm&Herstel&RestoreModelRestorationFormDatabaseDatabaseModelRestorationFormrHoudt de tijdelijke modellen bij indien recuperatie faalt4Keep temporary models in case of restoration failureModelRestorationFormModelherstelModel restorationModelRestorationFormpgModeler werd niet correct afgesloten en sommige modellen waren nog steeds geladen. Klik op <strong>Herstel</strong> om deze mogellen te heropenen of <strong>Annuleer</strong> om het herstel af te breken.pgModeler was not closed properly in a previous execution and some models were still being edited. Click Restore to reopen the models or Cancel to abort the restoration.ModelRestorationFormpgModeler zal proberen om de geselecteerde modellen te herstellen. Indien dit niet lukt blijven deze staan. Deze optie dient als laatste redmiddel om een database model te recupereren. Tijdelijke modellen zullen blijven staan totdat de applicatie wordt afgesloten. Dit betekent dat de gebruiker moet proberen deze manueel te recupereren vooraleer pgModeler af te sluiten.?pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler.ModelRestorationForm^De operatie werd geannuleerd door de gebruiker.Operation canceled by the user.ModelValidationHelperrEr zijn fouten! SQL validatie zal niet worden uitgevoerd.>There are pending errors! SQL validation will not be executed.ModelValidationHelper......ModelValidationWidget00ModelValidationWidgetf<em>Het hierboven vermeldde object werd aangemaakt door een relatie. Verander het naamspatroon van de genererende relatie. Dit probleem kan niet automatisch worden verholpen!</em>The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!ModelValidationWidgetAutodetecteer AutodetectModelValidationWidgetAnnulerenCancelModelValidationWidgetDAnnuleer de lopende SQL validatie.&Cancel the SQL validation in progress.ModelValidationWidgetWijzig de aanmaak-volgorde voor twee objecten door hun ids om te wisselen?Change the creation order for two objects by swapping their idsModelValidationWidgetLeegmakenClearModelValidationWidget:Validatieresultaten leegmakenClear validation resultsModelValidationWidgetrConflicterende object: <strong>%1</strong> <em>(%2)</em>.6Conflicting object: %1 (%2).ModelValidationWidget Ctrl+SCtrl+SModelValidationWidget\Het database model werd succesvol gevalideerd.&Database model successfully validated.ModelValidationWidgetFouten: het model zal niet worden opgeslagen zolang er validatiefouten zijn.BErrors: model will not be saved while there are validation errors.ModelValidationWidgetEscEscModelValidationWidgetVensterFormModelValidationWidget$Verberg dit widgetHide this widgetModelValidationWidget OptiesOptionsModelValidationWidget"PostgreSQL versiePostgreSQL versionModelValidationWidgetLBezig met het verwerken van object: %1Processing object: %1ModelValidationWidget~Refererende object: <strong>%1</strong> <em>(%2)</em> [id: %3].%1 (%2) [id: %3].ModelValidationWidgetLRelatie: <strong>%1</strong> [id: %2].+Relationship: %1 [id: %2].ModelValidationWidgetfDe SQL commando's worden uitgevoerd op de server...!Running SQL commands on server...ModelValidationWidgetSQL Validatie:SQL Validation:ModelValidationWidgetSQL validatie faalde omwille van de volgende fouten. <strong>LET OP:</strong><em> Deze fouten ontkrachten het model niet maar kunnen <strong>export</strong> en <strong>diff</strong> benvloeden.</em>SQL validation failed due to error(s) below. NOTE: These errors does not invalidates the model but may affect operations like export and diff.ModelValidationWidgetHet object <strong>%1</strong> <em>(%2)</em> [id: %3] wordt door <strong>%4</strong> object(en) gerefereerd vr zijn aanmaak.The object %1 (%2) [id: %3] is being referenced by %4 object(s) before its creation.ModelValidationWidget>Het object <strong>%1</strong> <em>(%2)</em> [id: %3]%4 refereerd naar kolommen aangemaakt door <strong>%5</strong> relatie(s) maar wordt vr deze aangemaakt.The object %1 (%2) [id: %3]%4 is referencing columns created by %5 relationship(s) but is created before them.ModelValidationWidgetHet object <strong>%1</strong> <em>(%2)</em> heeft een naam die conflicteerd met de naam van <strong>%3</strong> andere objecten.qThe object %1 (%2) has a name that conflicts with %3 object's name(s).ModelValidationWidgetDe relatie <strong>%1</strong> [id: %2] is in een permanente ongeldige staat en moet worden herplaats.mThe relationship %1 [id: %2] is in a permanent invalidation state and needs to be relocated.ModelValidationWidgetXProbeer de validatieinformatie te verhelpen.3Try to apply a fix on the selected validation info.ModelValidationWidgethProbeer om de gerapporteerde problemen te verhelpen.#Try to resolve the reported issues.ModelValidationWidgetVa&lideer Va&lidateModelValidationWidget|Let op: dit voorkomt niet dat het model kan worden opgeslagen..Warnings: does not prevents model to be saved.ModelValidationWidget(geen objecten) (no objects) ModelWidget"90 (horizontaal)90° (horizontal) ModelWidget90 (vertikaal)90° (vertical) ModelWidget.90 + 90 (horizontaal)90° + 90° (horizontal) ModelWidget*90 + 90 (vertikaal)90° + 90° (vertical) ModelWidget<strong>OPGELET:</strong> Het databasemodel is beschermd! Operaties die het zouden kunnen aanpassen zijn uitgeschakeld!jATTENTION: The database model is protected! Operations that could modify it are disabled! ModelWidget<strong>PAS OP:</strong> Een relatie verwijderen kan onherroepbare ongeldigheden veroorzaken in andere objecten en ervoor zorgen dat deze objecten ook worden verwijderd. Bent u er zeker van dat u wenst verder te gaan?CAUTION: Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? ModelWidget<strong>PAS OP:</strong> Meerdere objecten in n keer verwijderen kan onherroepbare ongeldigheden veroorzaken in andere objecten binnen het model en ervoor zorgen dat deze objecten ook worden verwijderd. Bent u zeker dat u verder wenst te gaan?CAUTION: Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? ModelWidget<strong>PAS OP:<strong> U staat op het punt om objecten te verwijderen in cascade modus, dit betekent dat ook objecten die niet geselecteerd zijn verwijderd kunnen worden. Bent u zeker dat u wilt verdergaan?CAUTION: You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed? ModelWidgetNVoeg een nieuw object toe aan het modelAdd a new object in the model ModelWidgetrWenst u alle afhankelijken van de geselecteerde objecten ook te kopiren? Dit minimalizeert het verbreken van referenties wanneer gekopieerde objecten in een ander model worden geplakt.Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. ModelWidget Alt+QAlt+Q ModelWidget Alt+SAlt+S ModelWidgetNieuw lijn Break line ModelWidget&Eigenaar veranderen Change owner ModelWidgetConstraints Constraints ModelWidgetConverteerConvert ModelWidget2Converteer naar sequentieConvert to sequence ModelWidget.Converteer naar serieelConvert to serial ModelWidgetKopieerCopy ModelWidget Ctrl+ACtrl+A ModelWidget Ctrl+CCtrl+C ModelWidget Ctrl+ECtrl+E ModelWidget Ctrl+VCtrl+V ModelWidget Ctrl+XCtrl+X ModelWidgetAangepaste SQL Custom SQL ModelWidgetKnippenCut ModelWidgetDelDel ModelWidget"Verwijder cascade Del. cascade ModelWidgetVerwijderenDelete ModelWidget<Afhankelijkheden && VerwijzersDeps && Referrers ModelWidgetSchakel SQL uit Disable SQL ModelWidgetBent u zeker dat u de relatie wilt converteren naar een intermediaire tabel?JDo you really want to convert the relationship into an intermediate table? ModelWidgetBent u er zeker van dat u het geselecteerde object wenst te verwijderen?1Do you really want to delete the selected object? ModelWidget,Machtigingen aanpassenEdit permissions ModelWidgetLBewerk de eigenschappen van het objectEdit the object properties ModelWidgetSchakel SQL in Enable SQL ModelWidgetF2F2 ModelWidget^Bezig met het genereren van XML voor: `%1' (%2)Generating XML for: `%1' (%2) ModelWidgetOvererving Inheritance ModelWidget>Het databasemodel wordt geladenLoading database model ModelWidget$Meer op meer (n-n)Many to Many (n-n) ModelWidget*Verplaats naar schemaMove to schema ModelWidget NieuwNew ModelWidget0Niet alle objecten werden in het model geplakt omwille van fouten die werden gegenereerd gedurende dit proces. Kijk de error-stack na voor meer details!zNot all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! ModelWidget"Een op meer (1-n)One to Many (1-n) ModelWidget Een-op-een (1-1)One to One (1-1) ModelWidgetOpen relatieOpen relationship ModelWidgetPlakkenPaste ModelWidgetVBezig met het plakken van object: `%1' (%2)Pasting object: `%1' (%2) ModelWidgetJBezig met het plakken van objecten...Pasting objects... ModelWidgetEigenschappen Properties ModelWidgetBeschermProtect ModelWidgetNBeschermt object(en) tegen aanpassingen%Protects object(s) from modifications ModelWidgetSnelQuick ModelWidgetTSnelle actie voor het geselecteerde object$Quick action for the selected object ModelWidget@Snelle hernoeming van het objectQuick rename the object ModelWidgetRelaties Relationships ModelWidget Verwijder punten Remove points ModelWidgetHernoemRename ModelWidgetDHet databasemodel wordt opgeslagenSaving database model ModelWidgetSelecteerSelect ModelWidgetSelecteer Alles Select all ModelWidget$Selecteer kinderenSelect children ModelWidget^Selecteert alle grafische objecten in het model.Selects all the graphical objects in the model ModelWidgetZet tagSet tag ModelWidgetShift+Del Shift+Del ModelWidget(Toon object broncodeShow object source code ModelWidgetBronSource ModelWidgetBroncode Source code ModelWidget SpatieSpace ModelWidgetTabellenTables ModelWidgetHet cascade verwijderen kwam enkele problemenen tegen tijdens het uitvoeren! Sommige objecten konden niet worden verwijderd of geregistreerd in de actie-geschiedenis! Gelieve de error-stack na te kijken voor meer details.The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details. ModelWidgetBescherming af Unprotect ModelWidgetZBezig met het valideren van object: `%1' (%2)Validating object: `%1' (%2) ModelWidgetZoom: %1% Zoom: %1% ModelWidgetn`%1' informatie voor object `%2' wordt verwerkt (%3)...,Processing `%1' info for object `%2' (%3)...ModelsDiffHelperBDiff informatie wordt verwerkt...Processing diff infos...ModelsDiffHelperFObject `%1' wordt behandeld (%2)...Processing object `%1' (%2)...ModelsDiffHelperLObject `%1' wordt overgeslagen (%2)...Skipping object `%1' (%2)...ModelsDiffHelper00NewObjectOverlayWidget11NewObjectOverlayWidget22NewObjectOverlayWidget33NewObjectOverlayWidget44NewObjectOverlayWidget55NewObjectOverlayWidget88NewObjectOverlayWidget99NewObjectOverlayWidgetAANewObjectOverlayWidgetAggregator AggregateNewObjectOverlayWidgetBBNewObjectOverlayWidgetCCNewObjectOverlayWidgetCastCastNewObjectOverlayWidgetSortering CollationNewObjectOverlayWidget KolomColumnNewObjectOverlayWidgetConstraint ConstraintNewObjectOverlayWidgetConversie ConversionNewObjectOverlayWidgetKopieerCopyNewObjectOverlayWidgetDDNewObjectOverlayWidget DomeinDomainNewObjectOverlayWidgetEENewObjectOverlayWidgetEvent Trigger Event TriggerNewObjectOverlayWidgetUitbreiding ExtensionNewObjectOverlayWidgetFFNewObjectOverlayWidgetVensterFormNewObjectOverlayWidgetFunctieFunctionNewObjectOverlayWidgetGGNewObjectOverlayWidgetHHNewObjectOverlayWidgetIINewObjectOverlayWidget IndexIndexNewObjectOverlayWidgetOvererving InheritanceNewObjectOverlayWidgetJJNewObjectOverlayWidgetKKNewObjectOverlayWidgetLLNewObjectOverlayWidgetTaalLanguageNewObjectOverlayWidgetMMNewObjectOverlayWidgetMeer-op-meer Many-to-manyNewObjectOverlayWidgetOONewObjectOverlayWidgetEen-op-meer One-to-manyNewObjectOverlayWidgetEen-op-een One-to-oneNewObjectOverlayWidgetOp. Klasse Op. ClassNewObjectOverlayWidgetOp. Familie Op. FamilyNewObjectOverlayWidgetOperatorOperatorNewObjectOverlayWidgetPPNewObjectOverlayWidgetMachtigingen PermissionsNewObjectOverlayWidgetQQNewObjectOverlayWidgetRRNewObjectOverlayWidgetRolRoleNewObjectOverlayWidget RegelRuleNewObjectOverlayWidgetSSNewObjectOverlayWidget SchemaSchemaNewObjectOverlayWidgetSequentieSequenceNewObjectOverlayWidgetTTNewObjectOverlayWidget TabelTableNewObjectOverlayWidgetTablespace TablespaceNewObjectOverlayWidgetTagTagNewObjectOverlayWidgetTekst boxTextboxNewObjectOverlayWidgetTriggerTriggerNewObjectOverlayWidgetTypeTypeNewObjectOverlayWidgetUUNewObjectOverlayWidgetVVNewObjectOverlayWidgetViewViewNewObjectOverlayWidgetWWNewObjectOverlayWidgetXXNewObjectOverlayWidgetYYNewObjectOverlayWidgetZZNewObjectOverlayWidgetLeegmakenClearNumberedTextEditor LadenLoadNumberedTextEditorLSQL Code (*.sql);;Alle bestanden (*.*)!SQL file (*.sql);;All files (*.*)NumberedTextEditorAfhankelijken DependenciesObjectDepsRefsWidgetBSluit indirecte afhankelijken uitExclude indirect dependenciesObjectDepsRefsWidgetIDIDObjectDepsRefsWidget6Neem indirecte afhankele opInclude indirect referencesObjectDepsRefsWidget ObjectObjectObjectDepsRefsWidgetTAfhankelijken & referenties van het object"Object's dependencies & referencesObjectDepsRefsWidgetOuder Object Parent ObjectObjectDepsRefsWidgetOuder Type Parent TypeObjectDepsRefsWidgetReferenties ReferencesObjectDepsRefsWidgetDit object bestaat niet langer. Het lijsten van afhankelijken en referenties is uitgeschakeld.ZThis object does not exists anymore. The dependencies and references listing are disabled.ObjectDepsRefsWidgetTypeTypeObjectDepsRefsWidget......ObjectFinderWidget&HoofdlettergevoeligCase SensitiveObjectFinderWidgetLeegmakenClearObjectFinderWidgetAlles Wissen Clear AllObjectFinderWidget8Maakt de zoekresultaten leegClears the search resultsObjectFinderWidget0Definieert de zoekfilterDefines the search filterObjectFinderWidget&Exacte Overeenkomst Exact MatchObjectFinderWidget FilterFilterObjectFinderWidgetZoekFindObjectFinderWidgetVensterFormObjectFinderWidgetP<strong>%1</strong> object(en) gevonden.$Found %1 object(s).ObjectFinderWidget$Verberg dit widgetHide this widgetObjectFinderWidgetIDIDObjectFinderWidget.Geen objecten gevonden.No objects found.ObjectFinderWidget ObjectObjectObjectFinderWidgetOuder Object Parent ObjectObjectFinderWidgetOuder Type Parent TypeObjectFinderWidgetPatroon:Pattern:ObjectFinderWidget$Regular expressionRegular ExpressionObjectFinderWidgetSelecteerSelectObjectFinderWidgetSelecteer Alles Select AllObjectFinderWidgetTypeTypeObjectFinderWidget.......ObjectRenameWidgetAnnulerenCancelObjectRenameWidgetVensterFormObjectRenameWidgetHernoemRenameObjectRenameWidget naar:to:ObjectRenameWidgetVeld leegmaken Clear fieldObjectSelectorWidgetVensterFormObjectSelectorWidget Selecteer Object Select ObjectObjectSelectorWidgetItem ToevoegenAdd ItemObjectsTableWidget Alt+RAlt+RObjectsTableWidgetBevestiging ConfirmationObjectsTableWidget Ctrl+End, Ctrl+SCtrl+End, Ctrl+SObjectsTableWidgetCtrl+Home Ctrl+HomeObjectsTableWidgetDelDelObjectsTableWidgetvBent u zeker dat u het geselecteerde item wilt verwijderen?/Do you really want to remove the selected item?ObjectsTableWidgetItem Aanpassen Edit ItemObjectsTableWidgetVensterFormObjectsTableWidgetInsInsObjectsTableWidgetNaar Beneden Move DownObjectsTableWidgetNaar BovenMove UpObjectsTableWidget,Naar de laatste plaats Move to endObjectsTableWidget*Naar de eerste plaats Move to startObjectsTableWidget"Alles Verwijderen Remove AllObjectsTableWidget Item Verwijderen Remove ItemObjectsTableWidgetShift+Del Shift+DelObjectsTableWidget SpatieSpaceObjectsTableWidgetItem Updaten Update ItemObjectsTableWidget"(ongeldig object)(invalid object) OperationList......OperationListWidget00OperationListWidget11OperationListWidget6Verwijder actiegeschiedenisDelete operation historyOperationListWidgetHet verwijderen van de geschiedenis van de uitgevoerde acties kan niet worden ongedaan gemaakt, bent u zeker dat u wilt verdergaan?ZDelete the executed operations history is an irreversible action, do you want to continue?OperationListWidget$Uitgevoerde ActiesExecuted OperationsOperationListWidget$Verberg dit widgetHide this widgetOperationListWidgetNaam: %1Name: %1OperationListWidgetObject: %1 Object: %1OperationListWidget8ActiegeschiedenisuitsluitingOperation history exclusionOperationListWidgetActie: %1 Operation: %1OperationListWidgetActies: Operations:OperationListWidgetPositie: Position:OperationListWidgetOpnieuw doenRedoOperationListWidgetOngedaan makenUndoOperationListWidgetaangemaaktcreatedOperationListWidgetaangepastmodifiedOperationListWidgetverplaatstmovedOperationListWidgetverwijderdremovedOperationListWidget Standaardklasse:Default Class:OperatorClassWidgetElementtype: Element Type:OperatorClassWidgetElementenElementsOperatorClassWidgetFunctieFunctionOperatorClassWidgetFunctie: Function:OperatorClassWidgetIndexering: Indexing:OperatorClassWidget ObjectObjectOperatorClassWidget"Operator Familie: Op. Family:OperatorClassWidgetOperatorOperatorOperatorClassWidget Operator FamilieOperator FamilyOperatorClassWidgetOperator: Operator:OperatorClassWidget OpslagStorageOperatorClassWidgetOpslagtype Storage TypeOperatorClassWidget.Ondersteuning/StrategieSupport/StrategyOperatorClassWidget0Ondersteuning/Strategie:Support/Strategy:OperatorClassWidgetTypeTypeOperatorClassWidgetIndexering: Indexing:OperatorFamilyWidgetGeavanceerdAdvancedOperatorWidgetArgumenten ArgumentsOperatorWidgetCommutator: Commutator:OperatorWidget HASHESHASHESOperatorWidget Join:Join:OperatorWidget(Linkse Argument TypeLeft Argument TypeOperatorWidget MERGESMERGESOperatorWidgetNegator:Negator:OperatorWidget"Operator functie:Operator Func.:OperatorWidgetOpties:Options:OperatorWidgetRestrict: Restrict:OperatorWidget*Rechtse Argument TypeRight Argument TypeOperatorWidgetOm een unaire operator aan te maken moet u <strong><em>'any'</em></strong> als een van zijn argumenten specifiren. Daarenboven mag de functie die de operator definieert slechts n parameter bezitten die van hetzelfde type moet zijn als de unaire operator.To create a unary operator it is necessary to specify as 'any' one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator.OperatorWidget Standaardwaarde:Default Value:ParameterWidgetININParameterWidget Modus:Mode:ParameterWidgetOUTOUTParameterWidgetVARIADICParameterWidget-- Er zijn geen machtigingen gedefinieerd voor het gespecifieerde object!3-- No permissions defined for the specified object!PermissionWidget/* Er kon geen SQL Codevoorbeeld worden gegenereerd voor de machtigingen!;/* Could not generate the SQL code preview for permissions!PermissionWidget(Machtiging toekennenAdd PermissionPermissionWidgetActie annulerenCancel OperationPermissionWidgetCascadeCascadePermissionWidgetCodevoorbeeld Code PreviewPermissionWidget2Niet-uitvoerbare SQL codeDisable SQL codePermissionWidget,Machtigingen aanpassenEdit permissionsPermissionWidgetGRANT OPTION GRANT OPTIONPermissionWidgetID:ID:PermissionWidgetIdIdPermissionWidgetNaamNamePermissionWidgetMachtigingen PermissionsPermissionWidgetMachtiging PrivilegePermissionWidgetMachtiginen PrivilegesPermissionWidget RollenRolesPermissionWidget(Machtiging aanpassenUpdate PermissionPermissionWidgetj** Object(en) die niet kon(den) worden gecorrigeerd: # ** Object(s) that couldn't fixed:  PgModelerCLI0 commandolijn interface. command line interface. PgModelerCLI@Het bestand %1 kan niet worden verwijderd! Kijk na of de huidige gebruiker voldoende machtigingen heeft om het bestand te verwijderen en of het bestand bestaat.gCan't erase the file %1! Check if the current user has permissions to delete it and if the file exists. PgModelerCLI2DBMS exporteringsopties: DBMS export options:  PgModelerCLIDatabase modelbestanden (.dbm) zijn reeds geassocieerd met pgModeler!@Database model files (.dbm) are already associated to pgModeler! PgModelerCLIVDe XML van de objecten word geextraheerd...Extracting objects' XML... PgModelerCLI"Algemene opties: General options:  PgModelerCLIDOnvolledige verbindingsinformatie!"Incomplete connection information! PgModelerCLIHet invoerbestand mag niet hetzelfde zijn als het uitvoerbestand!)Input file must be different from output! PgModelerCLIfThe actie om de mime optie the updaten is ongeldig!/Invalid action specified to update mime option! PgModelerCLIHet invoerbestand is ongeldig! Kijk na of dit bestand door pgModeler werd gegenereerd ofdat het bestand gecorrupteerd raakte!^Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted! PgModelerCLIBEen ongeldige zoom gespecifieerd!Invalid zoom specified! PgModelerCLI2Mime databaseoperatie: %1Mime database operation: %1 PgModelerCLIAndere opties: Miscellaneous options:  PgModelerCLILHet model werd succesvol gecorrigeerd!Model successfully fixed! PgModelerCLIDOptie '%1' aanvaardt geen waardes.#Option '%1' does not accept values. PgModelerCLIFDe objecten worden heraangemaakt...Recreating objects... PgModelerCLIjHet update-mime-database commando wordt uitgevoerd...'Running update-mime-database command... PgModelerCLI*Mime update begint...Starting mime update... PgModelerCLI,Model export begint...Starting model export... PgModelerCLI0Modelcorrectie begint...Starting model fixing... PgModelerCLIREr zijn geen verbindingen geconfigureerd.$There are no connections configured. PgModelerCLIEr is geen bestandsassociatie tussen pgModeler and .dbm bestanden!AThere is no file association related to pgModeler and .dbm files! PgModelerCLI2Niet-herkende optie '%1'.Unrecognized option '%1'. PgModelerCLI>Gebruik: pgmodeler-cli [OPTIES]Usage: pgmodeler-cli [OPTIONS] PgModelerCLI`Er is geen waarde gespecifieerd voor optie '%1'.$Value not specified for option '%1'. PgModelerCLIOPGEPAST: Er zijn objecten die niet konden worden gecorrigeerd. We proberen opnieuw... (poging %1 van %2)SWARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2) PgModelerCLIAuteur: %1 Author: %1PgModelerPlugin"Plugin InformatiePlugin InformationPgModelerPluginVersie: %1 Version: %1PgModelerPluginHWenst u de <strong> SQL %1 status</strong> ook toe te passen op de referenties van het object? Dit vermijdt problemen bij het exporteren of valideren van het model.Do you want to apply the SQL %1 status to the object's references too? This will avoid problems when exporting or validating the model. PgModelerUiNSuitschakelen disabling PgModelerUiNSinschakelenenabling PgModelerUiNSData Type Data TypePgSQLTypeWidgetDimensie DimensionPgSQLTypeWidgetVensterFormPgSQLTypeWidgetFormaat:Format:PgSQLTypeWidgetInterval: Interval:PgSQLTypeWidgetL:L:PgSQLTypeWidget LengteLengthPgSQLTypeWidgetMMPgSQLTypeWidgetGEENNONEPgSQLTypeWidgetP:P:PgSQLTypeWidgetPrecisie PrecisionPgSQLTypeWidget SRID:SRID:PgSQLTypeWidgetRuimtelijk:Spatial:PgSQLTypeWidgetTijdszone: Timezone:PgSQLTypeWidget Type:Type:PgSQLTypeWidgetVariatie: Variation:PgSQLTypeWidgetZZPgSQLTypeWidget[ ]:[ ]:PgSQLTypeWidgetVensterFormPluginsConfigWidgetBibliotheekLibraryPluginsConfigWidget Geladen plug-insLoaded plug-insPluginsConfigWidget,Open in bestandsbeheerOpen in file managerPluginsConfigWidget"Plug-in startmap:Plug-ins root directory:PluginsConfigWidget PluginPluginPluginsConfigWidget VersieVersionPluginsConfigWidgetExpressies Expressions PolicyWidgetNaamName PolicyWidget RollenRoles PolicyWidget%1 (lijn %2) %1 (line: %2)QObjectnieuwe_database new_databaseQObject%1_kopieert_%2 %1_copies_%2 Relationship(%1_heeft_meerdere_%2%1_has_many_%2 Relationship*%1_heeft_exact_een_%2 %1_has_one_%2 Relationship%1_erft_van_%2%1_inherits_%2 Relationship:meerdere_%1_heeft_meerdere_%2many_%1_has_many_%2 RelationshipKolom (Bron):Column (Source):RelationshipConfigWidgetKolom (Doel):Column (Target):RelationshipConfigWidget8Verbindt FK naar PK kolommenConnect FK to PK columnsRelationshipConfigWidgetVVerbindt de centrale punten van de tabellenConnect tables' center pointsRelationshipConfigWidget VerbindingsmodusConnection ModeRelationshipConfigWidgetKopieerCopyRelationshipConfigWidgetStandaardDefaultRelationshipConfigWidgetUitstelbaar: Deferrable:RelationshipConfigWidgetUitstel: Deferral:RelationshipConfigWidget6FK instellingen && PatronenFK Settings && PatternsRelationshipConfigWidget&Foreign Key (Bron):Foreign Key (Source):RelationshipConfigWidget&Foreign Key (Doel):Foreign Key (Target):RelationshipConfigWidget0Foreign key instellingenForeign key settingsRelationshipConfigWidgetVensterFormRelationshipConfigWidgetGeneralisatieGeneralizationRelationshipConfigWidget4Meerdere op meerdere (n:n)Many to many (n:n)RelationshipConfigWidgetNaamspatronen Name patternsRelationshipConfigWidgetON DELETE: ON DELETE:RelationshipConfigWidgetON UPDATE: ON UPDATE:RelationshipConfigWidget*Een op meerdere (1:n)One to many (1:n)RelationshipConfigWidget Een-op-een (1:1)One to one (1:1)RelationshipConfigWidget,Het patroon voor de kolommen wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n).rPattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipConfigWidgetHet patroon voor kolommen die worden gegenereerd op basis van de pk van de doeltabel (n-n).APattern for columns generated based upon target table's pk (n-n).RelationshipConfigWidget2Het patroon voor de foreign key wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n).vPattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipConfigWidgetHet patroon voor de foreign key wordt gegenereerd op basis van de pk van de doeltabel (n-n).EPattern for foreign key generated based upon target table's pk (n-n).RelationshipConfigWidgetHet patroon voor de primary key wordt gegenereerd op basis van de relatie met de identifier.=Pattern for primary key generated by identifier relationship.RelationshipConfigWidgetHet patroon voor de unieke sleutel wordt gegenereerd op basis van de relatie.5Pattern for unique key generated by the relationship.RelationshipConfigWidget$Primary Key Kolom:Primary Key Column:RelationshipConfigWidget0Naam van de Primary Key:Primary Key Name:RelationshipConfigWidgetRelatietype:Relationship type:RelationshipConfigWidget6Naam van de unieke sleutel:Unique Key Name:RelationshipConfigWidget is vereist is requiredRelationshipWidget1-n1-nRelationshipWidgetALLALLRelationshipWidgetGeavanceerdAdvancedRelationshipWidgetAttribuut AttributeRelationshipWidgetAttributen AttributesRelationshipWidgetCOMMENTSCOMMENTSRelationshipWidgetCONSTRAINTS CONSTRAINTSRelationshipWidgetCardinaliteit: Cardinality:RelationshipWidgetKolom (Bron):Column (Source):RelationshipWidgetKolom (Doel):Column (Target):RelationshipWidgetConstraint ConstraintRelationshipWidgetConstraints ConstraintsRelationshipWidgetKopieeropties Copy OptionsRelationshipWidget"Aangepaste kleur: Custom Color:RelationshipWidgetDEFAULTSDEFAULTSRelationshipWidgetStandaardDefaultRelationshipWidgetUitstelbaar: Deferrable:RelationshipWidgetUitstel: Deferral:RelationshipWidgetHAfhankelijkheid / Kopieer de relatieDependency / Copy relationshipRelationshipWidget&Foreign Key (Bron):Foreign Key (Source):RelationshipWidget&Foreign Key (Doel):Foreign Key (Target):RelationshipWidget0Foreign key instellingenForeign key SettingsRelationshipWidget&Algemene Tabelnaam:Gen. Table Name:RelationshipWidgetAlgemeenGeneralRelationshipWidgetBGeneralisatierelatie (overerving))Generalization relationship (inheritance)RelationshipWidgetINCLUDING INCLUDINGRelationshipWidgetINDEXESINDEXESRelationshipWidgetIdentifier IdentifierRelationshipWidgetIn meer-op-meer relaties worden beide tabellen als referentie gebruikt om de link-tabel te representeren. Kolommen van beide tabellen worden gekopieerd naar de resulterende link-tabel en foreign keys naar elke deelnemende tabel worden aangemaakt.In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table.RelationshipWidget2In plaats van een multi-kolom primary key te creeren op basis van de foreign key kolommen, wordt een enkele kolom aangemaakt en gebruikt als primary key.Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key.RelationshipWidget(Meer-op-meer relatieMany to many relationshipRelationshipWidgetNaamNameRelationshipWidgetNaamspatronen Name PatternsRelationshipWidgetDe naam van de tabel die is gegenereerd op basis van de meer-op-meer relatie:Name of the table generated from many to many relationshipRelationshipWidgetON DELETE: ON DELETE:RelationshipWidgetON UPDATE: ON UPDATE:RelationshipWidget&Een-op-meer relatieOne to many relationshipRelationshipWidget$Een-op-een relatieOne to one relationshipRelationshipWidget,Het patroon voor de kolommen wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n).rPattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipWidgetHet patroon voor kolommen die worden gegenereerd op basis van de pk van de doeltabel (n-n).APattern for columns generated based upon target table's pk (n-n).RelationshipWidget2Het patroon voor de foreign key wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n).vPattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n).RelationshipWidgetHet patroon voor de foreign key wordt gegenereerd op basis van de pk van de doeltabel (n-n).EPattern for foreign key generated based upon target table's pk (n-n).RelationshipWidgetHet patroon voor de primary key wordt gegenereerd op basis van de relatie met de identifier.=Pattern for primary key generated by identifier relationship.RelationshipWidgetHet patroon voor de unieke sleutel wordt gegenereerd op basis van de relatie.5Pattern for unique key generated by the relationship.RelationshipWidget0Naam van de Primary Key:Primary Key Name:RelationshipWidgetPrimary key Primary keyRelationshipWidget$Primary Key Kolom:Primay Key Column:RelationshipWidget\De ontvanger (of gerefereerde) tabel zal de gegenereerde kolommen en de foreign key ontvangen om de link tussen beiden te bewerkstelligen. Dit is de (n) zijde van de relatie.Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship.RelationshipWidget$Ontvangende Tabel:Receiver Table:RelationshipWidget Referentietabel:Reference Table:RelationshipWidgetvDe referentietabel heeft kolommen in zijn primary key die gekopieerd zullen worden naar de ontvangende tabel om de link tussen deze te bewerkstelligen. Dit is de (1) zijde van de relatie.Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship.RelationshipWidget&Gerefereerde Tabel:Referenced Table:RelationshipWidgetDe gerefereerde tabel heeft kolommen waarnaar wordt gerefereerd door een foreign key in een andere tabel. Dit is de (1) zijde van de relatie.kReferenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship.RelationshipWidgetDe gerefereerde tabel heeft kolommen waarnaar wordt gerefereerd door een view die deze kolommen gebruikt om zijn eigen kolommen aan te maken.gReferenced table has its columns referenced by a view in order to construct the columns of this latter.RelationshipWidget$Refererende Tabel:Referer Table:RelationshipWidget"Refererende View: Referer View:RelationshipWidgetDe refererende tabel refereert naar een of meerdere kolommen in een andere tabel via foreign keys. Dit is the (n)-zijde van de relatie.sReferer table references one or more columns of a table through foreign keys. This is the (n) side of relationship.RelationshipWidgetDe refererende view refereert naar een of meerdere kolommen van een tabel om zijn eigen kolommen aan te maken.UReferer view references one or more columns of a table to construct it's own columns.RelationshipWidgetRelatietype: Rel. Type:RelationshipWidgetFRelatie gegenereerd via foreign key&Relationship generated via foreign keyRelationshipWidgetSTORAGESTORAGERelationshipWidgetEnkele PK kolomSingle PK columnRelationshipWidgetTabel 1:Table 1:RelationshipWidgetTabel 2:Table 2:RelationshipWidgetDe ontvanger's primary key wordt samengesteld door de gegenereerde foreign key kolommen.QThe receiver's primary key will be composed by the generated foreign key columns.RelationshipWidgetDit geavanceerde tab-blad toont de objecten (kolommen of tabellen) die automatisch worden aangemaakt door de verbindingen van de relatie alsook de foreign keys die de link tussen de deelnemende tabellen voorstelt.This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables.RelationshipWidgetTypeTypeRelationshipWidget6Naam van de unieke sleutel:Unique Key Name:RelationshipWidget0Gebruik standaardwaarden Use defaultsRelationshipWidgetZGebruik globale instellingen voor deze velden$Use global settings for these fieldsRelationshipWidgetGebruik de speciale primary key wanneer u een primary key samengesteld uit gegenereerde kolommen van de ontvangende tabel wilt insluiten. <strong>Belangrijk:</strong> indien dit een nieuwe relatie is moet u de creatie van deze relatie voltooien en dit dialoogvenster daarna opnieuw openen om de speciale primary key aan te maken.Use the special primary key if you want to include a primary key containing generated columns to the receiver table. Important: if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key.RelationshipWidgetGebruik de waarden ingesteld in het instellingsvenster voor de velden hieronder?Use the values defined on settings dialogs for the fields belowRelationshipWidget"[DOEL] is vereist[DST] is requiredRelationshipWidget"[BRON] is vereist[SRC] is requiredRelationshipWidgetdepdepRelationshipWidgetfkfkRelationshipWidgetn-nn-nRelationshipWidget[binaire data] [binary data]ResultSetModelAttributen Attributes RoleWidgetKan inloggen Can login RoleWidgetVerbindingen: Connections: RoleWidgetGencrypteerd Encrypted RoleWidgetLid van Member of RoleWidget LedenMembers RoleWidgetLeden (Admin.)Members (Admin.) RoleWidgetWachtwoord: Password: RoleWidgetRolRole RoleWidgetSuperuser Superuser RoleWidgetGeldigheidValidity RoleWidget(yyyy-MMM-dd hh:mm:ssyyyy-MMM-dd hh:mm:ss RoleWidgetCommando'sCommands RuleWidget4Voorwaardelijke Expressie:Conditional Expr.: RuleWidget Event:Event: RuleWidget Uitvoeringstype:Execution Type: RuleWidgetSQL Commando: SQL Command: RuleWidgetSQL commando SQL command RuleWidget Om een regel aan te maken die niets doet (<strong>DO NOTHING</strong>), laat eenvoudigweg de commando's in de SQL commando tabel leeg.To create a rule that does not perform any action (DO NOTHING) simply do not specify commands in the SQL commands table. RuleWidget......SQLExecutionWidget Alt+ZAlt+FSQLExecutionWidget Alt+OAlt+OSQLExecutionWidgetAlles Wissen Clear AllSQLExecutionWidget@Wis SQL invoerveld en resultaten!Clear sql input field and resultsSQLExecutionWidgetBestand met komma-gesepareerde waarden (*.csv);;Alle bestanden (*.*)4Comma-separated values file (*.csv);;All files (*.*)SQLExecutionWidget&Kopier de selectieCopy selectionSQLExecutionWidgetE&xporterenE&xportSQLExecutionWidgetPExporteer de resultaten naar CSV bestandExport results to a CSV fileSQLExecutionWidgetF6F6SQLExecutionWidgetVensterFormSQLExecutionWidget LadenLoadSQLExecutionWidget&Laad SQL commando'sLoad SQL commandsSQLExecutionWidgetUitvoerenRun SQLSQLExecutionWidget*Voer het commando uitRun the specified SQL commandSQLExecutionWidgetLSQL Code (*.sql);;Alle bestanden (*.*)!SQL file (*.sql);;All files (*.*)SQLExecutionWidgetOpslaanSaveSQLExecutionWidget$Sla CSV bestand op Save CSV fileSQLExecutionWidget*Sla SQL commando's opSave SQL commandsSQLExecutionWidgetOpslaan alsSave asSQLExecutionWidgetSnippe&ts Snippe&tsSQLExecutionWidgetHet SQL invoerveld en de resultaten-lijst zullen worden leeggemaakt! Wenst u verder te gaan?JThe SQL input field and the results grid will be cleared! Want to proceed?SQLExecutionWidget[binaire data] [binary data]SQLExecutionWidget... SQLToolWidget<strong>LET OP:</strong> Van alle databases ontkoppelen sluit alle tab-bladen in dit venster! Bent u zeker dat u verder wilt gaan?ATTENTION: Disconnect from all databases will close any opened tab in this view! Do you really want to proceed? SQLToolWidget Alt+RAlt+R SQLToolWidgetAttributen Attributes SQLToolWidget"DatabaseverkennerDatabase explorer SQLToolWidget<Van alle databases ontkoppelenDisconnect from all databases SQLToolWidgetVensterForm SQLToolWidgetSQL uitvoering SQL execution SQLToolWidgetBroncode Source code SQLToolWidgetOpgepastWarning SQLToolWidgetVensterFormSceneInfoWidgetVulkleur: Fill color: SchemaWidgetToon rechthoekShow rectangle SchemaWidget Cache:Cache:SequenceWidgetCyclisch:Cyclic:SequenceWidgetToename: Increment:SequenceWidgetMaximum:Maximum:SequenceWidgetMinimum:SequenceWidget"Bezittende kolom: Owner Col.:SequenceWidget Start:Start:SequenceWidget/* Er trad een fout op tijdens het onleden van het snippet '%1': %2 */*/* Error parsing the snippet '%1': %2 */SnippetsConfigWidgetToevoegenAddSnippetsConfigWidgetAlle snippets All snippetsSnippetsConfigWidget$Van toepassing op: Applies to:SnippetsConfigWidget*Annuleer aanpassingenCancel editionSnippetsConfigWidget<Maak een nieuwe verbinding aanCreate new connectionSnippetsConfigWidgetJVerwijder de geselecteerde verbindingDelete selected connectionSnippetsConfigWidgetdBent u zeker dat u alle snippets wilt verwijderen?*Do you really want to remove all snippets?SnippetsConfigWidgetGelieve een andere snippet id te selecteren, de id <strong>%1</strong> is reeds in gebruik!TDuplicated snippet id %1 detected. Please, specify a different one!SnippetsConfigWidgetFPas de geselecteerde verbinding aanEdit selected connectionSnippetsConfigWidgetGelieve een waarde in te vullen voor de code van snippet <strong>%1</strong>!KEmpty code for snippet %1. Please, specify a value for it!SnippetsConfigWidgetGelieve een waarde in te vullen voor het label van snippet <strong>%1</strong>!LEmpty label for snippet %1. Please, specify a value for it!SnippetsConfigWidgetFilter:Filter:SnippetsConfigWidgetVensterFormSnippetsConfigWidgetAlgemeenGeneralSnippetsConfigWidgetAlgemeen doelGeneral purposeSnippetsConfigWidgetID:ID:SnippetsConfigWidget$Een ongeldig ID patroon werd gedetecteerd. Deze moet starten met minstens n letter en worden gevormed door letters, nummer en/or een underscore!Invalid ID pattern detected %1. This one must start with at leat one letter and be composed by letters, numbers and/or underscore!SnippetsConfigWidget Label:Label:SnippetsConfigWidgetVHet snippet bevat geen syntactische fouten.&No syntax errors found in the snippet.SnippetsConfigWidgetOntleedbaarParsableSnippetsConfigWidget>Ontleedbare of dynamische snippets worden in de <strong>schema micro language</strong> syntax geschreven. Wanneer een ontleedbaar snippet wordt gebruikt worden attributen die met <strong>{}</strong> zijn omringd, vervangen door de attributen van het overeenkomstige geselecteerde object.Parsable or dynamic snippets are written in the schema micro language syntax. When using a parsable snippet the attributes surrounded in {} will be replaced by the selected object's matching attributes.SnippetsConfigWidgetOntleedParseSnippetsConfigWidgetOntleed het snippet om zeker te zijn dat het geen syntactische fouten bevat.?Parse the snippet in order to check if there are syntax errors.SnippetsConfigWidgetPlaatshouder PlaceholdersSnippetsConfigWidget"Alles Verwijderen Remove AllSnippetsConfigWidgetShift+Del Shift+DelSnippetsConfigWidgetSnippets: Snippets:SnippetsConfigWidgetHet dynamische snippet bevat n of meer syntactische fouten. Bijkomende info: <br/><em>%1</em>OThe dynamic snippet contains syntax error(s). Additional info:
%1SnippetsConfigWidgetUpdatenUpdateSnippetsConfigWidgethBij ontleedbare snippets worden lege attributen vervangen door een waarde volgens het formaat <strong>{attribuut}</strong>. Deze optie kan de betekenis van het snippet benvloeden.When handling parsable snippets empty attributes will be replaced by a value in the format {attribute}. Note that this option can affect the semantics of the resulting snippet.SnippetsConfigWidget&-- LET OP: de volgende code bevat SQL voor zowel het geselecteerde object -- alsook zijn afhankelijken kinderen (indien zo aangevinkt). -- -- Dit feature bestaat enkel zodat u op een eenvoudige manier de volledige -- SQL definitie van het object kan testen. -- -- Bij het exporteren of genereren van de SQL code voor de volledige database -- worden alle objecten in hun originele positie geplaatst. |-- NOTE: the code below contains the SQL for the selected object -- as well for its dependencies and children (if applicable). -- -- This feature is only a convinience in order to permit you to test -- the whole object's SQL definition at once. -- -- When exporting or generating the SQL for the whole database model -- all objects will be placed at their original positions. SourceCodeWidgett-- Er is geen SQL code beschikbaar voor dit type object --2-- SQL code unavailable for this type of object --SourceCodeWidget<!-- XML codevoorbeelden zijn niet beschikbaar in de demo-versie -->;SourceCodeWidgetCodeweergave: Code display:SourceCodeWidget<De broncode wordt gegeneerd...Generating source code...SourceCodeWidgetOrigineelOriginalSourceCodeWidget:Origineel + SQL voor kinderenOriginal + children's SQLSourceCodeWidgetDOrigineel + SQL voor afhankelijkenOriginal + depedencies' SQLSourceCodeWidgetPostgreSQL PostgreSQLSourceCodeWidgetSQLSQLSourceCodeWidgetLSQL Code (*.sql);;Alle bestanden (*.*)!SQL code (*.sql);;All files (*.*)SourceCodeWidgetSla SQL OpSave SQLSourceCodeWidget,Sla SQL code op als...Save SQL code as...SourceCodeWidgetDSla de SQL code op in een bestand.Save the SQL code to a file.SourceCodeWidget(BroncodevisualisatieSource code visualizationSourceCodeWidgetVersie:Version:SourceCodeWidgetXMLXMLSourceCodeWidget iconecodigoSourceCodeWidget Voor:Before:SwapObjectsIdsWidgetAanmaken:Create:SwapObjectsIdsWidgetFilter:Filter:SwapObjectsIdsWidgetIDIDSwapObjectsIdsWidgetID:ID:SwapObjectsIdsWidget ObjectObjectSwapObjectsIdsWidgetOuder Object Parent ObjectSwapObjectsIdsWidgetOuder Type Parent TypeSwapObjectsIdsWidget0Wissel de veldwaarden omSwap the values of the fieldsSwapObjectsIdsWidget(Wissel de waarden om Swap valuesSwapObjectsIdsWidgetTypeTypeSwapObjectsIdsWidgetBTabellen kunnen slechts `%1' instancies per kind-object type of voorouder-tabellen hebben in demonstratie-versies! U heeft deze limiet bereikt voor het type `%2'In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2'Tablenieuwe_tabel new_tableTable Ctrl+ECtrl+ETableDataWidget Ctrl+VCtrl+VTableDataWidgetDelDelTableDataWidgetInsInsTableDataWidgetPlakkenPasteTableDataWidgetShift+Del Shift+DelTableDataWidgetRelatie: %1 Relationship: %1TableObjectView KopieCopy TableWidgetStandaardwaarde Default Value TableWidget EventEvent TableWidget EventsEvents TableWidgetUitvoering Execution TableWidgetAfvuringFiring TableWidgetPGenereer ALTER voor kolommen/constraints&Generate ALTER for columns/constraints TableWidgetIndexeringIndexing TableWidgetNaamName TableWidgetNeeNo TableWidgetON DELETE ON DELETE TableWidgetON UPDATE ON UPDATE TableWidget OptiesOptions TableWidget OuderParent TableWidgetRefer. Tabel Refer. Table TableWidget RollenRoles TableWidget SchemaSchema TableWidgetTag:Tag: TableWidgetTypeType TableWidgetNiet geloggedUnlogged TableWidgetMet OIDWith OID TableWidgetJaYes TableWidgetMap: Directory:TablespaceWidgetVensterFormTablespaceWidgetInhoud:Body: TagWidgetKleurenColors TagWidget&Uitgebreide inhoud:Extended body: TagWidgetSchemanaam: Schema name: TagWidgetTabelnaam: Table name: TagWidget Titel:Title: TagWidgetTaken uitvoerenExecuting tasksTaskProgressWidgetJWachten op het starten van de taak...Waiting task to start...TaskProgressWidgetVetBold TextboxWidget Kleur:Color: TextboxWidgetLettertype:Font: TextboxWidgetCursiefItalic TextboxWidget(Selecteer tekstkleurSelect text color TextboxWidget TekstText TextboxWidgetOnderstrepen Underline TextboxWidgetptpt TextboxWidgetArgument: Argument: TriggerWidgetArgumenten Arguments TriggerWidget KolomColumn TriggerWidget Kolom:Column: TriggerWidgetKolommenColumns TriggerWidgetVoorwaarde: Condition: TriggerWidgetConstraint Constraint TriggerWidget DELETEDELETE TriggerWidgetUitstelbaar: Deferrable: TriggerWidget Event:Event: TriggerWidgetUitvoer: Excution: TriggerWidgetFOR EACH ROW FOR EACH ROW TriggerWidgetFunctie: Function: TriggerWidget INSERTINSERT TriggerWidgetOpties:Options: TriggerWidgetRefer. Tabel: Refer. Table: TriggerWidgetTRUNCATETRUNCATE TriggerWidgetTypeType TriggerWidget UPDATEUPDATE TriggerWidgetANALYZE:ANALYZE: TypeWidgetUitlijning: Alignment: TypeWidgetAttributen Attributes TypeWidgetBasistype Base Type TypeWidgetPer waardeBy value TypeWidget"Canonische Func.:Canonical Func.: TypeWidgetCategorie: Category: TypeWidgetSorteerbaar Collatable TypeWidgetSortering Collation TypeWidgetSortering: Collation: TypeWidgetConfiguratie:Configuration: TypeWidget Standaardwaarde:Default Value: TypeWidgetDelimiter: Delimiter: TypeWidgetElementtype Element Type TypeWidgetEnumeratie Enumeration TypeWidgetEnumeratie: Enumeration: TypeWidgetEnumeraties Enumerations TypeWidgetFuncties Functions TypeWidget INPUT:INPUT: TypeWidgetInterne lengte:Internal Length: TypeWidgetLike type Like Type TypeWidgetNaamName TypeWidget Naam:Name: TypeWidgetOUTPUT:OUTPUT: TypeWidget Operator Klasse:Operator Class: TypeWidgetOpties:Options: TypeWidgetVoorkeur Preferred TypeWidget RECV:RECV: TypeWidget OmvangRange TypeWidget SEND:SEND: TypeWidgetOpslag:Storage: TypeWidgetSubtypeSubtype TypeWidget&Subtype Diff Func.:Subtype Diff Func.: TypeWidgetTPMOD_IN: TPMOD_IN: TypeWidgetTPMOD_OUT: TPMOD_OUT: TypeWidgetDe functies die aan een omvang worden toegewezen moeten de volgende signatures bezitten:<br/><br/><strong>Canonish:</strong> <em>any functie(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision functie(subtype, subtype)</em>The functions to be assigned to a range type should have the following signatures:

Canonical: any function(any)
Subtype Diff: double precision function(subtype, subtype) TypeWidgetDe functies die worden toegewezen aan een type moeten in de C programmeertaal zijn geschreven en moeten, respectievelijk de volgende signatures bezitten:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any functie(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring functie(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta functie(any)</em></td> <td><strong>RECV:</strong> <em>any functie(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer functie(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring functie(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean functie(internal)</em></td> <tr> </table>The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:
INPUT: any function(cstring, oid, integer) OUTPUT: cstring function(any)
SEND: byta function(any) RECV: any function(internal, oid, integer)
TPMOD_IN: integer function(cstring[]) TPMOD_OUT: cstring function(integer)
ANALYZE: boolean function(internal)
 TypeWidgetTypeType TypeWidgetcharchar TypeWidget double precisiondouble precision TypeWidgetintegerinteger TypeWidgetsmallintsmallint TypeWidget......UpdateNotifierWidget 0.0.00.0.0UpdateNotifierWidgetAanpassingen ChangelogUpdateNotifierWidgetPHet ophalen van update informatie faaldeFailed to check updatesUpdateNotifierWidget4Verkrijg een binair pakketGet binary packageUpdateNotifierWidget(Verkrijg de broncodeGet source codeUpdateNotifierWidget$Verberg dit widgetHide this widgetUpdateNotifierWidget&Geen nieuwe updatesNo updates foundUpdateNotifierWidgetBLeidt naar de broncode op GitHub.&Redirects to GitHub source repository.UpdateNotifierWidget8Leidt naar de aankooppagina.Redirects to purchase page.UpdateNotifierWidgetReleasedatum: Released in:UpdateNotifierWidgetHet ophalen van nieuwe versie informatie faalde! De volgende HTTP status code werd gegenereerd: <strong>%1</strong>jThe update notifier failed to check for new versions! A HTTP status code was returned: %1UpdateNotifierWidget&Update AankondigingUpdate NotifierUpdateNotifierWidgetZDit is de meest recente versie van pgModeler!DYou are running the most recent pgModeler version! No update needed.UpdateNotifierWidgetmmm dd, yyyy mmm dd, yyyyUpdateNotifierWidget/* De SQL code kon niet worden gegenereerd. Kijk na of alle attributen correct zijn ingevuld! S/* Could not generate the SQL code. Make sure all attributes are correctly filled!  ViewWidget AliasAlias ViewWidgetAlias Kol. Alias Col. ViewWidgetCodevoorbeeld Code Preview ViewWidgetKol./Expr. Col./Expr. ViewWidget KolomColumn ViewWidgetKolomalias: Column Alias: ViewWidget Kolom:Column: ViewWidget EventEvent ViewWidget EventsEvents ViewWidgetUitvoering Execution ViewWidgetExpressie Expression ViewWidgetExpressiealias:Expression Alias: ViewWidgetExpressie: Expression: ViewWidgetAfvuringFiring ViewWidgetIndexenIndexes ViewWidgetIndexeringIndexing ViewWidget Modus:Mode: ViewWidgetNaamName ViewWidget OptiesOptions ViewWidget GewoonOrdinary ViewWidgetRefer. Tabel Refer. Table ViewWidgetReferentietype:Reference Type: ViewWidgetReferenties References ViewWidget RegelsRules ViewWidgetTabelalias: Table Alias: ViewWidgetTabelexpressieTable Expression ViewWidget Tabel:Table: ViewWidgetTag:Tag: ViewWidgetTriggersTriggers ViewWidgetGebruikt in:Used in: ViewWidgetViewdefinitieView Definition ViewWidgetZonder data With no data ViewWidgetVensterForm WelcomeWidgetVorige sessie Last session WelcomeWidgetNieuw model New model WelcomeWidgetOpen model Open model WelcomeWidget Recente modellen Recent models WelcomeWidget"Voorbeeldmodellen Sample models WelcomeWidgetpgmodeler-0.9.2/lang/nl_NL.ts000066400000000000000000024756061360462764600160350ustar00rootroot00000000000000 AboutWidget About pgModeler Over pgModeler 0.0.0 0.0.0 build: PostgreSQL Database Modeler PostgreSQL Database Modeler Open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand, let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards. Een Open Source data modeleer tool ontworpen voor PostgreSQL. Met pgModeler hoef je niet langer zelf je DDL commando's schrijven, laat dit over aan pgModeler! Deze software brengt de concepten van Entity-Relationship diagrammen samen met de features die PostgreSQL implementeerd als uitbreidingen van de SQL standaard. <html><head/><body><p><a href="http://pgmodeler.com.br"><span style=" text-decoration: underline; color:#2980b9;">https://pgmodeler.io</span></a></p></body></html> <html><head/><body><p>Copyright 2006-2018 - Raphael Araújo e Silva &lt;<a href="mailto:raphael@pgmodeler.com.br"><span style=" text-decoration: underline; color:#0057ae;">raphael@pgmodeler.io</span></a>&gt;</p></body></html> pgModeler is proudly a brazilian software! pgModeler is trotse braziliaanse software! Hide this widget Verberg dit widget ... (BUILD_NUM) License Licensie AggregateWidget Final Function: Finale functie: Sort Operator: Sorteer-operator: Initial Condition: Initiële Vereiste: Funtion Inputs Functie Invoer Function State Functie Staat Transition Func.: Overgangsfunctie: Input Data Type Invoer Data Type State Data Type Status Data Type An aggregate function that accepts the types <em><strong>typeA</strong></em> and <em><strong>typeB</strong></em> as input types and which type of state is <em><strong>state_type</strong></em>, must obey the following rules: <br/><br/> <strong> &nbsp;&nbsp;&nbsp;• Final Function:</strong> <em>void final_function(<strong>state_type</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp;• Transition Function:</strong> <em><strong>state_type</strong> transition_function(<strong>state_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em> Een aggregatie-funtie die de types <em><strong>typeA</strong></em> en <em><strong>typeB</strong></em> als invoer aanvaardt en waarvan het status-type <em><strong>status_type</strong></em> is. De volgende regels moeten voldaan zijn: <br/><br/> <strong>&nbsp;&nbsp;&nbsp;• Finale Functie:</strong> <em>void finale_functie(<strong>status_type</strong>)</em><br/> <strong>&nbsp;&nbsp;&nbsp;• Overgangsfunctie:</strong> <em><strong>status_type</strong> transitie_functie(<strong>status_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em> AppearanceConfigWidget Form Venster Element: Element: Global: Font style Algemeen: Lettertype Global: Constraints descriptor Algemeen: Constraints beschrijving Global: Object selection Algemeen: Object selectie Global: Position hint text Algemeen: Positie hint tekst Global: Position hint box Algemeen: Positie hint box Global: Objects type Algemeen: Object-type Global: Lock arc Algemeen: Lock arc Global: Lock body Algemeen: Lock body Table: Schema name Tabel: Schemanaam Table: Table name Tabel: Tabelnaam Table: Columns box Tabel: Kolom box Table: Extended attributes box Tabel: Uitgebreide attributen box Table: Title box Tabel: Titel box Rule: Name Regel: Naam Rule: Descriptor Regel: Beschrijving Index: Name Index: Naam Index: Descriptor Index: Beschrijving Trigger: Name Trigger: Naam Trigger: Descriptor Trigger: Beschrijving Constraint: Name Constraint: Descriptor View: Schema name View: Schemanaam View: View name View: View-naam View: References box View: Referenties box View: Extended attributes box View: Uitgebreide attributen box View: Title box View: Titel box View: Table / columns alias View: Tabel / Kolom alias View: Referenced column View: Gerefereerde kolom View: Referenced table View: Gerefereerde tabel View: Reference descriptor View: Referentiebeschrijving Textbox: Body Tekst box: Inhoud Column: Column name Kolom: Kolom naam Column: Descriptor Kolom: Beschrijving Column: Included / Inherited by relationship Kolom: Ingesloten / Overgeërfd via relatie Column: Protected Kolom: Beschermd Column (pk): Column name Kolom (pk): Kolom naam Column (pk): Descriptor Kolom (pk): Beschrijving Column (fk): Column name Kolom (fk): Kolom naam Column (fk): Descriptor Kolom (fk): Beschrijving Column (uq): Column name Kolom (uq): Kolom naam Column (uq): Descriptor Kolom (uq): Beschrijving Column (nn): Column name Kolom (nn): Kolom naam Column (nn): Descriptor Kolom (nn): Beschrijving Relationship: Descriptor Relatie: Beschrijving Relationship: Label text Relatie: Label tekst Relationship: Label box Relatie: Label box Relationship: Attribute text Relatie: Attribuut tekst Relationship: Attribute descriptor Relatie: Attribuut beschrijving Tag: Name Tag: Naam Tag: Body Tag: Inhoud Placeholder: Body Font: Lettertype: Colors: Kleuren: pt pt Underline Onderstrepen Italic Cursief Bold Vet Application Unknown exception caught! Een onbekende uitzondering trad op! Failed to create initial configuration in `%1'! Check if the current user has write permission over that path and at least read permission over `%2'. De initiële configuratie kon niet worden gecreëerd in `%1'! Kijk na of de huidige gebruiker schrijf-machtigingen heeft op dit pad en minstens lees-machtigingen op '%2'. BaseConfigWidget A backup of the previous settings was saved into <strong>%1</strong>! BaseForm Dialog Dialoogvenster &Apply &Toepassen &Cancel &Annuleren &Ok &Ok %1 properties BaseObject Column Kolom Constraint Constraint Function Functie Trigger Trigger Index Index Rule Regel Table Tabel View View Domain Domein Schema Schema Aggregate Aggregator Operator Operator Sequence Sequentie Role Rol Conversion Conversie Cast Cast Language Taal Type Type Tablespace Tablespace Operator Family Operator Familie Operator Class Operator Klasse Database Database Collation Sortering Extension Uitbreiding Event Trigger Event Trigger Relationship Relatie Policy Textbox Tekst box Permission Machtiging Parameter Parameter Type Attribute Type Attribuut Tag Tag Basic Relationship Basisrelatie Generic SQL new_object nieuw_object nieuwe_objecten BaseObjectView SQL off SQL uit BaseObjectWidget Name: Naam: Comment: Commentaar: Tablespace: Tablespace: Schema: Schema: Edit object's permissions Machtiginen voor dit object aanpassen Edit permissions Machtigingen aanpassen This object is protected thus no change in form will be applied to it. Dit object is beschermd en dus worden vorm-aanpassingen niet toegepast. Disables the generated SQL code using comment tokens (--). This will disable the code of all child and referrer objects. Maakt de gegenereerde SQL code onuitvoerbaar via comment-tokens (--). Dit zorgt ervoor dat de code voor alle kinder-objecten en refererende objecten wordt uitgeschakeld. Disable SQL code Niet-uitvoerbare SQL code Collation: Sortering: Append or prepend a set of SQL commands to the object's definition. Voeg SQL commando toe voor of na de definitie van het object. Custom SQL Aangepaste SQL Owner: Eigenaar: ID: ID: icone icone Required field. Leaving this empty will raise errors! Vereist veld. Dit veld leeglaten leidt tot foutmeldingen! Value(s) Waarde(s) Version Versie The <em style='color: %1'><strong>highlighted</strong></em> fields in the form or one of their values are available only on specific PostgreSQL versions. Generating SQL code for versions other than those specified in the fields' tooltips may create incompatible code. BaseRelationship rel_%1_%2 rel_%1_%2 BaseTableView Toggles the extended attributes display Connected rels: %1 Verbonden relaties: %1 BugReportForm Bug Report Bug Rapport Bug report Bug rapport Create Versturen &Cancel &Annuleren Use the form below to generate a complete bug report. Please, try to be as clear as possible when describing the actions that can reproduce the bug. Additionally, it's important to attach a sample database model so that the bug can be quickly discovered and fixed! Gebruik dit formulier om een volledig bug rapport aan te maken. Gelieve zo volledig en duidelijk mogelijk de actie die tot de bug leidden, te beschrijven. Indien mogelijk, voeg een voorbeeld database model toe aan dit rapport zodat de bug snel gevonden en gecorigeerd kan worden! Report Rapport Issue details Probleeminformatie Output: Output: Select the report's output folder Selecteer de output-map voor het rapport ... ... <html><head/><body><p>If you prefer it's possible to report this issue anytime on pgModeler's project repository at <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html> <html><head/><body><p>Indien u wenst kan u bugs ook rapporten via pgModeler's project repository op <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html> Database Model Database Model Attach the below database model file to be debugged. Voeg het database model waarmee het probleem zich voordoet toe. Attach a different database model Voeg een ander database model toe Bug report successfuly generated! Please, send the file <strong>%1</strong> to <em>%2</em> in order be analyzed. Thank you for the collaboration! Het bug rapport werd gegeneerd! Gelieve het bestand <strong>%1</strong> naar <em>%2</em> te sturen zodat het kan worden gebruikt bij het debuggen. Hartelijk dank voor je bijdrage! Load model Laad model Database model (*.dbm);;All files (*.*) Database model (*.dbm);;Alle bestanden (*.*) Select report output folder Selecteer de rapport-uitvoer map BulkDataEditWidget Bulk data edit CastWidget I&mplicit Assignment Toewijzing Input / Output Invoer / Uitvoer Conversion Func.: Conversie-functie: Cast Type: Cast Type: E&xplicit Source data type Bron data type Target data type Doel data type The function to be assigned to a cast from <em><strong>typeA</strong></em> to <em><strong>typeB</strong></em> must have the following signature: <em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>. De functie die wordt gebruikt bij den cast van <em><strong>typeA</strong></em> naar <em><strong>typeB</strong></em> moet de volgende signature hebben:: <em><strong>typeB</strong> functie(<strong>typeA</strong>, integer, boolean)</em>. CodeCompletionWidget Make &persistent Makes the widget closable only by ESC key or mouse click on other controls. Zorgt ervoor dat widgets enkel kunnen worden gesloten via de ESC toets of via een muisklik op andere controls. SQL Keyword SQL Sleutelwoord (no items found.) (geen items gevonden.) CollationWidget Locale: Locale: Encoding: Codering: LC_COLLATE: LC_CTYPE: The fields <strong><em>Collation</em></strong>, <strong><em>Locale</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> are mutually exclusive, so you have to set only one of them in order to properly handle a collation. De velden <strong><em>Sortering</em></strong>, <strong><em>Locale</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> zijn onderling uitsluitend, om een sortering correct te gebruiken hoeft u slechts één van deze velden in te stellen. Not defined Niet gedefinieerd ColorPickerWidget Form Venster Generate random color(s) Genereer willekeurige kleur(en) Alt+R Alt+R Select color Selecteer kleur ColumnWidget Default Value: Standaardwaarde: Edit the underlying sequence's attributes Edit sequence Identity: E&xpression: &NOT NULL Se&quence: ConfigurationForm pgModeler Configuration pgModeler Configuratie General Algemeen Relationships Relaties Appearance Voorkomen Connections Verbindingen Snippets Snippets Plug-ins Plug-ins Defaults Standaard waarden &Apply &Toepassen &Cancel &Annuleren In some cases restore the default settings related to it may solve the problem. Would like to do that? Restore Any modification made until now in the current section will be lost! Do you really want to restore default settings? De waarden in de huidige sectie zullen worden overschreven! Bent u er zeker van dat u de standaard waarden wilt instellen? ConnectionsConfigWidget Password: Wachtwoord: Connection Alias: Verbindingsalias: Connection DB: Verbinding DB: Host/Port: Host/Poort: User: Gebruiker: Timeout: Timeout: SSL Mode: SSL Modus: Disable Uit Diff Diff Export Exporteer Import Importeren Validation Security Allow Toegelaten Require Vereist AC verification AC verificatie Full verification Volledige verificatie Kerberos Server: Client Certificate: Client Certificaat: Revoked Certs.: Herroepen Certs: Client Key: Client Sleutel: Root Certificate: Root Certificaat: ~/.postgresql/root.crt Connections: Verbindingen: second(s) Second(en) Force GSSAPI Forceer GSSAPI ~/.postgresql/postgresql.crt Add Toevoegen Update Updaten Test Test ~/.postgresql/root.crl ~/.postgresql/postgresql.key Create new connection Maak een nieuwe verbinding Edit database connections Cancel edition Annuleer aanpassingen Duplicate the selected connection Dupliceer de geselecteerde verbinding Edit selected connection Pas de geselecteerde verbinding aan Delete selected connection Verwijder de geselecteerde verbinding General Algemeen Other params: Specify additional connection parameters in the form [param]=[value]. These parameters are described in the <strong>libpq</strong> chapter at PostgreSQL docs. Default for: Automatically browses the named database when using this connection to manage databases on <strong>Manage</strong> view. Bladert automatisch door de genoemde database wanneer deze verbinding wordt gebruikt om databases te beheren via de <strong>Beheer</strong> view. Auto browse Indicates in which operations (diff, export, import or validation) the connection is used if none is explicitly specified by the user. Success Success Connection successfully established! Server details: PID: `%1' Protocol: `%2' Version: `%3' There is a connection being created or edited! Do you want to save it? Wenst u de nieuwe of aan te passen verbinding op te slaan vooraleer verder te gaan? Found %1 connection(s) %1 verbinding(en) gevonden No connections found Geen verbindingen gevonden Edit connections ConstraintWidget Match: Evenaar: Constraint Type: Constraint Type: This attribute cannot be changed once the object is created. Dit attribuut kan niet worden aangepast eens het object is aangemaakt. Expression: Expressie: Deferrable: Uitstelbaar: Deferral: Uitstel: ON DELETE: ON UPDATE: No inherit: Geen overerving: Exclude Elements Elementen Uitsluiten Columns Kolommen Column: Kolom: Referenced Columns Gerefereerde Kolommen Table: Tabel: Indexing: Indexering: Fill Factor: Vul-factor: Column Kolom Type Type Columns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form. Kolommen die werden ingesloten via relaties kunnen niet manueel worden toegevoegd aan of verwijderd uit de primaire sleutel. Dit soort aanpassingen kan tot fouten leiden. Om een primaire sleutel aan te maken via kolommen die werden ingesloten door relaties, gebruik de volgende opties: identifier veld, attributen & constraints tab-blad of primaire sleutel tab=blad in het relatie-venster. ConversionWidget Source Encoding: Broncodering: Target Encoding: Doelcodering: Conversion Func.: Conversie-functie: Default Conversion: Standaard Conversie: The function to be assigned to an encoding conversion must have the following signature: <em>void function(integer, integer, cstring, internal, integer)</em>. Een functie die wordt toegewezen aan een coderingsconversie met de volgende signature hebben: <em>void functie(integer, integer, cstring, internal, integet)</em>. CrashHandlerForm Crash Handler Crash Handler Stack trace Stack trace Input: Invoer: Load report file for analysis Laad rapport bestand voor analyze Save the attached model file on the filesystem Bewaar het ingevoegde model bestaand op het bestandssysteem pgModeler bug report (*.bug);;All files (*.*) pgModeler bug rapport (*.bug);;Alle bestanden (*.*) Load report Laad rapport Save model Bewaar model Database model (*.dbm);;All files (*.*) Database model (*.dbm);;Alle bestanden (*.*) Crash handler Crash Handler Bug report analysis mode activated. Bug rapport analyze modus is geactiveerd. Oops! pgModeler just crashed! Oeps! pgModeler crashte! We apologize for what happened! It is clear that a nasty bug caused that. Please fill out the form below describing your actions before pgModeler quit unexpectedly. This will help on bug extermination and improve the software. We verontschuldigen ons voor wat net gebeurde! Het is overduidelijk dat een ernstige bug dit veroorzaakte. Gelieve het formuleer hieronder in te vullen met een beschrijving van wat u deed vooraleer pgModeler onverwachts afsloot. Dit zal ons helpen om deze bug te corrigeren en de software te verbeteren. CsvLoadWidget Form Venster Load CSV CSV File: Select output file Selecteer uitvoerbestand ... ... Separator: Use the first row as column names in the CSV file. By unchecking this option the first row is used as data. Columns in the first row Load Laden Semicolon (;) Comma (,) Space Spatie Tabulation Other ; Text delimiter: " Load CSV file Comma-separted values (*.csv);;All files (*.*) CustomSQLWidget Add custom SQL code SQL code SQL code Puts an SELECT command template at current cursor position. Plaatst een SELECT commando-sjabloon op de huidige positie van de cursor. &SELECT &SELECT Puts an INSERT command template at current cursor position. Plaatst een INSERT commando-sjabloon op de huidige positie van de cursor. &INSERT &INSERT Puts an UPDATE command template at current cursor position. Plaatst een UPDATE commando-sjabloon op de huidige positie van de cursor. &UPDATE &UPDATE Puts an DELETE command template at current cursor position. Plaatst een DELETE commando-sjabloon op de huidige positie van de cursor. &DELETE &DELETE &Clear &Leegmaken Append SQL Nagevoegde SQL Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command. Plaats de SQL code op het einde van de modeldefinitie. Deze optie afvinken zorgt ervoor dat de SQL wordt ingevoegd na het CREATE DATABASE commando. Append at end of model definition. Voeg toe aan het einde van de modeldefinitie. Prepend SQL Voorgevoegde SQL Prepend at beginning of model definition. Voeg toe aan het begin van de modeldefinitie. <html><head/><body><p>Use custom commands with extreme caution because you can change the semantics of the entire model when running SQL validation or export processes. Additionally, depending on the amount of commands, those processes can have their performance sensibly degradated.</p></body></html> <html><head/><body><p>Wees voorzichtig bij het gebruik van aangepaste SQL. Dit kan leiden tot een verandering van de betekenis van het volledige model wanneer SQL validatie wordt uigevoerd of wanneer het model wordt geëxporteerd. Het is ook mogelijk, afhankelijk van de hoeveelheid commando's, dat de prestaties van deze processen voelbaar en negatief kunnen worden beïnvloed.</p></body></html> Generic INSERT Generische INSERT Include serial columns Sluit seriële kolommen in Exclude serial columns Sluit seriële kolommen uit Generic SELECT Generische SELECT Table SELECT Tabel SELECT Generic UPDATE Generische UPDATE Table UPDATE Tabel UPDATE Generic DELETE Generische DELETE Table DELETE Tabel DELETE DataManipulationForm Data Manipulation Datamanipulatie &Close &Sluiten Refresh listing De lijst wordt vernieuwd F5 F5 Save changes Aanpassingen opslaan Ctrl+S Ctrl+S Export results to CSV file Exporteer de resultaten naar een CSV bestand Ctrl+X Ctrl+X Undo modifications Aanpassingen ongedaan maken Ctrl+Z Ctrl+Z Ins Ins Mark the selected rows to be deleted Markeer de geselecteerde rij als 'te verwijderen' Del Del Duplicate the selected rows Ctrl+D Add new rows from a CSV file Filter the result set Filter de resultaten Table: Tabel: Schema: Schema: in in Hide views Verberg views Filter expression Filterexpressie Order && Limit Sortering && Limiet results (Use <strong>0</strong> for no limit) Column: Kolom: <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> Copy items on the grid Paste items on the grid Ctrl+V Ctrl+V Browse referenced tables Change the values of all selected cells at once Ctrl+E Ctrl+E ASC ASC Add empty rows DESC DESC Limit in: Limiet in: Add Item Item Toevoegen Remove Item Item Verwijderen Clear the order by columns list Maak de sorterings-kolomlijst leeg Move selected item up Verplaats het geselecteerde item naar boven Move selected item down Verplaats het geselecteerde item naar beneden Copy as CSV Copy as text Copy items Pase items Browse tables Duplicate row(s) Delete row(s) Edit cell(s) <strong>WARNING: </strong> There are some changed rows waiting the commit! Do you really want to discard them and retrieve the data now? Rows returned: <strong>%1</strong>&nbsp;&nbsp;&nbsp; <em>(Limit: <strong>%1</strong>)</em> <em>(Limiet: <strong>%1</strong>)</em> none Column Kolom No objects found Geen objecten gevonden Found %1 object(s) %1 object(en) gevonden Views can't have their data handled through this grid, this way, all operations are disabled. Data van views kan niet worden aangepast via dit raster, alle operaties zijn uitgeschakeld. The selected table doesn't owns a primary key! Updates and deletes will be performed by considering all columns as primary key. <strong>WARNING:</strong> those operations can affect more than one row. De geselecteerde tabel bevat geen primary key! Update en delete commando's worden uitgevoerd door alle kolommen als primary key te beschouwen. <strong>OPGEPAST</strong> deze acties kunnen meer dan één rij beïnvloeden. Referenced tables (none) Referrer tables This row is marked to be %1 Deze rij is als %1 gemarkeerd. deleted verwijderd updated aangepast inserted ingevoegd [binary data] [binaire data] <strong>WARNING:</strong> Once commited its not possible to undo the changes! Proceed with saving? <strong>OPGEPAST: </strong> Eens toegepast is het niet langer mogelijk om aanpassingen ongedaan te maken! Bent u zeker dat u wilt opslaan? delete delete update update insert insert DatabaseExplorerWidget Form Venster Data &Grid Data &Grid Alt+G Alt+G ... ... Open the grid to visualize or edit data Open a new SQL execution pane Ctrl+F6 Ctrl+F6 Update the objects tree Toggle the display of filter widget as well the system/extension objects. Sort items alphabetically. When unchecked, items are sorted by OID. Sort alphabetically Drop this database Verwijder deze database Expands all items Alle items uitklappen Collapses all items Alle items inklappen Filters the currently loaded items in the tree by using a pattern and matching their names. If <strong>By OID</strong> is checked the pattern is interpreted as an integer value that represents the object id (OID). <br><br/><strong>HINT:</strong> if you need to search the entire database use the full refresh (<strong>Ctrl+F5</strong>) prior the filtering. Filter: Filter: By OID Per OID Attribute Attribuut Value Waarde Show raw attributes (not found, OID: %1) (niet gevonden, OID: %1) -- Source code not generated! Hit F7 or middle-click the item to load it. -- Admin. roles Admin. rollen Alignment Uitlijning Analyze func. Analyzeer func. Arg. count Aantal Argumenten Arg. default count Standaard aantal argument Arg. defaults Standaardargumenten Arg. modes Argumentenmodus Arg. names Argumentennamen Arg. types Argumententypes Behavior type Gedragstype By value Per waarde Cast type Cast type Category Categorie Collatable Sorteerbaar Collation Sortering Comment Commentaar Commutator Op. Commutator Op. Configuration Configuratie Conn. limit Verbindingslimiet Constraint Constraint Create DB Maak DB aan Create role Maak rol aan Curr. version Huidige versie Default Standaard Default value Standaardwaarde Definition Definitie Delimiter Delimiter Dest. type Doeltype Dimension Dimensie Directory Map Dest. encoding Doelcodering Element Element Encoding Codering Encrypted Geëncrypteerd Enumerations Enumeraties Exec. cost Uitvoeringskost Expression Expressie Op. family Operator Familie Final func. Finale functie Function Functie Func. type Functietype Handler func. Behandelende Functie Handles type Behandelt type Hashes Hashes Index type Indextype Inherit Erft over Ini. condition Initiële Vereiste: Inline func. Inline Functie Input func. Invoerfunctie Internal length Interne lengte Interval type Intervalstype I/O cast I/O cast Join func. Join func. Language Taal LC COLLATE LC COLLATE LC CTYPE LC CTYPE Leak proof Lekdicht Left type Linkse type Length Lengte Library Bibliotheek Can login Kan inloggen Materialized Gematerialiseerd Member roles Lid-rollen Merges Samenvoegingen Name Naam Negator op. Negator op. Not null Niet null Object type Objecttype OID OID With OIDs Met OIDs Old version Oude versie Operator Operator Operator func. Operator functie Output func. Uitvoerfunctie Owner Eigenaar Owner column Bezittende kolom Parents Ouders Password Wachtwoord Permissions Machtigingen Precision Precisie Preferred Voorkeur Range attributes Omvangsattributen Receive func. Ontvangersfunctie Ref. roles Ref. rollen Replication Replicatie Restriction func. Belemmeringsfunctie Return type Resultaatstype Returns SETOF Geeft SETOF terug Right type Rechtse type Rows amount Aantal rijen Schema Schema Security type Beveiligingstype Send func. Zendfunctie Sort op. Sorteeroperato Source type Brontype Src. encoding Broncodering State type Statustype Storage Opslag Superuser Superuser Tablespace Tablespace Type mod. in func. Type mod. in functie Type mod. out func. Type mod. buiten functie Transition func. Transitiefunctie Trusted Vertrouwd Type Type Type attribute Typeattribuut Types Types Unlogged Niet gelogged Validator func. Validatiefunctie Validity Geldigheid Windows func. Windowing func. false onwaar true waar Cache value Cachewaarde Cycle Cyclus Increment Toename Max. value Max. waarde Min. value Min. waarde Start value Startwaarde Last value Laatste waarde Subtype Subtype Op. class Op. klasse Canonical func. Canonische func. Subtype diff func. Subtype diff func. Deferrable Uitstelbaar For each row Voor elke rij Firing Afvuring On insert Bij insert On delete Bij delete On update Bij update On truncate Bij truncate Arguments Argumenten Table Tabel Trigger func. Trigger func. Columns Kolommen Condition Voorwaarde Deferment Uitstel Event Event Execution mode Uitvoeringsmodus Commands Commando's Position Positie Comparison type Vergelijkingstype Ref. columns Ref. columns Expressions Expressies Fill factor Vulfactor No inherit Geen overerving Op. classes Op. klasses Operators Operators Ref. table Ref. tabel Unique Uniek Predicate Predicaat Collations Sorteringen Inherited Overgeërfd Client encoding Configuration file Data directory Dynamic library path Dynamic shared memory Hba file Listen addresses Max. connections Listen port Server encoding SSL SSL ca file SSL cert file SSL crl file SSL key file Server version Ident file Password encryption Connection ID Server PID Server protocol Referrers Identity Command USING expr. CHECK expr. Roles Rollen RLS enabled RLS forced Show objects filter Show system objects Show extension objects Snippets Snippets Drop object Verwijder object Drop cascade Verwijder cascade Truncate Truncate Trunc. cascade Trunc. cascade Show data Toon data Reload properties Eigenschappen herladen Update Updaten Rename Hernoem Source code Broncode Quick refresh Full refresh -- Source code unavailable for this kind of object -- Do you really want to drop the object <strong>%1</strong> <em>(%2)</em>? Bent u zeker dat u het object <strong>%1</strong> <em>%2</em> wilt verwijderen? Do you really want to <strong>cascade</strong> drop the object <strong>%1</strong> <em>(%2)</em>? This action will drop all the other objects that depends on it. Bent u er zeker van dat u het object &lt;strong&gt;%1&lt;/strong&gt; &lt;em&gt;(%2)&lt;/em&gt; via &lt;strong&gt;cascade&lt;/strong&gt; wilt verwijderen? Deze actie verwijdert ook alle objecten die afhankelijk zijn van dit object. Do you really want to truncate the table <strong>%1</strong>? Bent u zeker dat u de tabel <strong>%1</strong> wil truncaten? Do you really want to <strong>cascade</strong> truncate the table <strong>%1</strong>? This action will truncate all the tables that depends on it? Bent u er zeker van dat u de tabel <strong>%1</strong> <em>(%2)</em> via <strong>cascade</strong> wilt verwijderen? Deze actie verwijdert ook alle tabellen die afhankelijk zijn van deze tabel. Also restart sequences Src. table: %1 Src. column(s): %2 Ref. table: %1 Ref. column(s): %2 -- Source code genaration for buil-in and base types currently unavailable -- -- Source code unavailable for the object %1 (%2). -- Warning Opgepast You're running a demonstration version! The data manipulation feature is available only in the full version! Dit is een demonstratie-versie. De data manipulatie functionaliteit is enkel beschikbaar in de volledige versie! <strong>CAUTION:</strong> You are about to drop the entire database <strong>%1</strong>! All data will be completely wiped out. Do you really want to proceed? <strong>PAS OP:</strong> U staat op het punt om de volledige database <strong>%1</strong> te verwijderen! Alle data zal verloren gaan. Bent u zeker dat u verder wilt gaan? DatabaseImportForm Settings Instellingen Options Opties Connection: Verbinding: Resolve some of the object's dependencies by querying the catalog when a needed object does not exists on the loaded set. In some cases it's necessary to combine this option with others below. This option does not applies to database level objects like role, tablespace and language as well for data types, extensions. Automatically resolve dependencies Los afhankelijkheden automatisch op Random colors will be assigned to imported relationships facilitating the identification of links between tables mainly in large models. Om de identificatie van de links tussen tabellen in grote modellen makkelijker te maken zullen willekeurige kleuren worden gebruikt om de geïmporteerde relaties aan te duiden. Random colors for relationships Willekeurige kleuren voor relaties Enables the import of system built-in objects. It's recommend to select only those objects that are directly referenced by the ones to be imported. WARNING: Try to import a huge set of system objects can bloat the resultant model or even crash pgModeler due to memory/cpu overuse. Activeert het importeren van ingebouwde systeemobjecten. Het is aangeraden om enkel objecten te importeren waarnaar onmiddellijk worden gerefereerd. PAS OP: grote hoeveelheden systeemobjecten importeren kan leiden tot een opgezwollen resultaatsmodel of kan zelfs pgModeler tot een crash leiden omwillen van geheugen- of processor-uitputting. Import database Import system objects Importeer systeemobjecten Enables the import of objects created by extensions. Generally there is no need to check this option but if there are objects in the database that directly references this category of objects this mode must be enabled. Activeert het importeren van objecten die werden aangemaakt door uitbreidingen. Algemeen gezien is er geen nood om deze optie aan te vinken tenzij er objecten in de databse leven die onmiddellijk naar objecten van deze categorie refereren. Import extension objects Importeer uitbreidingsobjecten pgModeler ignores import errors and will try to create as many as possible objects. By checking this option the import operation will be not aborted but an incomplete model will be constructed. This option generates a log file on pgModeler's temp directory. pgModeler negeert importeerfouten en zal pogen om zoveel mogelijk objecten aan te maken. Door deze optie aan te vinken zal de importeer-taak niet afbreken bij een fout maar zal een onvolledig model worden aangemaakt. Deze optie creëert een log bestand in de tijdelijke map voor pgModeler. Ignore import errors Negeer importeerfouten All catalog queries as well the created objects' source code are printed to standard output (stdout). Alle catalogusqueries plus the broncode van de aangemaakte objecten wordt naar de standaard output (stdout) geprint. Debug mode Debugmodus Create all imported objects in the current working model instead of create a new one. Maak alle geïmporteerde objecten aan in het huidige model en maak geen nieuw model aan. Import objects to the working model Importeer de objecten in het huidige model Database Database Filter: Filter: Filter object by it's OID Filter objecten per hun OID By OID Per OID Select all objects Selecteer alle objecten ... ... Clear object selection Maak de objectselectie ongedaan Expands all items Alle items uitklappen Collapses all items Alle items inklappen Output Uitvoer Progress label... Vooruitgangslabel... Cancel Annuleren &Import &Close &Sluiten <strong>ATTENTION:</strong> You are about to import objects to the current working model! This action will cause irreversible changes to it even in case of critical errors during the process. Do you want to proceed? <strong>OPGEPAST:</strong> U staat op het punt om objecten te importeren in het huidige model! Deze actie zal onherroepbare verandering teweegbrengen, zelfs wanneer kritische problemen opduiken gedurende dit proces. Bent u zeker dat u verder wilt gaan? Importing process aborted! Het import proces werd afgebroken! Importing process canceled by user! Het import proces werd geannuleerd door de gebruiker! Importing process sucessfuly ended! Het import proces werd succesvol beëindigt! No databases found Er werd database gevonden Found %1 database(s) Er werd(en) %1 database(s) gevonden Retrieving objects from database... De objecten worden van de database opgehaald... Retrieving cluster level objects... De objecten op cluster-niveau worden opgehaald... Retrieving objects of schema `%1'... De objecten uit schema `%1' worden opgehaald... Retrieving objects of `%1' (%2)... This is a PostgreSQL built-in data type and cannot be imported. Dit is een ingebouwd type van PostgreSQL en kan niet worden geïmporteerd. This is a pgModeler's built-in object. It will be ignored if checked by user. Dit is een ingebouwd object van pgModeler. Dit object wordt genegeerd indien aangevinkt door de gebruiker. DatabaseImportHelper Retrieving system objects... `%1' Systeemobjecten ophalen... `%1' Retrieving objects... `%1' Objecten ophalen... `%1' Creating object `%1' (%2), oid `%3'... Trying to recreate object `%1' (%2), oid `%3'... Creating object `%1' (%2)... Object aanmaken `%1' (%2)... Import failed to recreate some objects in `%1' tries. Het importeren faalde na `%1' pogingen om sommige objecten te her-creëeren. Creating permissions for object `%1' (%2)... Machtigingen aanmaken voor object `%1' (%2)... Creating columns permissions... Kolommachtigingen aanmaken... Updating relationships of `%1' (%2)... Updaten van de relaties voor `%1' (%2)... Validating relationships... The database import ended but some errors were generated and saved into the log file `%1'. This file will last until pgModeler quit. Het importeren van de database is voltooid maar er werden enkele fouten gegenereerd, deze werden opgeslagen in het log-bestand `%1'. Dit bestand zal worden verwijderd wanneer u pgModeler afsluit. Destroying unused detached columns... De vrijstaande kolommen worden verwijderd... Assigning sequences to columns... Creating table inheritances... Tabel-overervingen worden aangemaakt... DatabaseModel The demonstration version can create only `%1' instances of each object type! You've reach this limit for the type: `%2' U kan slechts `%1' instancies per object type aanmaken in demonstratie-versies! U heeft deze limiet bereikt voor het type `%2' Loading: `%1' (%2) Bezig met laden: `%1' (%2) Validating relationships... Generating %1 code: `%2' (%3) Saving object `%1' (%2) Saving metadata of the object `%1' (%2) Metadata file successfully saved! Process successfully ended but no metadata was saved! Creating object `%1' (%2) Object `%1' (%2) wordt aangemaakt. Object `%1' (%2) already exists. Ignoring. Loading metadata for object `%1' (%2) Object `%1' (%2) not found. Ignoring metadata. Metadata file successfully loaded! DatabaseWidget Attributes Attributen LC_COLLATE: LC_CTYPE: Template DB: Sjabloon DB: Model Author: Modelauteur: Encoding: Codering: Connections: Verbindingen: Options: Opties: Allow connections Is template Default Objects Standaardobjecten Tablespace: Tablespace: Schema: Schema: Collation: Sortering: Owner: Eigenaar: The fields <strong>LC_COLLATE</strong> and <strong>LC_CTYPE</strong> have pre-configured values based upon the running system. You can freely modify those values if you intend to export the model to another host. De velden <strong>LC_COLLATE</strong> en <strong>LC_CTYPE</strong> hebben voorgedefinieerde waarden gebasseerd op het lopende systeem. Deze waarden kunnen vrij worden aangepast indien u dit model naar een andere host wenst te exporteren. Use the above fields to specify the default attributes assigned to new objects created on the database model. Leaving a field empty will cause PostgreSQL to use the default values when exporting the model. Gebruik de velden hierboven om de waarden voor standaard attributen die aan nieuwe objecten worden toegewezen, te specifieren. Het veld leeglaten zorgt ervoor dat PostgreSQL zijn standaardwaarden gebruikt bij het exporteren. Default Standaard DomainWidget Attributes Attributen Default Value: Standaardwaarde: Not null Niet null Check constraints Expression: Expressie: Name: Naam: Name Naam Expression Expressie DonateWidget Form Venster Donate to pgModeler Doneer aan pgModeler Hide this widget Verberg dit widget ... ... <html><head/><body><p>pgModeler is brought to you thanks to a <span style=" font-style:italic;">great effort to create and distribute a quality product</span>. This project is reaching out levels of maturity never imagined. All this is the result of a joint work between its author and the <span style=" font-weight:600;">Open Source community</span>. <br/><br/>This software has a long way to go yet and with your help we'll keep maintaining the good job and bringing new improvements on each release. If you did like pgModeler and thinks it deserves a contribution please make a donation!</p></body></html> <html><head/><body><p>pgModeler komt tot stand dankzij <span style=" font-style:italic;">een grote inzet om een kwaliteitsvol product te bezorgen</span>. Dit project heeft een niveau van volwassenheid bereikt die nooit was voorzien. Dit alles is het resultaat van de samenwerken tussen de auteur(s) en de <span style=" font-weight:600;">Open Source gemeenschap</span>. <br/><br/>Dit product heeft nog een lange weg af te leggen; met uw hulp kunnen we deze uitdaging aan en kunnen we nieuwe verbeteringen en toevoegingen aan dit product blijven publiceren bij elke release. Als u vertrouwd op pgMOdeler en denkt dat u kan bijdragen, gelieve dan een donatie te maken aan pgModeler!</p></body></html> I want to help! Ik wil helpen! ElementsWidget Form Venster Column: Kolom: Expression: Expressie: Collation: Sortering: Operator Class: Operator Klasse: Operator: Operator: Sorting: Sortering: Ascending Stijgend Descending Afdalend Nulls first Nulls eerst Element Element Type Type Operator Class Operator Klasse Sorting Sortering Nulls First Nulls eerst Collation Sortering Operator Operator Expression Expressie Yes Ja No Nee EventTriggerWidget Event: Event: Function: Functie: Filter Filter Tag: Tag: Tag command Tag commando Exception Assignment of a pseudo-type to the type of the column! Poging to toewijzing van een pseudo-type als het type van een kolom! Assignment of a precision greater than the length of the type! Toewijzing van een waarde met grotere precisie dan de toegewezen locatie! Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! Toewijzing van een ongeldige precisie aan het type time, timestamp of interval. De precisie moet in dit geval kleiner dan of gelijk zijn aan 6! Assignment of a not allocated column to object `%1' (%2)! Toewijzing van een niet-gealloceerde kolom aan het object `%1' (%2)! Reference to a column which index is out of the capacity of the column list! Referentie naar een kolom wiens index buiten de capaciteit van de kolomlijst ligt! Assignment of not allocated object! Toewijzing van een niet-gealloceerd object! Assignment of a not allocated schema to object `%1' (%2)! Toewijzing van een niet-gealloceerde schema aan het object `%1' (%2)! The object `%1' (%2) has inconsistent SQL or XML definition! het object `%1' (%2) heeft een inconsistente SQL of XML definitie! The object `%1' (%2) already exists on `%3' (%4)! Het object `%1' (%2) bestaat reeds op `%3' (%4)! The object `%1' (%2) cannot be assigned because there is already exists in the container object `%3'! Het object `%1' (%2) kan niet worden toegewezen omdat het reeds bestaat in het container-object `%3'! Assigning object of an invalid type! Toewijzing van een object van een ongeldig type! Removing an object of an invalid type! Verwijdering van een object van een ongeldig type! Obtaining an object of an invalid type! Het verkregen object is van een ongeldig type! Assignment of empty name to table return type! Toewijzing van een lege naam aan een tabel-terugkeertype! The insertion of the parameter `%1' will not be possible because there is another parameter with same name in the function `%2'! Het toevoegen van parameter `%1' is niet mogelijk omdat de functie `%2' reeds een parameter met deze naam bevat! The insertion of the table return type `%1' will not be possible because there is another return type with the same name in the `%2'! Het invoegen van tabel-terugkeertype `%1' is niet mogelijk omdat er reeds een terugkeer-type met deze naam bestaat in `%2'! Reference to a parameter which index is out of the parameter list bounds! Een referentie naar een parameter met een index die buiten de limieten ligt van de parameterlijst! Reference to an event which does not belongs to trigger! Een referentie naar een event die niet tot de trigger behoort! The column `%1' cannot be assigned to the trigger `%2' because they belongs to different parent tables! De kolom `%1' kan niet toegewezen worden aan de trigger `%2' omdat deze tot verschillende ouder-tabellen behoren! Assignment of a not allocated function to object `%1' (%2)! Toewijzing van een niet-gealloceerde functie aan het object `%1' (%2)! Assignment of a function which return type is different from `%1'! Toewijzing van een functie waarvan het terugkeertype verschilt van `%1'! Assignment of a function which parameter count is invalid to the object `%1' (%2)! Toewijzing van een functie waarvan het aantal parameters ongeldig is voor het object `%1' (%2)! Assignment of a function which language is invalid! Toewijzing van een functie waarvan de taal ongeldig is! Event trigger function must be coded in any language other than SQL! Event triggerfunctie moet geschreven zijn in een taal die verschilt van SQL! Assignment of not allocated table to object `%1' (%2)! Toewijzing van een niet-gealloceerde tabel aan object `%1' (%2)! Reference to an argument which index is out of argument list bounds! Referentie naar een argument met een index die buiten de limieten ligt van de argumentenlijst! Assignment of empty name to an object! Toewijzing van een lege naam aan een object! Assignment of a name which contains invalid characters! Toewijzen van een naam die ongeldige karakters bevat! Assignment of a name which length exceeds the maximum of 63 characters! Toewijzing van een naam die de maximumlengte van 63 karakters overtreed! Assignment of schema object which type is invalid! Toewijzing van een schemaobject wiens type ongeldig is! Assignment of tablespace object with invalid type! Toewijzing van een tablespaceobject met een ongeldig type! Assignment of tablespace to an invalid object! Toewijzing van een tablespace aan een ongeldig object! Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique! Toewijzing van een tablespace aan een constraint wiens type ongeldig is! Om tot een tablespace te behoren moet een constraint een primary key of een unieke sleutel zijn! Assignment of owner object which type is invalid! Toewijzing van een eigenaarsobject wiens type ongeldig is! Assignment of owner to an invalid object! Toewijzing van een eigenaar aan een ongeldig object! Assignment of appended or prepended SQL to an invalid object! Toewijzing van toegevoegde of voorgevoegde SQL aan een ongeldig object! Reference to a function with invalid type! Referentie naar een functie met een ongeldig type! Reference to an argument of the operator with invalid type! Referentie naar een argument van de operator met een ongeldig type! Reference to an operator with invalid type! Referentie naar een operator met een ongeldig type! Assignment of value to an invalid option type on role! Toewijzing van een waarde aan een ongeldig optietype van een rol! Reference to an invalid role type! Referentie naar een ongeldig rol-type! The insertion of the role `%1' is not possible because this is already being referenced by role `%2'! Het invoegen van de rol `%1' is onmogelijk omdat deze reeds wordt gerefereerd door rol `%2'! Reference redundancy detected by having the role `%1' referencing the role `%2'! Referentieredundantie gedetecteerd doordat de rol `%1' refereert naar rol `%2'! The role `%1' can not be listed as a member of itself! De rol `%1' kan geen lid zijn van zichzelf! Reference to a role which index is out of role list bounds! Referentie naar een rol wiens index buiten de limieten van de rollelijst ligt! Insertion of empty command to the rule! Invoeging van een leeg commando aan de regel! Reference to a command which index is out of the command list bounds! Referentie naar een commando wiens index buiten de limieten van de commandolijst ligt! Is not possible to create a self generalization/copy relationship! The table can not inherit or copy their own attributes! Het is onmodelijk om een zelf-generalisatie/kopieer-relatie aan te maken! De tabel kan niet van zichzelf erven of zijn eigen attributen kopieren! Assignment of an object that already belongs to another table! Toewijzing van een object dat reeds aan een andere tabel toehoort! Assignment of a schema to the sequence which differs from the schema of the owner table! Toewijzing van een schema aan de sequentie die verschilt van het schema van de eigenaars-tabel! Assignment of an invalid value to one of the sequence attributes! Toewijzing van een ongeldige waarde aan een van de sequentie-attributen! Assignment of a minimum value to the sequence which is greater than the maximum value! Toewijzing van een minimumwaarde die groter is dan de maximumwaarde van de sequentie! Assignment of a start value to the sequence which is extrapolating the range defined by minimum and maximum values! Toewijzing van een startwaarde aan de sequentie die de omvang extrapoleerd als gedefinieerd door de minimum- en maximumwaarden! Assignment of a null increment value to the sequence! Toewijzing van een null-vermeerdering aan de sequentie! Assignment of null cache value to the sequence! Toewijzing van null-cachewaarden aan de sequentie! Assignment of owner table which is not in the same schema as the sequence `%1'! Toewijzing van een eigenaarstabel die zich niet in hetzelfde schema bevindt als de sequentie `%1'! Assignment of owner table which does not belong to the same owner of the sequence `%1'! Toewijzing van een eigenaarstabel die niet tot dezelfde eigenaar behoort als de sequentie `%1'! Assignment of a nonexistent owner column to the sequence `%1'! Toewijzing van een niet-bestaande eigenaarskolom aan de sequentie `%1'! Assignment of an owner column to the sequence `%1' that is not related to any table! Toewijzing van een eigenaarskolom aan de sequentie `%1' die aan geen enkele tabel gerelateerd is! Reference to a label which index is out of labels list bounds! Referentie naar een label wiens index buiten de limieten ligt van de label-lijst! Allocation of object with invalid type! Allocatie van een object met ongeldig type! Assignment of a function with invalid return type to object `%1' (%2)! Toewijzing van een functie met een ongeldige terugkeerwaarde aan object `%1' (%2)! Assignment of a function with invalid parameter(s) type(s) to object `%1' (%2)! Toewijzing van een functie met ongeldige parametertype(s) aan object `%1' (%2)! Assignment of not allocated language! Toewijzing van een niet-gealloceerde taal! Assignment of language object which type is invalid! Toewijzing van een taalobject wiens type ongeldig is! Reference to data type with an index outside the capacity of data types list! Referentie naar een datatype met een index die buiten de capaciteit van de datatype lijst ligt! Assignment of a null type to object `%1' (%2)! Toewijzing van een null type aan het object `%1' (%2)! Assignment of invalid type to the object! Toewijzing van een ongeldig type aan het object! Assignment of an empty directory to object `%1' (%2)! Toewijzing van een lege map aan object `%1' (%2)! Obtaining types with invalid quantity! Types met ongeldige hoeveelheid verkregen! Insertion of item which already exists in the attributes list of the type! Invoegen van een item dat reeds bestaat in de attributenlijst van het type! Insertion of invalid item in the attributes list of the type! Invoegen van een ongeldig item in de attributenlijst van het type! Insertion of item which already exists in the enumarations list of the type! Invoegen van een item dat reeds bestaat in de enumeratielijst van het type! Insertion of invalid item in the enumerations list of the type! Invoegen van een ongeldig item in de enumeratielijst van het type! Reference to an attribute which index is out of the attributes list bounds! Referentie naar een attribuut met een index die buiten de limieten van de attributenlijst ligt! Reference to an enumeration which index is out of the enumerations list bounds! Referentie naar een enumeratie met een index buiten de limieten van de enumeratielijst! Assignment of invalid configuration to the type! Toewijzing van een ongeldige configuratie aan het type! There is already a relationship between `%1' (%2) and `%3' (%4) in the model! When using relationships of the type generalization, copy and one-to-one there can't be other relationships linked to the pair of tables. Unable to load the configuration file `%1'! Please check if file exists in its folder and/or if it is not corrupted! Invalid syntax in file `%1', line %2, column %3! Invalid instruction `%1' on file `%2', line %3, column %4! Unknown attribute `%1' in file `%2', line %3, column %4! Invalid metacharacter `%1' in file `%2', line %3, column %4! Invalid operator `%1' in comparison expression, file `%2', line %3, column %4! Attribute `%1' with an undefined value in file `%2', line %3, column %4! Attribute `%1' with an invalid name in file `%2', line %3, column %4! Could not access the file or directory `%1'! Make sure that it exists or if the user has access permissions on it! Could not load file `%1'. The same appears to be inconsistent or one of its dependencies (DTD files) has errors or is missing! Unsupported PostgreSQL version (%1) detected! Valid versions are between %2 and %3. Failed to drop the database `%1' because it is defined as the default database for the connection `%2'! The column `%1' must be `NOT NULL' because it composes the primary key of the table `%2'. You need to remove the column from the mentioned contraint in order to disable the `NOT NULL' on it! The identity column `%1' has an invalid data type! The data type must be `smallint', `integer' or `bigint'. Reference to an invalid affected command in policy `%1'! Reference to an invalid special role in policy `%1'! Assignment of an operator which input type count is invalid to aggregate function! Toewijzing van een operatie wiens inputtypehoeveelheid ongeldig is voor een aggregatiefunctie! Assignment of an operator which types of arguments is invalid! Toewijzing van een operator wiens argumententypes ongeldig zijn! Assignment of system reserved name to the object `%1' (%2)! Toewijzing van een systeem-gereserveerde naam aan het object `%1' (%2)! One function with invalid configuration is been used by the object `%1' (%2)! Een functie met ongeldige configuratie wordt gebruikt door het object `%1' (%2)! Assignment of an invalid strategy/support number to an operator class element! Toewijzing van een ongeldig strategy- of supportnummer aan een operatorklasse element! Insertion of element which already exists in the element list! Invoegen van een element dat reeds bestaat in de elementenlijst! Reference to an element which index is out of element list bounds! Referentie naar een element wiens index buiten de limiet van de elementenlijst valt! Reference to an object which index is out of object list bounds! Referentie anar een object wiens index buiten de limiet van de objectenlijst valt! Removal of an object not allocated! Verwijdering van een niet-gealloceerd object! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4)! Het object `%1' (%2) kan niet worden verwijderd omdat object `%3' (%4) ernaar verwijst! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4) that belongs to `%5' (%6)! Het object `%1' (%2) kan niet worden verwijderd omdat object `%3' (%4), dat aan `%5' (%6) toehoort, ernaar verwijst! Operation with object(s) which type(s) is invalid! Operatie met object(en) van een ongeldig type! Reference to object with invalid type! Verwijzing naar een object van een ongeldig type! Operation with object not allocated! Operatie op een niet-gealloceerd object! The creation of the relationship `%1' between the table `%2' and `%3' can not be done because one does not have a primary key. If the relationship is of the type n-n both tables must have primary keys! Het aanmaken van de relatie `%1' tussen de tabellen `%2' en `%3' kan niet worden voltooid omdat deze geen primary key bevatten. Indien de relatie van het type n-n is, moeten beide tabellen over een primary key beschikken! The relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user! De relatie van het type 1-1 waar beide tabellen verplicht meespelen is niet geimplementeerd omdat dit een fusie tussen de tabellen vereist die het design van de gebruiker zou breken! Assignment of an invalid expression to the object! Toewijzing van een ongeldige expressie aan het object! Assignment of a primary key to a table which already has one! Toewijzing van een primary key aan een tabel die reeds over een primary key beschikt! Identifier relationship can not be created for a self relationship, relationships of the type n-n, copy or generalization! De identifier-relatie kan niet worden aangemaakt voor een zelf-relatie, relaties van het type n-n, kopie or generalisatie! Unable to create a copy relationship because the column `%1' in table `%2' already exists in table `%3'! De kopie-relatie kon niet worden aangemaakt omdat de kolom `%1' in table `%2' reeds bestaat in tabel `%3'! Unable to create the generalization relationship because the column `%1' in table `%2' can not be merged with the column `%3' of table `%4' because they have incompatible types! De generalisatierelatie kan niet worden aangemaakt omdat de kolom `%1' in tabel `%2' niet kan worden samengevoegd met kolom `%3' van tabel `%4', deze kolommen hebben incompatibele types! Unable to create the generalization relationship because the constraint `%1' in table `%2' can not be merged with the constraint `%3' of table `%4' due to their incompatible composition! De generalisatierelatie kan niet worden aangemaakt omdat de constraint `%1' in tabel `%2' niet kan worden samengevoegd met constraint `%3' van tabel `%4', deze constraints hebben een incompatibele compositie! An attribute can not be added to a copy or generalization relationship! Een attribuut kan niet worden toegevoegd aan een kopie of een generalisatierelatie! A foreign key can not be added to a relationship because is created automatically when this is connected! Een foreign key kan niet worden toegevoegd aan een relatie omdat deze automatisch wordt aangemaakt wanneer deze wordt verbonden! The object `%1' (%2) is referencing the object `%3' (%4) which was not found in the model! Het object `%1' (%2) refereert naar het object `%3' (%4), dit laatste object kon niet worden gevonden in het model! Reference to an user-defined data type that not exists in the model! Referentie naar een gebruikersgedefinieerd type dat niet in het model bestaat! Assignment of invalid maximum size to operation list! Toewijzing van een ongeldige maximumwaarde aan de operatielijst! Unable to write the file or directory `%1'! Make sure the output directory exists, or if the user has write permissions over it! Het bestand of de map `%1' kon niet worden aangemaakt! Zorg ervoor dat de uitvoermap bestaat en dat de gebruiker er schrijfmachtigingen toe heeft! Unable to write the file `%1' due to one or more errors in the definition generation process! Het bestand `%1' kan niet worden geschreven omwille van een of meerdere fouten die optraden tijdens het definitie-generatie proces! The configuration of the relationship `%1' generates a redundancy between the relationships `%2'. Redundancy on identifier or generalization/copy relationships are not accepted since they result in incorrect column spreading making the model inconsistent! De configuratie van de relatie `%1' creeert een redundantie tussen de relaties `%2'. Redundanties van identifiers of generalisatie/kopie-relaties zijn niet geldig omdat deze kunnen leiden tot het incorrect verspreiden van kolommen en dit kan het model inconsistent maken! One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! Een of meerdere objecten werden als ongeldig gemarkeerd en werde automatisch verwijderd omdat deze naar kolommen refereerden die werden ingesloten door relaties die niet langer bestaan omwille van het ontkoppelen van de relatie of het uitsluiten van zulke gegenereerde kolommen! The primary key `%1' can only be allocated if declared within a block of code that defines a table or relationship! Een foreign key `%1' kan niet worden toegevoegd aan een relatie omdat deze automatisch wordt aangemaakt wanneer deze wordt verbonden! Reference to an invalid privilege type! Referentie naar een ongeldig machtigingstype! Insertion of a role which already exists in the role list of the permission! Invoegen van een rol die reeds in de rollenlijst van de machtiging aanwezig is! Assignment of privilege incompatible with the type of object referenced by permission! Toewijzing van een machtiging die niet compatibel is met het type waarnaar wordt verwezen door de machtiging! There is already a permission on object `%1' (%2) which has one or more equal roles from those present on permission to be assigned to the object! Er bestaat reeds een machtiging op object `%1' (%2) die een of meerdere zelfde rollen bevat als deze die onderdeel uitmaken van de nieuwe machtiging die aan het object worden toegewezen! A permission is referencing the object `%1' (%2) which was not found in the model! Een machtiging refereert naar object `%1' (%2) dat niet in het model kon worden teruggevonden! The object `%1' (%2) can not be created because its not being assigned to any schema! Het object `%1' (%2) kan niet worden aangemaakt omdat het niet aan een schema is toegewezen! The tablespace `%1' can not be inserted into the model because it points to the same directory as the tablespace `%2'! De tablespace `%1' kan niet worden ingevoegd in het model omdat het naar dezelfde map verwijst als de tablespace `%2'! It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! Het is niet mogelijk om arrays van domeinen of sequenties (dimensie >= 1) aan te maken! Dit feature is nog niet aanwezig in PostgreSQL! The function `%1' can not get a source code as a definition because its language is set to C. Use the attributes symbol and dynamic library instead! De functie `%1' kan geen broncode bevatten als definitie omdat de taal is ingesteld als 'C'. Gebruik het attributensymbool en dynamische bibliotheek in de plaats! The function `%1' can have the attributes symbol and dynamic library configured only if the language is set to C. For all other cases you must specify a source code that defines it in the DBMS! De functie `%1' kan enkel symboolattributen en een dynamische bibliotheek configureren waneer de taal is ingesteld als zijnde 'C'. In alle andere gevallen moet u broncode specifieren die de functie definieert in het DBMS! The operator `%1' can not be assigned as a comutator of operator `%2' because it has incompatible settings! De operator `%1' kan niet worden toegewezen als comutator van operator `%2' omdat deze incompatibele instellingen heeft! The operator `%1' can not be assigned as negator of operator `%2' because it has incompatible settings! De operator `%1' kan niet worden toegewezen als negator van operator `%2' omdat deze incompatibele instellingen heeft! The type `%1' can not self refer in the attributes `element' or `copy type' or be used as a data type of an attribute in the configuration of a composite type! Het type `%1' kan geen zelf-referentie bevatten in de attributen 'element' of 'kopie type' noch kan het worden gebruikt als het data type van een attribuut in de configuratie van een composiet-type! Assignment of invalid element to type `%1'! Toewijzing van een ongeldig element aan type `%1'! Assignment of invalid alignment to type `%1'! Toewijzing van een ongeldig uitlijning aan type `%1'! Assignment of invalid name to the table generated from N-N relationship! Een ongeldige naam werd toegewezen aan de tabel gegenereerd op basis van een N-N relatie! The relationship `%1' can not make use of the special primary key because it is marked as identifier or it is a self relationship! De relatie `%1' kan geen gebruik maken van de primary key omdat deze is aangeduid als identifier of omdat het een zelfverwijzende relatie is! The object `%1' (%2) can not be edited or deleted because it was automatically included through a relationship! If the object is an attribute or constraint the modifications must be done on the relationship editing form. Het object `%1' (%2) kan niet worden bewerkt of verwijderd omdat het automatisch werd ingesloten via een relatie! Indien het object een attribuut of een constraint is moeten de bewerkingen worden uitgevoerd via het Relatie bewerk-venster. The object `%1' (%2) can not be deleted because it is protected! Het object `%1' (%2) kan niet worden verwijderd omdat het beschermd is! The group `%1' has already been declared earlier! De groep `%1' werd reeds eerder gedeclareerd! The group `%1' can not be built in the groups declaration block (%2)! De groep `%1' kan niet worden opgebouwd in de groependeclaratie-block (%2)! The group `%1' was built but not declared in the groups declaration block (%2)! De groep `%1' werd opgebouwd maar is niet gedeclareerd in de groependeclaratie-block (%2)! The group `%1' can not be built without possessing child elements! De groep `%1' kan niet worden opgebouwd zonder kind-elementen! The group `%1' can not be built once more because this was done in previous blocks! De groep `%1' kan niet worden opgebouwd omdat dit reeds werd uitgevoerd in een vorige block! The group `%1' has been declared but not built! De groep `%1' werd gedeclareerd maar niet opgebouwd! Reference to a column of the objects table with invalid index! Een referentie naar een kolom in de objectentabel met een ongeldige index! Reference to a row of the objects table with invalid index! Een referentie naar een rij in de objectentabel met een ongeldige index! The object `%1' (%2) can not be manipulated because it is reserved to PostgreSQL! This object is present in the database model only as a reference! Het object `%1' (%2) kan niet worden gemanipuleerd omdat dit een gereserveerd object is in PostgreSQL! Dit object bestaat enkel als referentie in het databasemodel! The new configuration of the function invalidates the object `%1' (%2)! In this case it is needed to undo the relationship between the affected object and function in order to the new configuration to take effect! De nieuwe configuratie van de functie maakt het object `%1' (%2) niet langer gevalideerd! Om de nieuwe configuratie in voege te doen treden moet u de relatie tussen het beinvloedde object en de functie ongedaan maken. A view reference must be used in at least one these SQL scopes: View Definition, SELECT-FROM, FROM-WHERE or After WHERE! Een viewreferentie moet minstens in een van de volgende SQL scopes worden gebruikt: View Definitie, SELECT-FROM, FROM_WHERE of Na WHERE! Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns! Constraints zoals primary key, foreign key of unique key moeten minstens een kolom bevatten! Voor foreign keys moeten ook de gerefereerde kolommen worden geselecteerd! Could not find the default settings file `%1'! To restore default settings check the existence of the file and try again! Het standaardinstellingsbestand `%1' kon niet worden gevonden. Kijk na of dit bestand bestaat om de standaardinstellingen terug te zetten en probeer opnieuw! The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 Het exportproces faalde door een fout die werd gegenereerd door PostgreSQL tijdens het uitvoeren van een SQL commando. Voor meer informatie over de fout, gelieve de exception stack na te kijken! ** Uitgevoerde SQL commando: ** %1 Could not load the plugin `%1' from the library `%2'! Message returned by plugin manager: `%3' De plugin `%1' kon niet worden geladen van de bibliotheek `%2'! De plugin manager antwoordde met: `%3' One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. Een of meerdere plugin werden niet geactiveerd omwille van fouten gedurende het laadproces! Kijk de exception stack na voor meer details. Assignment of empty XML buffer to parser! Toewijzingen van een lege XML buffer aan de parser! Assignment of empty DTD file name! Toewijzing van een lege DTD bestandsnaam! Assignment of empty name to the DTD declaration! Toewijzing van een lege naam aan de DTD declaratie! Error while interpreting XML buffer at line %1 column %2. Message generated by the parser: %3. %4 Er trad een fout op tijdens het interpreteren van de XML buffer op lijn %1, kolom %2. De parser antwoordde met: %3. %4 Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! Een operatie werd uitgevoerd op een niet-gealloceerd element in de boomstructuur! De XML parser buffer moet eerst worden geladen en geinterpreteerd zodat deze boomstructuur kan worden gegenereerd! Operation with unallocated tree element! Operatie met een niet-gealloceerd object! Operation with element which does not exists in the element tree currently loaded! Er werd een operatie uitgevoerd op een element dat niet bestaat in de huidig geladen elementen-boomstructuur! Assignment of a value to an invalid connection parameter! Toewijzing van een waarde aan een ongeldige verbindingsparameter! Operation on connection not established! Er werd een operatie uitgevoerd op een niet-verbonden verbinding! Attempt to connect without define configuration parameters! Poging tot verbinden zonder dat de configuratieparameters zijn gedefinieerd! Attempt to start a connection already stablished! Poging tot het starten van een verbinding die reeds verbonden is! Could not connect to the database. Message returned: `%1' Er kon geen verbinding worden gemaakt met de database. Het bericht is: `%1' Assignment of not allocated SQL command result! Toewijzing van een niet-gealloceerde SQL commandoresultaat! Unable to allocate the result of the SQL command because the response from the DBMS was not understood by the client! Het is niet mogelijk om het resultaat van het SQL commando te allocaren omdat de client het antwoord van de DBMS niet verstond! Unable to allocate command result for the SQL because the server has generated a fatal error! Message returned by the DBMS: `%1' Het commandoresultaat voor de SQL code kan niet worden gealloceerd omdat de server een fatale fout genereerde! Het bericht dat terugkwam van de DBMS is: `%1' Reference to a column of tuple with invalid index! Referentie naar een kolom van een tuple met een ongeldige index! Reference to a column of tuple with invalid name! Referentie naar een kolom van een tuple met een ongeldige naam! Reference to a tuple with an invalid index or the result is empty (no tuples)! Referentie naar een tuple met een ongeldige index of het resultaat is leeg (geen tuples)! Reference to a column of a tuple which was not yet initialized (tuple navigation not started)! Referentie naar een kolom van een tuple dat nog niet werd geinitializeerd (tuple-navigatie nog niet gestart)! Could not execute the SQL command. Message returned: `%1' Het SQL commando kon niet worden uitgevoerd. Het teruggekeerde bericht is: `%1' Invalid use of a view reference as whole SQL definition! The assigned reference must be an expression! Ongeldig gebruik van een view-referentie als volledige SQL definitie! De toegewezen referentie moet een expressie zijn! Assignment of a second definition expression to the view! Toewijzing van een tweede definitie-expressie aan de view! It is not possible mix ordinary references (SELECT-FROM, FROM-WHERE, After WHERE) with references used as view SQL definition! Gewone referenties (SELECT-FROM, FROM-WHERE, Na WHERE) kunnen niet worden gemixt met referenties die gebruikt worden als SQL definitie! Assignment of collation object which type is invalid! Toewijzing van een sorteringsobject wiens type ongeldig is! At the moment pgModeler does not support the creation of primary keys which some columns were generated by relationship connection. To create primary keys with this feature you can use the field `Identifier' or the tab `Primary key' on relationship editing form! Op dit moment ondersteunt pgModeler de aanmaak van primary keys waarvan sommige kolomen door relatie-verbindingen worden gegenereerd nog niet. Om primary keys met dit feature aan te maken kan u gebruik maken van het veld 'Identifier' of het 'Primary key' tab-blad in het relatie-bewerkingsvenster! Collations must be created at least with attributes LC_COLLATE and LC_CTYPE defined! Sorteringsmethodes moeten worden aangemaakt en minstens LC_COLLATE en LC_CTYPE gedefinieerd hebben! The object `%1' (%2) cannot reference itself! This operation is not permitted for this kind of object! Het object `%1' (%2) kan niet naar zichzelf verwijzen! Deze operatie is niet toegelaten voor dit type object! Only operator families which uses `btree' as indexing method are accepted by operator class elements! Enkel operator-families die gebruik maken van `btree' als indexeringsmethod kunnen worden aanvaard als operatorklasse element! Reference to an invalid copy table option! Referentie naar een ongeldige kopie-tabel optie! Copy relationship between tables `%1' and `%2' cannot be done because the first one already copies attributes from `%3'! Tables can have only one copy table! De kopie-relatie tussen tabellen `%1' en `%2' kan niet worden aangemaakt omdat de eerste reeds attributen kopieert van `%3'! Tabellen kunnen over slechts een kopie-tabel beschikken! The INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers! De INSTEAD OF modus kan niet worden gebruikt voor triggers die aan tabellen toehoren! Dit is enkel beschikbaar voor triggers die aan views toehoren! The TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table! Het TRUNCATE event kan enkel worden gebruikt wanneer de trigger uitvoert voor elk statement en aan een tabel toebehoort! The INSTEAD OF mode cannot be used on view triggers that executes for each statement! De INSTEAD OF modus kan niet worden gebruikt voor view triggers die voor elk statement worden uitgevoerd! Constraint triggers can only be executed on AFTER events and for each row! Constraint triggers kunnen enkel worden uitgevoerd NA events en voor elke rij! A view trigger cannot be AFTER/BEFORE when it executes for each row! Een view trigger kan niet AFTER/BEFORE zijn wanneer deze voor elke rij wordt uitgevoerd! A trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event! Een trigger kan niet naar kolommen refereren wanneer deze gebruikt maakt van de INSTEAD OF modus binnen een UPDATE event! Assignment of a column which has no parent table to the object `%1' (%2)! Toewijzing van een kolom aan object `%1' (%2) die geen ouder-tabel heeft! Only constraint triggers can be deferrable or reference another table! Enkel constraint triggers kunnen uitstelbaar zijn of naar andere tabellen refereren! Reference to a function id which is incompatible with the user define type configuration! Een referentie naar een functie id die niet compatibel is met de configuratie van het gebruiker gedefinieerde type! The operator class assigned to the object `%1' (%2) must use `btree' as indexing method! De operatorklasse die is toegewezen aan het object `%1' (%2) moet 'btree' als indexeringsmethod gebruiken! The validation process failed due to an error triggered by the validation helper. For more details about the error check the exception stack! Het validatieproces faalde omwille van een fout in de validatie-helper. Kijk voor meer details over de fout de exception stack na! The extension `%1' is registered as a data type and cannot have the attribute `handles datatype' modified! De uitbreiding `%1' is geregistreerd als een data type, het 'behandeld data type' attribuut kan niet worden aangepast! The fk relationship `%1' cannot be created because the foreign-key that represents it was not created on table `%2'! De fk relatie `%1' kan niet worden aangemaakt omdat de foreign key die deze relatie weergeeft niet werd aangemaakt op tabel `%2'! Assignement of an invalid object name pattern to the relationship `%1'! Toewijzijng van een ongeldig objectnaamspatroon aan de relatie `%1'! Reference to an invalid object name pattern id on the relationship `%1'! Referentie naar een ongeldige id van objectnaamspatronen voor de relatie `%1'! Invalid use of variadic parameter mode! This mode can be used only with an array or "any" data type! The object `%1' (%2), oid `%3', could not be imported due to one or more errors! Check the exception stack for more details. `HINT:' if the object somehow references objects in `pg_catalog' or `information_schema' consider enable the importing of system objects. It's not possible convert the type of the column `%1' to serial! It must have an `integer' based type and its default value must be a call to `nextval(seq_name::regclass)' function or a sequence object must be directly assigned to the column! A parent table of `%1' which OID is `%2' was not found in the set of imported objects! The enumeration `%1' can't be assigned to the type `%2' because contains invalid characters! The enumeration `%1' can't be assigned to the type `%2' because is too long! The connection was idle for too long and was automatically closed! The connection was unexpectedly closed by the database server `%1' at port `%2'! Mixing incompatibles DBMS export modes: `ignore object duplications', `drop database' or `drop objects' cannot be used with `simulate export'! Mixen van niet-compatibele DBMS export-modussen: `negeer object duplicaten', `verwijder database' of `verwijder objecten' kan niet samen worden gebruikt met `simuleer export'! Mixing incompatibles DROP options: `drop database' and `drop objects' cannot be used at the same time! Mixen van niet-compatibele DROP opties: `verwijder database' en `verwijder objecten' kunnen niet samen worden gebruikt! Invalid object id swapping operation! The objects involved are the same! Ongeldige object id wissel-operatie! De betrokken objecten zijn dezelfde! Invalid object id swapping operation! The database itself, tablespaces or roles cannot have the ids swapped! Ongeldige object id wissel-operatie! De database zelf, tablespaces en rollen kunnen geen ids omwisselen! The widget already has a parent and cannot be assigned to a different object! Het widget heeft reeds een ouder en kan niet aan een ander object worden toegewezen! Could not load the database model file `%1'. Check the error stack to see details. Try to run `pgmodeler-cli --fix-model' in order to correct the structure of the file if that is the case. Het datababase modelbestand `%1' kon niet worden geladen. Kijk de foutenstack na voor meer details. Probeer `pgmodeler-cli --fix-model' uit te voeren op het model om de bestandsstructuur te corigeren indien dit nodig zou zijn. The column `%1' cannot reference it's parent table `%2' as data type! De kolom `%1' kan niet naar de oudertabel `%2' als data type verwijzen! Operation with an invalid element id `%1'! Operatie met een ongeldige olement id `%1'! Reference to an invalid color id `%1' for element `%2'! Referentie naar een ongeldige kleuren-id `%1' voor element `%2'! Assignment of an invalid object to `%1' (%2)! The assigned object must be of type `%3'. Toewijzing van een ongeldig object aan `%1' (%2)! Het toegewezen object moet van het type `%3' zijn. The sequence `%1' can't be assigned to the column `%2' because the data type of the latter is incompatible. The type used must be an integer one! De sequentie `%1' kan niet aan de kolom `%2' worden toegewezen omdat het data type van de kolom niet compatibel is. Het gebruikte type moet een integer type zijn! The option to generate temporary object names can only be used in simulation mode! De optie om tijdelijke objectnamen te genereren kan enkel worden gebruikt in simulatie-modus! Could not assign the variable `%1' to event trigger's filter. Currently, PostgreSQL supports only the `TAG' variable! De variabele `%1' kon niet worden toegewezen aan de filter van de event trigger! Op dit moment ondersteunt PostgreSQL enkel de `TAG' variabele! Could not perform the `%1' operation on `%2' using the data on row `%3'! All changes were rolled back. ** Returned error ** %4 De operatie `%1' op `%2' kon niet worden voltooid met de data op rij `%3'! Alle aanpassingen werden ongedaan gemaakt. ** Gerapporteerde fout ** %4 Malformed unescaped value on row `%1' column `%2'! Incorrect gevormde un-escape waarde op rij `%1', kolom `%2'! Trying to undo/redo an invalid operation over an object that does not exists anymore or can't be handled! The operation history will be cleaned up. Poging tot het ongedaan maken of opnieuw uitvoeren van een ongeldige operatie op een object dat niet langer bestaat of niet kan worden behandeld! De taakgeschiedenis zal worden leeggemaakt. The object `%1' (%2) can't be handled because some needed fields are not set! Please, make sure to fill at least the requires fields in order to properly create or update the object. Het object `%1' (%2) kan niet worden behandeld omdat sommige nodige velden niet werden ingesteld! Gelieve de verplichte velden in te voeren om het object correct aan te kunnen maken of passen. A relationship can only be swapped by other object of the same kind! De relatie kan enkel worden omgewisseld door een ander object van dezelfde soort! ExtensionWidget Version: Versie: Old Version: Oude Versie: This attribute cannot be changed once the object is created. Dit attribuut kan niet worden veranderd eens het object is aangemaakt. Handles data type Behandelt dit data type FindReplaceWidget Form Venster Hide this widget Verberg dit widget ... ... Replace one occurrence Vervang één voorkomen Replace Vervangen Replace all occurrences Vervang alle voorkomens Replace All Vervang Allen Replace the selection and find the next one Vervang in de selectie en vindt de volgende Replace && Find Vervang && Zoek Replace: Vervang: Find: Zoek: Find previous Zoek vorige Shift+F3 Find next Zoek volgende F3 Case sensitive Hoofdlettergevoelig Regular expression Regular expression Whole words Volledig woord FunctionWidget Attributes Attributen Security: Beveiliging: Function Type: Functietype: Rows Returned: Aantal rijen Return Method: Terugkeermethode: Behavior: Gedrag: Set Set Language: Si&mple Tab&le Return Table Terugkeertabel Execution Cost: Uitvoeringskost: Windown Func. Windowing Functie Leakproof Lekdicht Parameters Parameters Definition Definitie Dynamic Library: Dynamische Bibliotheek Symbol: Symbool: Library: Bibliotheek: Source code: Broncode: Column Kolom Type Type Name Naam Mode Modus Default Value Standaardwaarde: GeneralConfigWidget Form Venster General && Design Algemeen && Design General Algemeen Operation history: Taakgeschiedenis: Check if there is a new version on server Vink dit aan om na te kijken of een nieuwe versie beschikbaar is op de server Design Design Graphical objects (table, views and textboxes) will be created in a single step without the need to click on canvas Grafische objecten (tabellen, views en tekstvakken) worden in een enkele stap aangemaakt zonder op het canvas te hoeven klikken Simplify creation of graphical objects Should be 'Vereenvoudig de aanmaak van grafische objecten' but that's way too long for the space Versimpel creatie van grafische objecten After loading the model the last zoom and position on canvas will be restored Nadat het model geladen is wordt de laatste zoomwaarde en positie op het canvas hersteld Save and restore last position and zoom Behoud de laatste positie en zoom Disable render smoothness Schakel vlakke rendering uit Hide the object that represents the relationship name Verberg het object dat de relatienaam voorstelt Hide relationship name Verberg relatienaam Validate before save, export or diff Valideer voor opslaan, exporteren of diff Hide the object which represents the tag assigned to the table Verberg het tag object dat is toegekend aan de tabel Hide table tags Verberg tabel-tags Start move the canvas when the cursor is on the canvas edges Verplaatst het canvas wanneer de cursor zich op de rand van het canvas bevindt Move canvas by keep mouse on corners Verplaats canvas bij muis in de hoeken Hide the portion of table which represent triggers, indexes and rules Verberg het tabel-gedeelte dat triggers, indexes en regels voorstelt Hide table extended attributes Verberg uitgebreide attributen Disable antialiasing for lines and texts improving performance when handling huge models. Triggers a dialog asking the user to validate the model before a save, export or diff operation. When enabled this option creates a placeholder object at the previous table's position when starting to move it. This will cause graphical updates on relationship lines to be performed only when the drag & drop action is done improving the performance. Disabling placeholders will cause those updates to be executed every time the table's position changes a single pixel (classical behavior). Use placeholders when moving tables Toggles the code completion in all fields that accepts the input of SQL commands. Schakelt codevervollediging aan of af in alle velden die SQL commando's aanvaarden. Minimum object opacity (%): Defines the minimum opacity percentage applied to the objects when using the fade out feature. A zero opacity causes the object to be completely hidden not being possible to interact with it in the canvas area. Canvas grid size: Defines the vertical and horizontal grid size. This value affects the spacing of objects when using object grid alignment feature. By default the range selection is triggered with Shift + left click. By checking this option range selection will be activated only with a single click and move. Trigger range selection with a single click Defines the maximum amount of elements held in the operation history. Once reached the maximum number the history is automatically cleaned. Defines the period when the opened models will be saved automatically. Autosave interval (minutes): Enable SQL code completion Schakel SQL codevervollediging in Replaces any straight line in relationship by curved ones in order to improve the model's visualization. Use curved lines for relationships Souce code editor args: lines Clear the entire SQL comand history. Clear history Open in file manager Open in bestandsbeheer Overrides the default user interface language defined by the system. Requires restarting the program. <strong>NOTE:</strong> UI translations are third party collaborations thus any typo or mistake should be reported directly to their respective maintainers. SQL history max. length: Check updates at startup User interface language: Browse the source code editor application Souce code editor: Configurations directory: Printing && Code Printen && Code Code style Codestijl Size: Grootte: Font: Lettertype: Colors: Kleuren: Options: Opties: Display line numbers Geef lijnnummers weer Highlight lines at cursor's position Licht de huidige lijn onder de cursor op pt pt Custom tab width: Printing Printen Print grid Print raster Print page numbers Print paginanummers Paper: Papier: A0 (841 x 1189 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) B0 (1030 x 1456 mm) B1 (728 x 1030 mm) B10 (32 x 45 mm) B2 (515 x 728 mm) B3 (364 x 515 mm) B4 (257 x 364 mm) B5 (182 x 257 mm) B6 (128 x 182 mm) B7 (91 x 128 mm) B8 (64 x 91 mm) B9 (45 x 64 mm) C5E (163 x 229 mm) Comm10E (105 x 241 mm) DLE (110 x 220 mm) Executive (191 x 254 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Legal (216 x 356 mm) Letter (216 x 279 mm) Tabloid (279 x 432 mm) Custom Aangepast Orientation: Oriëntatie: Landscape Landschap Portrait Portret Unity: Eenheid: Custom Size: Aangepaste Grootte: Width: Breedte: Height: Hoogte: Page Margins: Paginamarges: Left: Links: Left margin Linkermarge Top: Kop: Top margin Kopmarge Right: Rechts: Right margin Rechtermarge Bottom: Voet: Bottom margin Voetmarge Milimeters Milimeters Pixels Pixels Inches Inches Centimeter Centimeter Line numbers' font color Lettertypekleur van lijnnummers Line numbers' background color Achtergrondkleur van lijnnummers Highlighted line color Uitlichtkleur The little brown fox jumps over the lazy dog The little brown fox jumps over the lazy dog System default All files (*.*) Load file GenericSQLWidget SQL code SQL code HintTextWidget Form Venster IndexWidget Attributes Attributen Indexing: Indexering: Fill Factor: Vul-factor: Options: Opties: Concurrent Gelijktijdig Unique Uniek Fast update Snelle update Buffering Buffering Predicate: Predicaat: Elements Elementen LanguageWidget Trusted: Vertrouwd: Validator Func.: Validatiefunctie: Handler Func.: Behandelende Functie: Inline Func.: Inline Functie: The functions to be assigned to the language should have, respectively, the following signatures:<br/><br/> <strong>Handler Function:</strong> <em>language_handler function()</em><br/> <strong>Validator Function:</strong> <em>void function(oid)</em><br/> <strong>Inline Function:</strong> <em>void function(internal)</em> De functie die worden toegewezen aan de taal moeten de volgende signatures hebben, respectievelijk: <br/><br/> <strong>Handler Functie:</strong> <em>taal_handler_functie()</em><br/> <strong>Validatie Functie:</strong> <em>void functie(oid)</em><br/> <strong>Inline Functie:</strong> <em>void functie(internal)</em> MainWindow pgModeler - PostgreSQL Database Modeler pgModeler - PostgreSQL Database Modeler Toggle the model objects widget Schakel het modelobjecten-widget in of uit O&bjects O&bjecten Alt+B Alt+B Toogle the model validation widgets Toon of verberg het modelvalidatie-widget &Validation &Validatie Alt+V Alt+V Toggle the operation history widget Toon of verberg het commandogeschiedenis-widget &Operations &Operaties Alt+O Alt+O Toggle the object finder Toon en verberg de objectenvinder Find Object Zoek Object Ctrl+F Ctrl+F &File &Bestand &Edit &Bewerken &Show &Weergave General Algemeen Controls Controls &Load &Laden Sa&ve as E&xit Exit pgModeler &About pgModeler &Print Print model &Undo Undo operation &Redo Redo operation &Export &Exporteer Ctrl+Shift+E &Show grid &Close &Sluiten &Normal zoom &Align to grid Show &delimiters &Settings F12 F12 &Overview &Support Access the support page New Nieuw &Diff Determine the changes between model/database and another database Shift+M &Bug report Objects me&tadata Objects metadata Arrange objects Rearrange objects over the canvas Ctrl+N Ctrl+S Ctrl+S Zoom in Inzoomen Ctrl+= Ctrl+= Zoom out Uitzoomen Zoom - Zoom - He&lp Pl&ugins &New New model Nieuw model &Save Op&slaan &Zoom in Zoo&m out Ctrl+- Ctrl+- Ctrl+O Ctrl+O Ctrl+Q Ctrl+Q F4 F4 Ctrl+P Ctrl+P Ctrl+Z Ctrl+Z Ctrl+Y Ctrl+Y Export the current opened model in different modes Exporteer het huidig geopende model in verschillende modussen &Recent Models &Import Rest&ore Session &Fix a model &Check for update Ctrl+Shift+S Ctrl+Shift+S Show grid Raster tonen Ctrl+G Ctrl+G Close current model Sluit dit model Ctrl+W Ctrl+W Ctrl+0 Ctrl+0 Align objects position to grid Lijn objecten uit op het raster Ctrl+H Ctrl+H Show the page delimiters Toon pagina-delimiters Ctrl+L Ctrl+L Edit pgModeler settings Bewerk de pgModeler instellingen Save all Alles opslaan Show the model overview Toon modeloverzicht F10 F10 F1 F1 New object Plugins Plugins Access the list of loaded plugins Bekijk de lijst van geladen plugins Load recently opened model Laad recent geopend model Import existing database to new model (reverse engineering) Importeert een bestaande database in een nieuw model (Reverse Engineering) Ctrl+Shift+I Ctrl+Shift+I New version found! Er is een nieuwe versie beschikbaar! Update for the current version is available on project's site Er is een update beschikbaar voor de huidige versie op de website van het project action_main_menu Main menu Hoofdmenu Show expanded Toon uitgeklapt Expands the main menu bar in classical mode Klapt het hoofdmenu uit in klassieke modus Hide main menu Verberg hoofdmenu Hides the main menu bar and put the action on a separated action This looks like something that could use revisiting (the original EN text that is) Verbergt de hoofdmenu en verplaats de actie naar een afgescheiden actie Ctrl+Shift+H Ctrl+Shift+H Ctrl+Shift+D Welcome Welkom Welcome screen Welkomstscherm Shift+W Design Design Design database models Design databasemodellen Shift+D Manage Beheer Manage existent databases Beheer bestaande databases Report a bug Rapporteer een bug Donate Doneer Help pgModeler by donating! Help pgModeler via donering! (Demo) (Demo) Saving temp. models Tijdelijke modellen opslaan Clear Menu Menu leegmaken The demonstration version can create only `one' instance of database model! De demonstratieversie kan slechts één databasemodel instantie aanmaken! Save model Model opslaan Grid Hierarchical Scattered Save modified model(s) The following models were modified but not saved: %1. Do you really want to quit pgModeler? The model <strong>%1</strong> was modified! Do you really want to close without save it? Warning Opgepast You're running a demonstration version! The model saving feature is available only in the full version! Dit is een demonstratie-versie! Het opslaan van modellen is enkel beschikbaar in de volledige versie! Confirmation Bevestiging <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! It's recommended to validate it before save in order to create a consistent model otherwise the generated file will be broken demanding manual fixes to be loadable again! <strong>PAS OP: </strong> Het model <strong>%1</strong> is niet gevalideerd! Het is aangeraden om het model te valideren vooraleer dit op te slaan om ervoor te zorgen dat u een consistent model behoudt, anders is het modelijk dat het gegenereerde bestand onvolledig is en manuele correcties zal vereissen om het opnieuw te kunnen laden! Save anyway Toch opslaan Validate Valideer Save '%1' as... Sla '%1' op als... Database model (*.dbm);;All files (*.*) Database model (*.dbm);;Alle bestanden (*.*) Access support page You're running a demonstration version! Note that you'll be able to create only <strong>%1</strong> instances of each type of object and some key features will be disabled or limited!<br/><br/>You can purchase a full binary copy or get the source code at <a href='http://pgmodeler.com.br'>pgmodeler.com.br</a>. <strong>NOTE:</strong> pgModeler is an open source software, but purchasing binary copies or providing some donations will support the project and cover all development costs.<br/><br/> <strong>HINT:</strong> in order to test all features it's recommended to use the <strong>demo.dbm</strong> model located in </strong>Sample models</strong> at <strong>Welcome</strong> view.<br/><br/><br/><br/> Rearrange objects over the canvas is an irreversible operation! Would like to proceed? <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the export process it's recommended to validate in order to correctly create the objects on database server! <strong>PAS OP:</strong> Het model <strong>%1</strong> is niet gevalideerd! Vooraleer u het export proces start is het aangeraden om de validatie uit te voeren. Dit zorgt ervoor dat de objecten correct op de database server kunnen worden aangemaakt! Export anyway Toch exporteren <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the diff process it's recommended to validate in order to correctly analyze and generate the difference between the model and a database! <strong>PAS OP:</strong> Het model <strong>%1</strong> is niet gevalideerd! Het is aangeradem om het model te valideren vooraleer u het diff process start. Dit zorgt voor een correcte analyse en het correct genereren van de diff tussen het model en de database! Diff anyway Voer diff toch uit Database model printing Databasemodel printen Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. Er werden veranderingen gedetecteerd tussen de papier- en margedefinities van het model die ertoe kunnen leiden dat de objectenn foutief worden geprint. Wenst u te printen met deze nieuwe instellingen? Om de standaardinstellingen te gebruiken, klik op 'Nee' of klik 'Annuleren' om het printen af te breken. Load model Laad model Could not load the database model file `%1'. Check the error stack to see details. You can try to fix it in order to make it loadable again. Het database modelbestand `%1' kon niet worden geladen. Kijk de error stack na voor details. U kan proberen het probleem te corrigeren om het bestand weer laadbaar te maken. Fix model Corrigeer model Cancel Annuleren This action will open a web browser window! Want to proceed? Deze actie opent een browservenster! Wilt u verdergaan? (no samples found) (geen voorbeelden gevonden) save opslaan export exporteer diff diff Executing pending <strong>%1</strong> operation... De uitvoer wacht op <strong>%1</strong> taak... Messagebox Dialog Dialoogvenster msg Exceptions Uitzonderingen Show raw text errors or information. Toon technische error-tekst en -informatie. Show/hide exceptions stack. Toon/verberg uitzonderingsstack. ... &Yes &Ja &No &Nee Cancel Annuleren &Ok &OK &Cancel &Annuleren Error Fout Alert Waarschuwing Information Informatie Confirmation Bevestiging MetadataHandlingForm Handle metadata &Apply &Cancel Handle objects metadata Settings Instellingen Extract from: Loading a metadata file to the current model is an irreversible operation so be sure to specify a backup file before proceed. Options Opties Handles the following database model attributes in the metadata file: author, zoom factor, last position and default objects. Database model metadata Handles the objects' positioning in the metadata file. Objects' positioning Handles the objects' custom colors in the metadata file. Currently available only for relationships and schemas. Custom object's colors Handles the objects' protection status in the metadata file. Objects' protection status Handles the objects' SQL disabled status in the metadata file. Objects' SQL disabled status Handles the objects' fade out status in the metadata file. Objects' fade out status Save tags to the output file when extracting metadata. When loading the file, the tags are recreated and duplicated ones are ignored. Save textboxes to the output file when extracting metadata. When loading the file, the textboxes are recreated and duplicated ones are ignored. Handles the objects' custom SQL commands in the metadata file. Custom SQL commands Textbox objects Tag objects Handles the tables' and views' extended attributes display status in the metadata file. Tables' extended attributes display Save generic SQL objects to the output file when extracting metadata. When loading the file, the objects are recreated and duplicated ones are ignored. Generic SQL objects Backup file: Select file ... ... Extracts the objects' metadata from the loaded models and apply to the current focused model. A backup file can be specified to where the focused model's current metadata will be saved. &Extract and restore Extracts the objects metadata from one of the loaded models saving the info to a backup file. Extract &only Reads the objects' metadata from a previously saved backup file and apply to the current model. &Restore a backup file Apply to: Operation: Output Uitvoer Progress label... Vooruitgangslabel... model not saved yet The backup file cannot be the same as the input model! Extracting metadata to file `%1' Saving backup metadata to file `%1' Applying metadata from file `%1' Metadata processing aborted! Objects metadata file (*.omf);;All files (*.*) ModelDatabaseDiffForm Settings Instellingen Connection: Verbinding: Database: Database: Ignore import errors Negeer importeerfouten Import system objects Importeer systeemobjecten Import extension objects Importeer uitbreidingsobjecten For DROP command, the objects that depends on an object to be dropped will be deleted as well. For TRUNCATE command, tables that are linked to a table to be truncated will be truncate too. <strong>NOTE:</strong> this option can affect more objects than listed in the output or diff preview. Voor DROP commando's worden objecten die afhankelijk zijn van het object dat verwijderd wordt, ook verwijderd. Voor het TRUNCATE commando worden tabellen die gelinkt zijn aan de te trunceren tabel ook getrunceerd. <strong>LET OP:</strong> deze optie kan objecten beïnvloeden die niet in het uitvoer- of diff-voorbeeld opgenomen zijn. Drop or truncate in cascade mode Drop of trunceer in cascade modus Permissions already set on database objects will be kept.The ones configured on the model will be applied to the database. Machtigingen die reeds op databaseobjecten zijn toegepast zullen behouden blijven. De machtigingen die door het model worden gespecifieerd zullen worden toegepast op de database. Keep object's permissions Behoudt de machtigingen van het object Database cluster level objects like roles and tablespaces will not be dropped. Database cluster-niveau objecten zoals rollen en tablespaces zullen niet worden verwijderd. Keep cluster objects Behoudt clusterobjecten Recreate only unmodifiable objects Hercreeer enkel niet-aanpasbare objecten Force recreation of objects Forceer het heraanmaken van objecten Ignores errors generated by duplicated objects when exporting the diff to database. Negeer fouten die worden gegenereerd door duplicate objecten gedurende het exporteren van de diff naar de database. Ignore duplicity errors Negeer fouten omwille van duplicaten Serial columns are converted to integer and having the default value changed to <strong>nextval(sequence)</strong> function call. By default, a new sequence is created for each serial column but checking this option sequences matching the name on column's default value will be reused and will not be dropped. Seriële kolommen worden geconverteerd naar integers en hun standaardwaarde wordt ingesteld als een functieaanroep naar <strong>nextval(sequentie)</strong>. Normaal gezien wordt een nieuwe sequentie aangemaakt voor elke seriële kolom maar deze optie aanvinken zorgt ervoor dat sequenties die de naam van de kolom gebruiken worden hergebruikt in plaats van verwijderd. Reuse sequences on serial columns Hergebruik sequenties op seriële kolommen No command to rename the destination database will be generated even the model's name differ from database name. Behoudt de naam van de doeldatabase wanneer deze verschilt van de databasenaam in het model. Preserve database name Behoudt databasenaam Diff mode Diff modus Override the PostgreSQL version when generating the diff. The default is to use the same version as the input database. Zet de versie waarvoor de diff wordt gegenereerd expliciet zelf. Standaard wordt dezelfde versie gebruikt als de invoerdatabase. Use PostgreSQL: Gebruikt PostgreSQL: Compares the model and the input database storing the diff in a SQL file for later usage. Vergelijkt het model en de invoerdatabase en slaat het verschil op in een SQL bestand voor later gebruik. File: Bestand: Select output file Selecteer uitvoerbestand ... ... Compares the model and the input database generating a diff and applying it directly to the latter. <strong>WARNING:</strong> this mode causes irreversible changes on the database and in case of failure the original structure is not restored, so make sure to have a backup before proceed. Vergelijkt het model met de invoerdatabase en genereerd een diff die op die laatste wordt toegepast. <strong>PAS OP:</strong> deze modus veroorzaakt onherroepelijke veranderingen in de database en in geval van falen wordt de originele structuur niet hersteld, zorg ervoor dat u een backup hebt vooraleer u verdergaat. Ignores as many as possible errors on import step. This option generates an incomplete diff. Clears the data of all tables which will have columns modified. This is useful to avoid errors related to type casting. <strong>WARNING:</strong> DO NOT use this option on production servers and always make a backup before use it. Import system (built-in) objects. Use this if the import step is returning errors related to missing objects. Import objects created by extensions. Use this if the import step is returning errors even importing built in ones. Instead of use an ALTER command to modify certain kind of objects a DROP and CREATE will be used in order to do a full modification. This option does not affects the database object. Avoid the generation of DROP commands for objects that exists in database but not in the model. This is useful when diff a partial model against the complete database. Do not drop missing objects Store in S&QL file Diff tool Generate diff code Source database Current model: (model) Compare to Appl&y on server Diff Diff Froce the generation of DROP commands for columns and constraints that exist in database but not in the model. This is useful when diff a partial model against the complete database and the user needs to drop columns and constraint but preserve the rest of the objects. Drop missing columns and constraints Truncate tables before alter columns Import && Export Import Importeren Export Exporteer This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes Output Uitvoer Changes: Aanpassingen: Cancel Annuleren Progress label... Vooruitgangslabel... Step label... Staplabel... <html><head/><body><p>Objects marked with an <span style=" font-weight:600;">ALTER</span> may not be effectively changed unless that the differences detected are in attributes that can be modified through ALTER commands otherwise no operationwill be performed or, if the force recreation is checked, the object will be dropped and created again.</p></body></html> <html><head/><body><p>Objecten die zijn aangeduid met <span style=" font-weight:600;">ALTER</span> kunnen mogelijkerwijs niet worden aangepast tenzij de gedetecteerde verschillen in de attribute liggen die kunnen worden aangepast via een ALTER commando; in alle andere gevallen zal geen actie worden ondernomen of, indien 'Forceer het heraanmaken van objecten' is aangevinkt, zal het object worden verwijderd en heraangemaakt.</p></body></html> Objects to be created Objecten die aangemaakt moeten worden 0 0 Objects to be dropped Objecten die verwijderd moeten worden Possible objects to be changed Objecten die mogelijkerwijs aangepast moeten worden Ignored objects (system ones or with sql disabled) Genegeerde objecten (systeemobjecten of objecten waarvan SQL is uitgeschakeld) Diff Preview Diff voorbeeld &Apply diff Diff &Toepassen &Generate &Genereer &Close &Sluiten Waiting process to start... Wachten op het starten van de taak... Confirmation Bevestiging <strong>WARNING:</strong> The generated diff is ready to be exported! Once started this process will cause irreversible changes on the database. Do you really want to proceed? <strong>PAS OP:</strong> De gegenereerde diff is klaar om geëxporteerd te worden! Eens gestart zal dit proces onherroepelijke veranderingen aanbrengen aan de database. Bent u zeker dat u wilt verdergaan? Apply diff Diff toepassen Preview diff Diff belijken model not saved yet (none) Step %1/%2: Importing database <strong>%3</strong>... Step %1/%2: Comparing <strong>%3</strong> and <strong>%4</strong>... Step %1/%2: Exporting diff to database <strong>%3</strong>... Diff process paused. Waiting user action... Het diff proces is gepauzeerd. Wachten op een actie van de gebruiker... Saving diff to file <strong>%1</strong> De diff wordt opgeslagen in het bestand <strong>%1</strong> Diff process sucessfully ended! Het diff proces werd succesvol beëindigd! No operations left. Er zijn geen operaties meer. Operation cancelled by the user. De operatie werd geannulleerd door de gebruiker. Process aborted due to errors! Het proces werd afgebroken omwille van fouten! -- SQL code purposely truncated at this point in demo version! -- No differences were detected between model and database. -- -- Er werden geen verschillen gedetecteerd tussen het model en de database. -- Error code <strong>%1</strong> found and ignored. Proceeding with export. Foutencode <strong>%1</strong> trad op en werd genegeerd. De export gaat voort. Save diff as... Sla diff op als... SQL code (*.sql);;All files (*.*) SQL Code (*.sql);;Alle bestanden (*.*) ModelExportForm Export model Exporteer model Settings Instellingen Database server Database server pgModeler ignores errors generated by duplicated objects and creates only that ones which does not exists in the database. This option may be used when an object was created after a previous model export. pgModeler negeert fouten die worden gegenereerd door duplicate objecten en creëert objecten die nog niet in de database bestaan. Deze optie kan worden gebruikt wanneer een object werd gecreëerd door een eerdere model export. Ignore object duplicity Negeer object-duplicaten Connection: Verbinding: PostgreSQL version in which the SQL code should be generated. It is recommended to select this option only when the version of the DBMS, somehow, is not identifiable or if you need to generate a specific version of SQL code for test purposes. De PostgreSQL versie waarvoor SQL code moet worden gegenereerd. Het is aangeraden om deze optie enkel in te stellen wanneer de versie niet automatisch kan worden bepaald of wanneer u een specifieke versie nodig hebt voor bijvoorbeeld test-doeleinden. PostgreSQL: PostgreSQL: This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes If <strong>DB</strong> is checked pgModeler will destroy the database if already exists on the server. When <strong>Objects</strong> is checked pgModeler will execute the DROP command attached to SQL-enabled objects. <strong>WARNING:</strong> this option leads to data loss so make sure to have a backup first. Indien <strong>DB</strong> aangevinkt is, zal pgModeler de database verwijderen indien deze reeds in de server bestaat. Indien <strong>Objecten</string> is aangevinkt zal pgModeler DROP commando's toevoegen aan de objecten waarvoor SQL is ingeschakeld. <strong>PAS OP:</strong> deze optie kan tot dataverlies leiden, zorg ervoor dat u een recente backup kan terugplaatsen. Drop: Verwijder: DB DB pgModeler will destroy the database if already exists on the server. Make sure to have a backup before use this option because all data will be lost. pgModeler zal de database verwijderen indien deze reeds in de server aanwezig is. Zorg ervoor dat u een recente backup kan terugplaatsen indien nodig want alle data zal verloren gaan. Zoom: Zoom: Show grid Raster tonen Show delimiters Delimiters tonen Exporting the model page by page will generate files with a <strong>_p[n]</strong> suffix where <strong>n</strong> is the page id. Check if the current user has write permission on output folder. Het model pagina per pagina exportern genereert bestanden met de suffix <strong>_p[n]</strong> waarbij <strong>n</strong> de pagina id is. Zorg ervoor dat de huidige gebruiker schrijf-machtiging heeft in de uitvoermap. Page by page Pagina per pagina Select target file Selecteer doelbestand ... ... SQL file SQL bestand File: Bestand: Ob&jects Graphics file Type: Type: PostgreSQL version in which the SQL code should be generated De PostgreSQL versie waarvoor SQL code moet worden gegenereerd I&mage (PNG) &Vectorial (SVG) Output Uitvoer Cancel Annuleren Progress label... Vooruitgangslabel... &Export &Exporteer &Close &Sluiten Error code <strong>%1</strong> found and ignored. Proceeding with export. Foutencode <strong>%1</strong> trad op en werd genegeerd. De export gaat voort. Initializing model export... Model export wordt geïnitialiseerd... Saving file '%1' Bestand `%1' wordt opgeslagen Exporting process aborted! Het export proces werd afgebroken! Export model as... Exporteer model als... SQL script (*.sql);;All files (*.*) Portable Network Graphics (*.png);;All files (*.*) Scalable Vector Graphics (*.svg);;All files (*.*) Exporting process canceled by user! Het export proces werd geannuleerd door de gebruiker! Exporting process sucessfuly ended! Het export proces werd succesvol beëindigt! ModelExportHelper Generating SQL code for PostgreSQL `%1' Bezig met het genereren van SQL code voor PostgreSQL `%1' Output SQL file `%1' successfully written. Het uitvoer-SQL bestand `%1' werd succesvol opgeslagen. Rendering objects to page %1/%2. Objecten worden gerendered naar pagina %1/%2. Output image `%1' successfully written. Uitvoerafbeelding `%1' werd succesvol opgeslagen. Exporting model to SVG file. SVG representation of database model SVG file generated by pgModeler Output file `%1' successfully written. Starting export to DBMS. De export naar het DBMS begint. PostgreSQL version detection overridden. Using version `%1'. PostgreSQL versie-detectie werd overschreven. Versie `%1' wordt gebruikt. PostgreSQL `%1' server detected. PostgreSQL `%1' server ontdekt. Generating temporary names for database, roles and tablespaces. De tijdelijke namen voor de database, rollen en tablespaces worden gegenereerd. Enabling the SQL code for database `%1' to avoid errors. SQL code voor de database `%1' wordt geactiveerd om fouten te vermijden. Ignoring object duplication errors. Duplicaten-fouten worden genegeerd. Ignoring the following error code(s): `%1'. De volgende foutencode(s) worden genegeerd: `%1' Trying to drop database `%1'. Proberen om database `%1' te verwijderen. Simulation mode activated. Simulatiemodus geactiveerd. Generating SQL for `%1' objects... Genereren van SQL voor `%1' objecten... Destroying objects created on the server. Objecten aangemaakt op de server worden verwijderd. Restoring original names of database, roles and tablespaces. De originele namen van de database, rollen en tablespaces worden teruggezet. Creating object `%1' (%2) Object `%1' (%2) wordt aangemaakt. Creating database `%1' Connecting to database `%1' Renaming `%1' (%2) to `%3' Dropping object `%1' (%2) Object `%1' (%2) wordt verwijderd Changing object `%1' (%2) Object `%1' (%2) wordt aangepast. Running auxiliary command. Een hulpcommando wordt uitgevoerd. ModelFixForm Model file fix Modelcorrectiebestand <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Waiting process to start...</span></p></body></html> &Fix &Correctie &Close &Sluiten Fix model file Corrigeer modelbestand <html><head/><body><p>[pgmodeler-cli not found error]</p></body></html> <html><head/><body><p>[pgmodeler-cli kon niet worden gevonden]</p></body></html> pgmodeler-cli: pgmodeler-cli: Browse for pgmodeler-cli tool Blader naar pgmodeler-cli tool ... ... The specified file is not the pgModeler command line tool (pgmodeler-cli). Het gespecifieerde bestand is niet het pgModeler command line tool (pgmodeler-cli). Input file: Invoerbestand: Output file: Uitvoerbestand: Fix tries: Correctiepogingen: Select input file Selecteer invoerbestand Select output file Selecteer uitvoerbestand Load fixed model when finish Laad gecorrigeerde model na voltooïng In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. <strong>NOTE:</strong> relationships may lost their graphical configuration like custom points and line color. In sommige gevallen kan het correctieproces niet alle objecten herstellen en zijn manuele correcties via een tekstverwerker vereist. <strong>LET OP:</strong> relaties kunnen mogelijkerwijs hun configuratie verliezen, zoals aangepaste punten- en lijn-kleur. Waiting process to start... Wachten op het starten van de taak... Could not locate <strong>%1</strong> tool on <strong>%2</strong>. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below. Het tool <strong>%1</strong> kon niet worden gevonden in <strong>%2</strong>. Het correctieprocess kan niet verder gaan! Gelieve uw pgModeler installatie na te kijken of het pad naar het tool manueel in te stellen. pgModeler command line tool (%1) pgModeler command line tool (%1) ModelNavigationWidget Form Venster Previous model Vorige model Ctrl+Left Ctrl+Right Alt+C Next model Volgende model Close model Sluit model ... ... (model not saved yet) (het model werd nog niet opgeslagen) ModelObjectsWidget Model Objects Modelobjecten Visible object types Hide this widget Verberg dit widget ... ... 1 1 ID ID Object Object Type Type Parent Object Ouder Object Parent Type Ouder Type Select All Selecteer Alles Clear All Alles Wissen Model objects Select Selecteer Return Keer terug Cancel Annuleren Esc Esc Tree view Boomstructuur List view Lijst Objects view configuration Object-overzichtsconfiguratie Expands all items Alle items uitklappen Collapses all items Alle items inklappen Filter: Filter: By ID Volgens ID New Nieuw ModelOverviewWidget Model overview Modeloverzicht Failed to generate the overview image. The requested size %1 x %2 was too big and there was not enough memory to allocate! ModelRestorationForm Model restoration Modelherstel pgModeler was not closed properly in a previous execution and some models were still being edited. Click <strong>Restore</strong> to reopen the models or <strong>Cancel</strong> to abort the restoration. pgModeler werd niet correct afgesloten en sommige modellen waren nog steeds geladen. Klik op <strong>Herstel</strong> om deze mogellen te heropenen of <strong>Annuleer</strong> om het herstel af te breken. pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler. pgModeler zal proberen om de geselecteerde modellen te herstellen. Indien dit niet lukt blijven deze staan. Deze optie dient als laatste redmiddel om een database model te recupereren. Tijdelijke modellen zullen blijven staan totdat de applicatie wordt afgesloten. Dit betekent dat de gebruiker moet proberen deze manueel te recupereren vooraleer pgModeler af te sluiten. Keep temporary models in case of restoration failure Houdt de tijdelijke modellen bij indien recuperatie faalt Database Database File Modified Size &Cancel &Annuleer &Restore &Herstel ModelValidationHelper There are pending errors! SQL validation will not be executed. Er zijn fouten! SQL validatie zal niet worden uitgevoerd. Operation canceled by the user. De operatie werd geannuleerd door de gebruiker. ModelValidationWidget Form Venster Enables the validation of SQL code in DBMS. This process requires the use of a pre-configured connection. SQL validation will occur only in the last step (when all objects were validated) or when there are no warnings. Connection to be used in the SQL validation pgModeler will generate unique and temporary names for database, role and tablespace objects. This option avoids object duplication errors when running the SQL validation. Use unique temporary names for cluster level objects Warnings: does not prevents model to be saved. Let op: dit voorkomt niet dat het model kan worden opgeslagen. 0 0 Errors: model will not be saved while there are validation errors. Fouten: het model zal niet worden opgeslagen zolang er validatiefouten zijn. Hide this widget Verberg dit widget ... ... Swap ids SQL Validation: SQL Validatie: PostgreSQL version PostgreSQL versie Try to resolve the reported issues. Probeer om de gerapporteerde problemen te verhelpen. Ctrl+S Ctrl+S Clear validation results Validatieresultaten leegmaken Clear Leegmaken Try to apply a fix on the selected validation info. Probeer de validatieinformatie te verhelpen. Options Opties Cancel the SQL validation in progress. Annuleer de lopende SQL validatie. Cancel Annuleren Esc Esc Apply fixes Change the creation order for two objects by swapping their ids Wijzig de aanmaak-volgorde voor twee objecten door hun ids om te wisselen Va&lidate Va&lideer Autodetect Autodetecteer The object <strong>%1</strong> <em>(%2)</em> [id: %3] is being referenced by <strong>%4</strong> object(s) before its creation. Het object <strong>%1</strong> <em>(%2)</em> [id: %3] wordt door <strong>%4</strong> object(en) gerefereerd vóór zijn aanmaak. The object <strong>%1</strong> <em>(%2)</em> [id: %3]%4 is referencing columns created by <strong>%5</strong> relationship(s) but is created before them. Het object <strong>%1</strong> <em>(%2)</em> [id: %3]%4 refereerd naar kolommen aangemaakt door <strong>%5</strong> relatie(s) maar wordt vóór deze aangemaakt. The object <strong>%1</strong> <em>(%2)</em> has a name that conflicts with <strong>%3</strong> object's name(s). Het object <strong>%1</strong> <em>(%2)</em> heeft een naam die conflicteerd met de naam van <strong>%3</strong> andere objecten. The relationship <strong>%1</strong> [id: %2] is in a permanent invalidation state and needs to be relocated. De relatie <strong>%1</strong> [id: %2] is in een permanente ongeldige staat en moet worden herplaats. SQL validation failed due to error(s) below. <strong>NOTE:</strong><em> These errors does not invalidates the model but may affect operations like <strong>export</strong> and <strong>diff</strong>.</em> SQL validatie faalde omwille van de volgende fouten. <strong>LET OP:</strong><em> Deze fouten ontkrachten het model niet maar kunnen <strong>export</strong> en <strong>diff</strong> beïnvloeden.</em> The column <strong>%1</strong> on <strong>%2</strong> <em>(%3)</em> is referencing the geospatial data type <strong>%4</strong> but the <strong>postgis</strong> extension is not present in the model! <strong>HINT:</strong> try to swap the relationship by another ones that somehow are linked to it through generated columns or constraints to solve this issue. Note that other objects may be lost in the swap process. <strong>HINT:</strong> Create the extension in the model or let it be created by applying the needed fixes. <em>The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!</em> <em>Het hierboven vermeldde object werd aangemaakt door een relatie. Verander het naamspatroon van de genererende relatie. Dit probleem kan niet automatisch worden verholpen!</em> Conflicting object: <strong>%1</strong> <em>(%2)</em>. Conflicterende object: <strong>%1</strong> <em>(%2)</em>. Relationship: <strong>%1</strong> [id: %2]. Relatie: <strong>%1</strong> [id: %2]. Referrer object: <strong>%1</strong> <em>(%2)</em> [id: %3]. Refererende object: <strong>%1</strong> <em>(%2)</em> [id: %3]. SQL validation not executed! No connection defined. Database model successfully validated. Het database model werd succesvol gevalideerd. Running SQL commands on server... De SQL commando's worden uitgevoerd op de server... Processing object: %1 Bezig met het verwerken van object: %1 ModelWidget One to One (1-1) Een-op-een (1-1) One to Many (1-n) Een op meer (1-n) Many to Many (n-n) Meer op meer (n-n) Copy Kopieer Inheritance Overerving <strong>ATTENTION:</strong> The database model is protected! Operations that could modify it are disabled! <strong>OPGELET:</strong> Het databasemodel is beschermd! Operaties die het zouden kunnen aanpassen zijn uitgeschakeld! Source Bron Alt+S Alt+S Show object source code Toon object broncode Properties Eigenschappen Space Spatie Edit the object properties Bewerk de eigenschappen van het object Protect Bescherm Unprotect Bescherming af Protects object(s) from modifications Beschermt object(en) tegen aanpassingen Delete Verwijderen Del Del Del. cascade Verwijder cascade Shift+Del Shift+Del Select all Selecteer Alles Select tagged Select Selecteer Ctrl+A Ctrl+A Selects all the graphical objects in the model Selecteert alle grafische objecten in het model Edit data Convert Converteer Ctrl+C Ctrl+C Paste Plakken Ctrl+V Ctrl+V Cut Knippen Ctrl+X Ctrl+X Deps && Referrers Afhankelijkheden && Verwijzers New Nieuw Add a new object in the model Voeg een nieuw object toe aan het model Quick Snel Quick action for the selected object Snelle actie voor het geselecteerde object Rename Hernoem F2 F2 Quick rename the object Snelle hernoeming van het object Move to schema Verplaats naar schema Set tag Zet tag Edit permissions Machtigingen aanpassen Ctrl+E Ctrl+E Change owner Eigenaar veranderen Select children Selecteer kinderen Open relationship Open relatie Custom SQL Aangepaste SQL Alt+Q Alt+Q Convert to sequence Converteer naar sequentie Convert to serial Converteer naar serieel Break line Nieuw lijn Remove points Verwijder punten Enable SQL Schakel SQL in Disable SQL Schakel SQL uit Duplicate Ctrl+D Extended attributes Show Hide Jump to table Schemas rectangles Fade in/out Fade in Fade out Relationships Relaties Swap ids Edit the objects creation order by swapping their ids 90° (vertical) 90° (vertikaal) 90° (horizontal) 90° (horizontaal) 90° + 90° (vertical) 90° + 90° (vertikaal) 90° + 90° (horizontal) 90° + 90° (horizontaal) All objects Schemas Tables Tabellen Views Textboxes Zoom: %1% Zoom: %1% Do you really want to convert the relationship into an intermediate table? Bent u zeker dat u de relatie wilt converteren naar een intermediaire tabel? Loading database model Het databasemodel wordt geladen Saving database model Het databasemodel wordt opgeslagen Do you want to %1 the selected schema's children too? protect unprotect Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. Wenst u alle afhankelijken van de geselecteerde objecten ook te kopiëren? Dit minimalizeert het verbreken van referenties wanneer gekopieerde objecten in een ander model worden geplakt. Pasting objects... Bezig met het plakken van objecten... Validating object: `%1' (%2) Bezig met het valideren van object: `%1' (%2) Generating XML for: `%1' (%2) Bezig met het genereren van XML voor: `%1' (%2) Pasting object: `%1' (%2) Bezig met het plakken van object: `%1' (%2) Not all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! Niet alle objecten werden in het model geplakt omwille van fouten die werden gegenereerd gedurende dit proces. Kijk de error-stack na voor meer details! <strong>CAUTION:</strong> You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed? <strong>PAS OP:<strong> U staat op het punt om objecten te verwijderen in cascade modus, dit betekent dat ook objecten die niet geselecteerd zijn verwijderd kunnen worden. Bent u zeker dat u wilt verdergaan? <strong>CAUTION:</strong> Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? <strong>PAS OP:</strong> Meerdere objecten in één keer verwijderen kan onherroepbare ongeldigheden veroorzaken in andere objecten binnen het model en ervoor zorgen dat deze objecten ook worden verwijderd. Bent u zeker dat u verder wenst te gaan? <strong>CAUTION:</strong> Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? <strong>PAS OP:</strong> Een relatie verwijderen kan onherroepbare ongeldigheden veroorzaken in andere objecten en ervoor zorgen dat deze objecten ook worden verwijderd. Bent u er zeker van dat u wenst verder te gaan? Do you really want to delete the selected object? Bent u er zeker van dat u het geselecteerde object wenst te verwijderen? The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details. Het cascade verwijderen kwam enkele problemenen tegen tijdens het uitvoeren! Sommige objecten konden niet worden verwijderd of geregistreerd in de actie-geschiedenis! Gelieve de error-stack na te kijken voor meer details. (no objects) (geen objecten) None Source code Broncode Constraints Constraints ModelsDiffHelper Processing object `%1' (%2)... Object `%1' wordt behandeld (%2)... Skipping object `%1' (%2)... Object `%1' wordt overgeslagen (%2)... Processing diff infos... Diff informatie wordt verwerkt... Processing `%1' info for object `%2' (%3)... `%1' informatie voor object `%2' wordt verwerkt (%3)... No differences between the model and database. Preparing diff code... NewObjectOverlayWidget Form Venster Role Rol Tag Tag Cast Cast A A Language Taal Textbox Tekst box Event Trigger Event Trigger Tablespace Tablespace Schema Schema Domain Domein Conversion Conversie Aggregate Aggregator Collation Sortering Table Tabel Type Type Op. Family Op. Familie Sequence Sequentie Extension Uitbreiding Function Functie Op. Class Op. Klasse Operator Operator View View Permissions Machtigingen Rule Regel Index Index Column Kolom Constraint Constraint Generic SQL Trigger Trigger Policy Many-to-many Meer-op-meer One-to-many Een-op-meer One-to-one Een-op-een Inheritance Overerving Copy Kopieer G G K K H H J J D D E E F F L L O O U U I I R R S S Q Q T T P P M M Y Y W W 9 9 Z Z X X C C V V B B 8 8 1 1 2 2 3 3 5 5 4 4 0 0 NumberedTextEditor Load Laden Load the object's source code from an external file Edit Edit the source code in the preferred external editor Clear Leegmaken Upper case Lower case Ident right Ident left SQL file (*.sql);;All files (*.*) SQL Code (*.sql);;Alle bestanden (*.*) Load file The source editor `%1' is running on `pid: %2'. Could not start the source code editor application `%1'! Make to sure that the source editor path defined in the general settings points to a valid executable and the current user has permission to run the application. Error message returned: `%2' ObjectDepsRefsWidget Dependencies Afhankelijken ID ID Object Object Type Type Parent Object Ouder Object Parent Type Ouder Type Exclude indirect dependencies Sluit indirecte afhankelijken uit References Referenties Include indirect references Neem indirecte afhankele op This object does not exists anymore. The dependencies and references listing are disabled. Dit object bestaat niet langer. Het lijsten van afhankelijken en referenties is uitgeschakeld. Object's dependencies & references Afhankelijken & referenties van het object ObjectFinderWidget Form Venster Pattern: Patroon: Find Zoek Defines the search filter Definieert de zoekfilter Filter Filter Clears the search results Maakt de zoekresultaten leeg Clear Leegmaken ... ... Hide this widget Verberg dit widget (Un)selects the graphical objects in the results grid Select Selecteer Regular Expression Regular expression Exact Match Exacte Overeenkomst Select All Selecteer Alles Clear All Alles Wissen Case Sensitive Hoofdlettergevoelig ID ID Object Object Type Type Parent Object Ouder Object Parent Type Ouder Type Fades outs all the graphical objects in the results grid (or those not listed). The current fade in/out state of all objects is modified. Fade out Listed Not listed Found <strong>%1</strong> object(s). <strong>%1</strong> object(en) gevonden. No objects found. Geen objecten gevonden. ObjectRenameWidget Form Venster .... ... to: naar: Rename Hernoem Cancel Annuleren ObjectSelectorWidget Form Venster Clear field Veld leegmaken Select Object Selecteer Object Select %1 ObjectsTableWidget Form Venster Add Item Item Toevoegen Ins Ins Remove Item Item Verwijderen Del Del Update Item Item Updaten Alt+R Alt+R Remove All Alles Verwijderen Shift+Del Shift+Del Duplicate item Ctrl+D Edit Item Item Aanpassen Space Spatie Move Up Naar Boven Ctrl+Up Move Down Naar Beneden Ctrl+Down Move to start Naar de eerste plaats Ctrl+Home Ctrl+Home Move to end Naar de laatste plaats Ctrl+End, Ctrl+S Ctrl+End, Ctrl+S Confirmation Bevestiging Do you really want to remove the selected item? Bent u zeker dat u het geselecteerde item wilt verwijderen? Do you really want to remove all the items? OperationList (invalid object) (ongeldig object) OperationListWidget Executed Operations Uitgevoerde Acties Hide this widget Verberg dit widget ... ... 1 1 Operations: Acties: 0 0 Position: Positie: Delete operation history Verwijder actiegeschiedenis Undo Ongedaan maken Redo Opnieuw doen Object: %1 Object: %1 Name: %1 Naam: %1 created aangemaakt removed verwijderd modified aangepast moved verplaatst Operation: %1 Actie: %1 Operation history exclusion Actiegeschiedenisuitsluiting Delete the executed operations history is an irreversible action, do you want to continue? Het verwijderen van de geschiedenis van de uitgevoerde acties kan niet worden ongedaan gemaakt, bent u zeker dat u wilt verdergaan? OperatorClassWidget Default Class: Standaardklasse: Indexing: Indexering: Elements Elementen Element Type: Elementtype: Operator Operator Function Functie Storage Opslag Function: Functie: Operator: Operator: Support/Strategy: Ondersteuning/Strategie: Op. Family: Operator Familie: Storage Type Opslagtype Object Object Type Type Support/Strategy Ondersteuning/Strategie Operator Family Operator Familie OperatorFamilyWidget Indexing: Indexering: OperatorWidget MERGES MERGES HASHES HASHES Options: Opties: Arguments Argumenten Advanced Geavanceerd Join: Join: Restrict: Restrict: Commutator: Commutator: Negator: Negator: Operator Func.: Operator functie: Left Argument Type Linkse Argument Type Right Argument Type Rechtse Argument Type To create a unary operator it is necessary to specify as <strong><em>'any'</em></strong> one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator. Om een unaire operator aan te maken moet u <strong><em>'any'</em></strong> als een van zijn argumenten specifiëren. Daarenboven mag de functie die de operator definieert slechts één parameter bezitten die van hetzelfde type moet zijn als de unaire operator. ParameterWidget Default Value: Standaardwaarde: Mode: Modus: IN IN OUT OUT VARIADIC PermissionWidget Permissions Machtigingen ID: ID: Disable SQL code Niet-uitvoerbare SQL code Roles Rollen Privileges Machtiginen Edit permissions Machtigingen aanpassen &Grant Re&voke Cascade Cascade Privilege Machtiging GRANT OPTION GRANT OPTION Add Permission Machtiging toekennen Update Permission Machtiging aanpassen Cancel Operation Actie annuleren Code Preview Codevoorbeeld Id Id Name Naam Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. -- No permissions defined for the specified object! -- Er zijn geen machtigingen gedefinieerd voor het gespecifieerde object! /* Could not generate the SQL code preview for permissions! /* Er kon geen SQL Codevoorbeeld worden gegenereerd voor de machtigingen! PgModelerCLI Unrecognized option '%1'. Niet-herkende optie '%1'. Value not specified for option '%1'. Er is geen waarde gespecifieerd voor optie '%1'. Option '%1' does not accept values. Optie '%1' aanvaardt geen waardes. Usage: pgmodeler-cli [OPTIONS] Gebruik: pgmodeler-cli [OPTIES] command line interface. commandolijn interface. General options: Algemene opties: PNG and SVG export options: DBMS export options: DBMS exporteringsopties: Miscellaneous options: Andere opties: There are no connections configured. Er zijn geen verbindingen geconfigureerd. Input file must be different from output! Het invoerbestand mag niet hetzelfde zijn als het uitvoerbestand! Incomplete connection information! Onvolledige verbindingsinformatie! Invalid zoom specified! Een ongeldige zoom gespecifieerd! Invalid action specified to update mime option! The actie om de mime optie the updaten is ongeldig! Starting model fixing... Modelcorrectie begint... Starting mime update... Mime update begint... Starting model export... Model export begint... Model successfully fixed! Het model werd succesvol gecorrigeerd! Connection aliased as '%1' was not found in the configuration file. PostgreSQL Database Modeler Project - pgmodeler.io Copyright 2006-2018 Raphael A. Silva <raphael@pgmodeler.io> This CLI tool provides several operations over models and databases without the need to perform them in pgModeler's graphical interface. All available options are described below. %1, %2 [FILE] Input model file (.dbm). This is mandatory for fix, export operations. %1, %2 [DBNAME] Input database name. This is mandatory for import operation. %1, %2 [FILE] Output file. This is mandatory for fixing model or exporting to file, png or svg. %1, %2 Try to fix the structure of the input model file in order to make it loadable again. %1, %2 [NUMBER] Model fix tries. When reaching the maximum count the invalid objects will be discarded. %1, %2 Export the input model to a sql script file. %1, %2 Export the input model to a png image. %1, %2 Export the input model to a svg file. %1, %2 Export the input model directly to a PostgreSQL server. %1, %2 Import a database to an output file. %1, %2 Compares a model and a database or two databases generating the SQL script to synch the latter in relation to the first. %1, %2 Force the PostgreSQL version of generated SQL code. %1, %2 Silent execution. Only critical messages and errors are shown during process. %1, %2 Show this help menu. Connection options: %1, %2 List available connections in file %3. %1, %2 [ALIAS] Connection configuration alias to be used. %1, %2 [HOST] PostgreSQL host in which a task will operate. %1, %2 [PORT] PostgreSQL host listening port. %1, %2 [USER] PostgreSQL username. %1, %2 [PASSWORD] PostgreSQL user password. %1, %2 [DBNAME] Connection's initial database. %1, %2 Draws the grid in the exported image. %1, %2 Draws the page delimiters in the exported image. %1, %2 Each page will be exported in a separated png image. (Only for PNG images) %1, %2 [FACTOR] Applies a zoom (in percent) before export to png image. Accepted zoom interval: %3-%4 (Only for PNG images) %1, %2 Ignores errors related to duplicated objects that eventually exist in the server. %1, %2 [CODES] Ignores additional errors by their codes. A comma-separated list of alphanumeric codes should be provided. %1, %2 Drop the database before execute a export process. %1, %2 Runs the DROP commands attached to SQL-enabled objects. %1, %2 Simulates an export process by executing all steps but undoing any modification in the end. %1, %2 Generates temporary names for database, roles and tablespaces when in simulation mode. Database import options: %1, %2 Ignore all errors and try to create as many as possible objects. %1, %2 Import system built-in objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Import extension objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Run import in debug mode printing all queries executed in the server. Diff options: %1, %2 [DBNAME] The database used in the comparison. All the SQL code generated is applied to it. %1, %2 Save the generated diff code to output file. %1, %2 Apply the generated diff code on the database server. %1, %2 Don't preview the generated diff code when applying it to the server. %1, %2 Drop cluster level objects like roles and tablespaces. %1, %2 Revoke permissions already set on the database. New permissions configured in the input model are still applied. %1, %2 Drop missing objects. Generates DROP commands for objects that are present in the input model but not in the compared database. %1, %2 Force the drop of missing columns and constraints. Causes only columns and constraints to be dropped, other missing objects aren't removed. %1, %2 Rename the destination database when the names of the involved databases are different. %1, %2 Don't drop or truncate objects in cascade mode. %1, %2 Truncate tables prior to alter columns. Avoids errors related to type casting when the new type of a column isn't compatible to the old one. %1, %2 Don't reuse sequences on serial columns. Drop the old sequence assigned to a serial column and creates a new one. %1, %2 Don't force the recreation of objects. Avoids the usage of a DROP and CREATE commands to create a new version of the objects. %1, %2 Don't recreate the unmodifiable objects. These objects are the ones which can't be changed via ALTER command. %1, %2 [ACTION] Handles the file association to .dbm files. The ACTION can be [%3 | %4]. ** The diff process allows the usage of the following options related to import and export operations: * Export: * Import: ** When running the diff using two databases (%1 and %2) there's the need to specify two connections/aliases. If only one connection is set it will be used to import the input database as well to retrieve database used in the comparison. A second connection can be specified by appending a 1 on any connection configuration parameter listed above. Available connections (alias : connection string) No operation mode was specified! Export, fix model, import database, diff and update mime operations can't be used at the same time! Multiple export mode was specified! No input file was specified! No input database was specified! No output file was specified! No input file or database was specified! The input file and database can't be used at the same time! No database to be compared was specified! No diff action (save or apply) was specified! No output file for the diff code was specified! ** Error code `%1' found and ignored. Proceeding with export. ** Command: %1 Extracting objects' XML... De XML van de objecten word geextraheerd... Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted! Het invoerbestand is ongeldig! Kijk na of dit bestand door pgModeler werd gegenereerd ofdat het bestand gecorrupteerd raakte! Recreating objects... De objecten worden heraangemaakt... ** Object(s) that couldn't fixed: ** Object(en) die niet kon(den) worden gecorrigeerd: WARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2) OPGEPAST: Er zijn objecten die niet konden worden gecorrigeerd. We proberen opnieuw... (poging %1 van %2) Loading input file: %1 Fixed model file: %1 Export to PNG image: %1 Export to SVG file: %1 Export to SQL script file: %1 Export to DBMS: %1 Export successfully ended! Starting database import... Input database: %1 Saving the imported database to file... Import successfully ended! Starting diff process... Input model: %1 Compare to: %1 Loading input model... Importing the database `%1'... Comparing the generated models... No differences were detected. Saving diff to file `%1' ** WARNING: You are about to apply the generated diff code to the server. Data can be lost in the process! ** Proceed with the diff applying? (yes/no) > yes no Diff code not applied to the server. Applying diff to the database `%1'... Diff successfully ended! Mime database successfully updated! Database model files (.dbm) are already associated to pgModeler! Database modelbestanden (.dbm) zijn reeds geassocieerd met pgModeler! There is no file association related to pgModeler and .dbm files! Er is geen bestandsassociatie tussen pgModeler and .dbm bestanden! Mime database operation: %1 Mime databaseoperatie: %1 Can't erase the file %1! Check if the current user has permissions to delete it and if the file exists. Het bestand %1 kan niet worden verwijderd! Kijk na of de huidige gebruiker voldoende machtigingen heeft om het bestand te verwijderen en of het bestand bestaat. Running update-mime-database command... Het update-mime-database commando wordt uitgevoerd... PgModelerPlugin Plugin Information Plugin Informatie Version: %1 Versie: %1 Author: %1 Auteur: %1 PgModelerUiNS Do you want to apply the <strong>SQL %1 status</strong> to the object's references too? This will avoid problems when exporting or validating the model. Wenst u de <strong> SQL %1 status</strong> ook toe te passen op de referenties van het object? Dit vermijdt problemen bij het exporteren of valideren van het model. disabling uitschakelen enabling inschakelen PgSQLTypeWidget Form Venster Data Type Data Type SRID: SRID: Variation: Variatie: Z Z M M Precision Precisie Spatial: Ruimtelijk: Dimension Dimensie Format: Formaat: Timezone: Tijdszone: Type: Type: P: P: Length Lengte L: L: Interval: Interval: [ ]: [ ]: NONE GEEN PluginsConfigWidget Form Venster Open in file manager Open in bestandsbeheer Plug-ins root directory: Plug-in startmap: Loaded plug-ins Geladen plug-ins Plugin Plugin Version Versie Library Bibliotheek PolicyWidget Basics Command: Permissive Roles Rollen Expressions Expressies USING: CHECK: Name Naam Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. QObject new_database nieuwe_database %1 (line: %2) %1 (lijn %2) Relationship %1_has_one_%2 %1_heeft_exact_een_%2 %1_has_many_%2 %1_heeft_meerdere_%2 many_%1_has_many_%2 meerdere_%1_heeft_meerdere_%2 %1_inherits_%2 %1_erft_van_%2 %1_copies_%2 %1_kopieert_%2 RelationshipConfigWidget Form Venster Connection Mode Verbindingsmodus Connect FK to PK columns Verbindt FK naar PK kolommen This mode renders the relationships in crow's foot notation which has a better semantics and readability. It also determines the optimal point where the relationship is connected on the tables' edges taking their position into account. Crow's foot notation This mode determines the optimal point where the relationship is connected on the tables' edges taking their position into account. It implies the usage of the classical ER notation. Connect tables' edges This mode is available only for <strong>one-to-one</strong>, <strong>one-to-many</strong> and <strong>fk relationships</strong> but provides a better semantics when linking tables by placing the lines on the exact point where the relationship occurs. It implies the usage of the classical ER notation. This mode is the classical one. It connects the relationship to tables through their central points. It implies the usage of the classical ER notation. Connect tables' center points Verbindt de centrale punten van de tabellen FK Settings && Patterns FK instellingen && Patronen Foreign key settings Foreign key instellingen Deferral: Uitstel: Deferrable: Uitstelbaar: ON DELETE: ON DELETE: ON UPDATE: ON UPDATE: Name patterns Naamspatronen Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Het patroon voor de foreign key wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n). Foreign Key (Source): Foreign Key (Bron): Relationship type: Relatietype: Pattern for columns generated based upon target table's pk (n-n). Het patroon voor kolommen die worden gegenereerd op basis van de pk van de doeltabel (n-n). Column (Target): Kolom (Doel): One to one (1:1) Een-op-een (1:1) One to many (1:n) Een op meerdere (1:n) Many to many (n:n) Meerdere op meerdere (n:n) Generalization Generalisatie Copy Kopieer Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Het patroon voor de kolommen wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n). Column (Source): Kolom (Bron): Pattern for foreign key generated based upon target table's pk (n-n). Het patroon voor de foreign key wordt gegenereerd op basis van de pk van de doeltabel (n-n). Foreign Key (Target): Foreign Key (Doel): Pattern for unique key generated by the relationship. Het patroon voor de unieke sleutel wordt gegenereerd op basis van de relatie. Unique Key Name: Naam van de unieke sleutel: Pattern for primary key generated by identifier relationship. Het patroon voor de primary key wordt gegenereerd op basis van de relatie met de identifier. Primary Key Name: Naam van de Primary Key: Primary Key Column: Primary Key Kolom: Default Standaard RelationshipWidget General Algemeen Table 1: Tabel 1: Name Patterns Naamspatronen Use the values defined on settings dialogs for the fields below Gebruik de waarden ingesteld in het instellingsvenster voor de velden hieronder Use global settings for these fields Gebruik globale instellingen voor deze velden Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Het patroon voor de kolommen wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n). Column (Source): Kolom (Bron): Pattern for columns generated based upon target table's pk (n-n). Het patroon voor kolommen die worden gegenereerd op basis van de pk van de doeltabel (n-n). Column (Target): Kolom (Doel): Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Het patroon voor de foreign key wordt gegenereerd op basis van de pk van de gerefereerde tabel (1-1 en 1-n) of op basis van de pk van de brontabel (n-n). Foreign Key (Source): Foreign Key (Bron): Pattern for foreign key generated based upon target table's pk (n-n). Het patroon voor de foreign key wordt gegenereerd op basis van de pk van de doeltabel (n-n). Foreign Key (Target): Foreign Key (Doel): Pattern for primary key generated by identifier relationship. Het patroon voor de primary key wordt gegenereerd op basis van de relatie met de identifier. Primary Key Name: Naam van de Primary Key: Pattern for unique key generated by the relationship. Het patroon voor de unieke sleutel wordt gegenereerd op basis van de relatie. Unique Key Name: Naam van de unieke sleutel: Primay Key Column: Primary Key Kolom: Cardinality: Cardinaliteit: Name of the table generated from many to many relationship De naam van de tabel die is gegenereerd op basis van de meer-op-meer relatie Gen. Table Name: Algemene Tabelnaam: Rel. Type: Relatietype: Table 2: Tabel 2: [SRC] is required [BRON] is vereist [DST] is required [DOEL] is vereist Foreign key Settings Foreign key instellingen Deferrable: Uitstelbaar: Deferral: Uitstel: ON DELETE: ON DELETE: ON UPDATE: ON UPDATE: One to one relationship Een-op-een relatie &1-1 &gen E&XCLUDING One to many relationship Een-op-meer relatie 1-n 1-n Many to many relationship Meer-op-meer relatie n-n n-n Generalization relationship (inheritance) Generalisatierelatie (overerving) Dependency / Copy relationship Afhankelijkheid / Kopieer de relatie dep dep Relationship generated via foreign key Relatie gegenereerd via foreign key fk fk The receiver's primary key will be composed by the generated foreign key columns. De ontvanger's primary key wordt samengesteld door de gegenereerde foreign key kolommen. Identifier Identifier Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key. In plaats van een multi-kolom primary key te creeren op basis van de foreign key kolommen, wordt een enkele kolom aangemaakt en gebruikt als primary key. Single PK column Enkele PK kolom Custom Color: Aangepaste kleur: Copy Options Kopieeropties INDEXES INDEXES COMMENTS COMMENTS INCLUDING INCLUDING DEFAULTS DEFAULTS CONSTRAINTS CONSTRAINTS Use defaults Gebruik standaardwaarden ALL ALL STORAGE STORAGE Attributes Attributen Constraints Constraints Primary key Primary key Advanced Geavanceerd Attribute Attribuut Type Type Constraint Constraint Name Naam Use the special primary key if you want to include a primary key containing generated columns to the receiver table. <strong>Important:</strong> if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key. Gebruik de speciale primary key wanneer u een primary key samengesteld uit gegenereerde kolommen van de ontvangende tabel wilt insluiten. <strong>Belangrijk:</strong> indien dit een nieuwe relatie is moet u de creatie van deze relatie voltooien en dit dialoogvenster daarna opnieuw openen om de speciale primary key aan te maken. This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables. Dit geavanceerde tab-blad toont de objecten (kolommen of tabellen) die automatisch worden aangemaakt door de verbindingen van de relatie alsook de foreign keys die de link tussen de deelnemende tabellen voorstelt. Available tokens to define name patterns:<br/> <strong>%1</strong> = Reference (source) primary key column name. <em>(Ignored on constraint patterns)</em><br/> <strong>%2</strong> = Reference (source) table name.<br/> <strong>%3</strong> = Receiver (destination) table name.<br/> <strong>%4</strong> = Generated table name. <em>(Only for n:n relationships)</em> Default Standaard Referer View: Refererende View: Referer view references one or more columns of a table to construct it's own columns. De refererende view refereert naar een of meerdere kolommen van een tabel om zijn eigen kolommen aan te maken. Referenced table has its columns referenced by a view in order to construct the columns of this latter. De gerefereerde tabel heeft kolommen waarnaar wordt gerefereerd door een view die deze kolommen gebruikt om zijn eigen kolommen aan te maken. Referer Table: Refererende Tabel: Referer table references one or more columns of a table through foreign keys. This is the (n) side of relationship. De refererende tabel refereert naar een of meerdere kolommen in een andere tabel via foreign keys. Dit is the (n)-zijde van de relatie. Referenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship. De gerefereerde tabel heeft kolommen waarnaar wordt gerefereerd door een foreign key in een andere tabel. Dit is de (1) zijde van de relatie. Referenced Table: Gerefereerde Tabel: Reference Table: Referentietabel: Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship. De referentietabel heeft kolommen in zijn primary key die gekopieerd zullen worden naar de ontvangende tabel om de link tussen deze te bewerkstelligen. Dit is de (1) zijde van de relatie. Receiver Table: Ontvangende Tabel: Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship. De ontvanger (of gerefereerde) tabel zal de gegenereerde kolommen en de foreign key ontvangen om de link tussen beiden te bewerkstelligen. Dit is de (n) zijde van de relatie. In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table. In meer-op-meer relaties worden beide tabellen als referentie gebruikt om de link-tabel te representeren. Kolommen van beide tabellen worden gekopieerd naar de resulterende link-tabel en foreign keys naar elke deelnemende tabel worden aangemaakt. is required is vereist ResultSetModel [binary data] [binaire data] RoleWidget yyyy-MMM-dd hh:mm:ss yyyy-MMM-dd hh:mm:ss Validity Geldigheid Connections: Verbindingen: Attributes Attributen Superuser Superuser Inherit permissions Can create database Bypass RLS Can use replication Can login Kan inloggen Can create role Members Leden Member of Lid van Members (Admin.) Leden (Admin.) Password: Wachtwoord: Encrypted Geëncrypteerd Assigning <strong><em>-1</em></strong> to <strong><em>Connections</em></strong> creates a role without connection limit.<br/> Unchecking <strong><em>Validity</em></strong> creates an role that never expires. Role Rol RuleWidget Event: Event: Execution Type: Uitvoeringstype: Conditional Expr.: Voorwaardelijke Expressie: Commands Commando's SQL Command: SQL Commando: SQL command SQL commando To create a rule that does not perform any action (<strong>DO NOTHING</strong>) simply do not specify commands in the SQL commands table. Om een regel aan te maken die niets doet (<strong>DO NOTHING</strong>), laat eenvoudigweg de commando's in de SQL commando tabel leeg. SQLExecutionWidget Form Venster Save SQL commands Sla SQL commando's op Search in SQL code Close the current SQL script SQL script currently handled (not saved) Handle external SQL script &Script Alt+F Alt+Z Fi&nd Run the specified SQL command Voer het commando uit Run SQL Uitvoeren F6 F6 Clear sql input field and results Wis SQL invoerveld en resultaten Clear All Alles Wissen Export results to a CSV file Exporteer de resultaten naar CSV bestand Snippe&ts Snippe&ts Alt+T E&xport E&xporteren Alt+X Toggles the output pane &Output Alt+O Alt+O Current working database Results Messages History ... ... SQL file (*.sql);;All files (*.*) SQL Code (*.sql);;Alle bestanden (*.*) Load Laden Save Opslaan Save as Opslaan als [binary data] [binaire data] No results retrieved or changes done due to the error above. Messages (%1) Results (%1) [%1]: SQL command successfully executed in <em><strong>%2</strong></em>. <em>%3 <strong>%4</strong></em> Rows affected Rows retrieved Load SQL commands Laad SQL commando's Save CSV file Sla CSV bestand op Comma-separated values file (*.csv);;All files (*.*) Bestand met komma-gesepareerde waarden (*.csv);;Alle bestanden (*.*) The SQL input field and the results grid will be cleared! Want to proceed? Het SQL invoerveld en de resultaten-lijst zullen worden leeggemaakt! Wenst u verder te gaan? Copy selection Kopiëer de selectie Plain format CVS format This action will wipe out all the SQL commands history for all connections! Do you really want to proceed? Clear history Save history Reload history Find in history Hide find tool This action will wipe out all the SQL commands history for the current connection! Do you really want to proceed? SQLToolWidget Form Venster Database explorer Databaseverkenner Disconnect from all databases Van alle databases ontkoppelen ... Update the database list Toggle the object's attributes grid Attributes Attributen Alt+R Alt+R Toggle the display of source code pane Source code Broncode SQL execution SQL uitvoering Warning Opgepast <strong>ATTENTION:</strong> Disconnect from all databases will close any opened tab in this view! Do you really want to proceed? <strong>LET OP:</strong> Van alle databases ontkoppelen sluit alle tab-bladen in dit venster! Bent u zeker dat u verder wilt gaan? SceneInfoWidget Form Venster Current position of the mouse in the canvas - Current zoom factor Currently selected object(s) Dimensions of the selected object(s) No selection N/A Sel. objects: %1 SchemaWidget Fill color: Vulkleur: Show rectangle Toon rechthoek SequenceWidget Cyclic: Cyclisch: Start: Start: Maximum: Maximum: Minimum: Defualt values: Increment: Toename: Cache: Cache: Owner Col.: Bezittende kolom: User defined SnippetsConfigWidget Form Venster Label: Label: Applies to: Van toepassing op: ID: ID: Create new connection Maak een nieuwe verbinding aan Cancel edition Annuleer aanpassingen Edit selected connection Pas de geselecteerde verbinding aan Delete selected connection Verwijder de geselecteerde verbinding Remove All Alles Verwijderen Shift+Del Shift+Del Snippets: Snippets: Parse the snippet in order to check if there are syntax errors. Ontleed het snippet om zeker te zijn dat het geen syntactische fouten bevat. Parse Ontleed Add Toevoegen Update Updaten Parsable or dynamic snippets are written in the <strong>schema micro language</strong> syntax. When using a parsable snippet the attributes surrounded in <strong>{}</strong> will be replaced by the selected object's matching attributes. Ontleedbare of dynamische snippets worden in de <strong>schema micro language</strong> syntax geschreven. Wanneer een ontleedbaar snippet wordt gebruikt worden attributen die met <strong>{}</strong> zijn omringd, vervangen door de attributen van het overeenkomstige geselecteerde object. Parsable Ontleedbaar When handling parsable snippets empty attributes will be replaced by a value in the format <strong>{attribute}</strong>. Note that this option can affect the semantics of the resulting snippet. Bij ontleedbare snippets worden lege attributen vervangen door een waarde volgens het formaat <strong>{attribuut}</strong>. Deze optie kan de betekenis van het snippet beïnvloeden. Placeholders Plaatshouder Filter: Filter: General purpose Algemeen doel All snippets Alle snippets /* Error parsing the snippet '%1': %2 */ /* Er trad een fout op tijdens het onleden van het snippet '%1': %2 */ Duplicated snippet id <strong>%1</strong> detected. Please, specify a different one! Gelieve een andere snippet id te selecteren, de id <strong>%1</strong> is reeds in gebruik! Invalid ID pattern detected <strong>%1</strong>. This one must start with at leat one letter and be composed by letters, numbers and/or underscore! Een ongeldig ID patroon werd gedetecteerd. Deze moet starten met minstens één letter en worden gevormed door letters, nummer en/or een underscore! Empty label for snippet <strong>%1</strong>. Please, specify a value for it! Gelieve een waarde in te vullen voor het label van snippet <strong>%1</strong>! Empty code for snippet <strong>%1</strong>. Please, specify a value for it! Gelieve een waarde in te vullen voor de code van snippet <strong>%1</strong>! The dynamic snippet contains syntax error(s). Additional info: <br/><em>%1</em> Het dynamische snippet bevat één of meer syntactische fouten. Bijkomende info: <br/><em>%1</em> Do you really want to remove all snippets? Bent u zeker dat u alle snippets wilt verwijderen? No syntax errors found in the snippet. Het snippet bevat geen syntactische fouten. General Algemeen SourceCodeWidget Version: Versie: PostgreSQL PostgreSQL iconecodigo SQL SQL Code display: Codeweergave: Original Origineel Original + depedencies' SQL Origineel + SQL voor afhankelijken Original + children's SQL Origineel + SQL voor kinderen Save the SQL code to a file. Sla de SQL code op in een bestand. Save SQL Sla SQL Op XML XML Source code visualization Broncodevisualisatie <strong>Original:</strong> displays only the original object's SQL code.<br/><br/> <strong>Dependencies:</strong> displays the original code including all dependencies needed to properly create the selected object.<br/><br/> <strong>Children:</strong> displays the original code including all object's children SQL code. This option is used only by schemas, tables and views. Save SQL code as... Sla SQL code op als... SQL code (*.sql);;All files (*.*) SQL Code (*.sql);;Alle bestanden (*.*) Generating source code... De broncode wordt gegeneerd... -- NOTE: the code below contains the SQL for the selected object -- as well for its dependencies and children (if applicable). -- -- This feature is only a convinience in order to permit you to test -- the whole object's SQL definition at once. -- -- When exporting or generating the SQL for the whole database model -- all objects will be placed at their original positions. -- LET OP: de volgende code bevat SQL voor zowel het geselecteerde object -- alsook zijn afhankelijken kinderen (indien zo aangevinkt). -- -- Dit feature bestaat enkel zodat u op een eenvoudige manier de volledige -- SQL definitie van het object kan testen. -- -- Bij het exporteren of genereren van de SQL code voor de volledige database -- worden alle objecten in hun originele positie geplaatst. -- SQL code purposely truncated at this point in demo version! -- SQL code unavailable for this type of object -- -- Er is geen SQL code beschikbaar voor dit type object -- <!-- XML code preview disabled in demonstration version --> <!-- XML codevoorbeelden zijn niet beschikbaar in de demo-versie --> SwapObjectsIdsWidget Change objects creation order Create: Aanmaken: ID: ID: Before: Voor: Change the objects creation order is an irreversible operation and cause the operations history to be automatically erased. Note that the creation order configured in this form is not definitive and may change after a model validation. Swap the object ids changing their creation order Swap ids Filter: Filter: ID ID Object Object Type Type Parent Object Ouder Object Parent Type Ouder Type Swap the values of the fields Wissel de veldwaarden om Swap values Wissel de waarden om Table new_table nieuwe_tabel In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2' Tabellen kunnen slechts `%1' instancies per kind-object type of voorouder-tabellen hebben in demonstratie-versies! U heeft deze limiet bereikt voor het type `%2' TableDataWidget Edit table data Add empty rows Ins Ins Add an empty column Delete rows <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> Remove all rows from the grid preserving columns Shift+Del Shift+Del Delete the selected rows Del Del Duplicate the selected rows Ctrl+D Delete the selected columns Copy items on the grid Copy Add row Delete column Paste items on the grid Paste Plakken Ctrl+V Ctrl+V Fills the grid using a CSV file <html><head/><body><p>Some invalid or duplicated columns were detected. In order to solve this issue double-click the header of the highlighted ones in order to define the correct name in which the data belongs to or delete the entire column. Note that these columns are completely ignored when generating the <span style=" font-weight:600;">INSERT</span> commands.</p></body></html> Add column Duplicate rows Change the values of all selected cells at once Bulk data edit Ctrl+E Ctrl+E Remove all columns (and rows) from the grid Delete all columns Ctrl+Shift+Del Delete all rows Delete columns is an irreversible action! Do you really want to proceed? Remove all rows is an irreversible action! Do you really want to proceed? Remove all columns is an irreversible action! Do you really want to proceed? Unknown column Duplicated column TableObjectView Relationship: %1 Relatie: %1 TableWidget Options Opties Tag: Tag: With OID Met OID Generate ALTER for columns/constraints Genereer ALTER voor kolommen/constraints Unlogged Niet gelogged Enable row level security Force RLS for owner &Columns Co&nstraints Tri&ggers &Rules &Indexes &Policies &Tables Edit data Define initial data for the table Name Naam Schema Schema Type Type PK Default Value Standaardwaarde Attribute(s) It is not possible to mark a column as primary key when the table already has a primary key which was created by a relationship! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. It is not possible to mark a column created by a relationship as primary key! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. ON DELETE ON DELETE ON UPDATE ON UPDATE Refer. Table Refer. Tabel Firing Afvuring Events Events Execution Uitvoering Event Event Indexing Indexering Command Permissive USING expression CHECK expression Roles Rollen Parent Ouder Copy Kopie Yes Ja No Nee TablespaceWidget Form Venster Directory: Map: TagWidget Colors Kleuren Extended body: Uitgebreide inhoud: Body: Inhoud: Title: Titel: Schema name: Schemanaam: Table name: Tabelnaam: TaskProgressWidget Executing tasks Taken uitvoeren Waiting task to start... Wachten op het starten van de taak... TextboxWidget Font: Lettertype: Text Tekst pt pt Color: Kleur: Bold Vet Italic Cursief Underline Onderstrepen Select text color Selecteer tekstkleur TriggerWidget Constraint Constraint Deferrable: Uitstelbaar: FOR EACH ROW FOR EACH ROW Event: Event: INSERT INSERT DELETE DELETE UPDATE UPDATE TRUNCATE TRUNCATE Refer. Table: Refer. Tabel: Condition: Voorwaarde: Arguments Argumenten Argument: Argument: Columns Kolommen Column: Kolom: Function: Functie: Options: Opties: Excution: Uitvoer: Column Kolom Type Type TypeWidget Range Omvang Functions Functies INPUT: INPUT: OUTPUT: OUTPUT: RECV: RECV: SEND: SEND: TPMOD_IN: TPMOD_IN: TPMOD_OUT: TPMOD_OUT: ANALYZE: ANALYZE: Attributes Attributen Internal Length: Interne lengte: Storage: Opslag: Options: Opties: By value Per waarde Preferred Voorkeur Collatable Sorteerbaar Category: Categorie: Delimiter: Delimiter: Default Value: Standaardwaarde: Alignment: Uitlijning: integer integer char char smallint smallint double precision double precision Configuration: Configuratie: Base Type Basistype Enumeration Enumeratie Co&mposite Enumerations Enumeraties Enumeration: Enumeratie: Name: Naam: Collation: Sortering: Subtype Diff Func.: Subtype Diff Func.: Operator Class: Operator Klasse: Canonical Func.: Canonische Func.: Like Type Like type Element Type Elementtype Subtype Subtype Name Naam Type Type Collation Sortering The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table> De functies die worden toegewezen aan een type moeten in de C programmeertaal zijn geschreven en moeten, respectievelijk de volgende signatures bezitten:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any functie(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring functie(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta functie(any)</em></td> <td><strong>RECV:</strong> <em>any functie(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer functie(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring functie(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean functie(internal)</em></td> <tr> </table> The functions to be assigned to a range type should have the following signatures:<br/><br/><strong>Canonical:</strong> <em>any function(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision function(subtype, subtype)</em> De functies die aan een omvang worden toegewezen moeten de volgende signatures bezitten:<br/><br/><strong>Canonish:</strong> <em>any functie(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision functie(subtype, subtype)</em> UpdateNotifierWidget Update Notifier Update Aankondiging Hide this widget Verberg dit widget ... ... Released in: Releasedatum: mmm dd, yyyy mmm dd, yyyy Update found! New version: 0.0.0 0.0.0 Changelog Aanpassingen Redirects to purchase page. Leidt naar de aankooppagina. Get binary package Verkrijg een binair pakket Redirects to GitHub source repository. Leidt naar de broncode op GitHub. Get source code Verkrijg de broncode Failed to check updates Het ophalen van update informatie faalde The update notifier failed to check for new versions! Please, verify your internet connectivity and try again! Connection error returned: <em>%1</em> - <strong>%2</strong>. No updates found Geen nieuwe updates You are running the most recent pgModeler version! No update needed. Dit is de meest recente versie van pgModeler! The update notifier failed to check for new versions! A HTTP status code was returned: <strong>%1</strong> Het ophalen van nieuwe versie informatie faalde! De volgende HTTP status code werd gegenereerd: <strong>%1</strong> ViewWidget References Referenties Expression Alias: Expressiealias: Column: Kolom: Table: Tabel: Table Alias: Tabelalias: Used in: Gebruikt in: Column Kolom Expression Expressie Reference Type: Referentietype: View Definition Viewdefinitie Expression: Expressie: Column Alias: Kolomalias: The element will be used as part of the SELECT statement to retrieve columns or expressions that will compose the view's columns SELECT ... The element will be used as part of the WHERE clause in form of conditional expression WHERE ... The element is used in the FROM portion of the command in order to reference tables or construct JOIN statements FROM ... The element's expression is used exclusively as the view's definition The element will be appended to the very end of the view's definition. This is useful when using GROUP BY/HAVING statements End expression Triggers Triggers Rules Regels Indexes Indexen Table Expression Tabelexpressie Code Preview Codevoorbeeld Options Opties Tag: Tag: Mode: Modus: Ordinary Gewoon Recursi&ve &Materialized With no data Zonder data Col./Expr. Kol./Expr. Alias Alias Alias Col. Alias Kol. Flags: SF FW AW EX VD To reference all columns in a table (*) just do not fill the field <strong>Column</strong>, this is the same as write <em><strong>[schema].[table].*</strong></em> Name Naam Refer. Table Refer. Tabel Firing Afvuring Events Events Indexing Indexering Execution Uitvoering Event Event /* Could not generate the SQL code. Make sure all attributes are correctly filled! /* De SQL code kon niet worden gegenereerd. Kijk na of alle attributen correct zijn ingevuld! WelcomeWidget Form Venster New model Nieuw model Open model Open model Sample models Voorbeeldmodellen Recent models Recente modellen Last session Vorige sessie pgmodeler-0.9.2/lang/pt_BR.qm000066400000000000000000003107231360462764600160120ustar00rootroot00000000000000Z&$:%cOkON<{'t N+Oټ+[!11a4>-F . G<GEI@JMzWTTԩTTX\IYY]J_n>_Pj<{*$ |$Q~"^yyy+yLsyL%s֍֍8֍U@֍\֍i0֍kj֍֍֍֍֍T֍C֍֍֍֍֍$ ֍'4֍,֍B$֍CW֍C֍G9֍Pl֍r5tUz5t5tBcH5]H5hH5CH5H5)eH54H5N[H5[H5p "%&$%%>sB%&Q% gD|:e'eOweaenee eee#e e;eLeOeVoej"į \(Q ' jM y-Y"( !#[9An*˄*%+g"6vO9x;H5 |TZTTZTZoT*TiT\VvVLV] Wz]xXmz%X]DYb_YbYb)YbOoYu/YqZy%&Zy%a#Zy%Zj\\&t\ZEJeA k+5o-OoE-tl h^yau ϋy|EC]ᬱT/WM^MM9 <hGLp!aE$2)+ 28RmC^laQe)eYue[x{ydzQ|{y^&YŀyƠ?U7njqG`0)B. Q D >J%O2 WZ p*$7s4؎:eJ^ilJZ=QKXkyaVf>p`)hp`nxt3$ld*(d*e"d*id*XXXbKWE Gi2B%1w9!jw99w9ۍ6U6b6Q6t6 6>bR _njpßGsŻs8kŖ@ŖF**PX'a_В$ nPًo`ܟ0/1z[y%]'t3A|  6J C1(>"(>Y(>i(>(>X)h)hl3V?VmY5nZy+t1t1()jmW5AfR=ٴ;?FbZ^;#;Ì=Ǥ;^Z^^#<&-ΔΔΔXΔKw;y=}F `<% '!.&ѤC(!;zb*@N ` 5` f$lu{*W TW^N DtIbIIAIܲIߦIIIV<>"<>F<>V:<>F<>E<>S9<>m-\C:.Z*\3ɓZnUeЄЩ=bчѬF k Ґ,.GN!Go5W!Wڷ7#7RÒzN7|znjz?lzTųMųnvA,v݃АG\fАGMАGoPq bZz[0ztUYnr  QДk8ʔk,N]l,N$/3 ><2B~3H3H3H3HK8M9'!:ʔlI/@lUY Y Y Y :Y K<cg!ChlZ$hTOnLZ*p3^s(!{yH5_H5tH5v/z jP1&~1` 1E1O+,+!+V҅N{yO>W?qzE53BXQ-go 2+aƨEƨb&ƨG qR1D#ѵuO-ѵupIŵ:A1r n^_-(.9CQC)%Z>a_pؙ`Gt(~`*04gxwo/swob|!M!scZ%jAD mt˜U_>QȐ$Ȑ^0ȐldȐFȐɓ`ɓ>֣ے*=ے ے4C:(ȔEFN,S1,23`5jy:l,7;=;ĆCBb^G4cqj0Ow|Tw|"p +v8Dv8=ړNsVE` f` ` ƿ` t` U` \^$ e1cX 0y O ;Ya5 8 @9r;z-pO kJ vWh |~Q  vB + V g 0  krU jl ii  ʮ NJL> NJ,_ NJ0 NJT H V z _!C ht Z> j$@,  #N )`= *pa 6 # M(N MJq M T Z4 Ze _1}? ci* ci* cGY cYR cS cZG cZVu cZj4 cZSm cZm dE eU e( g im o^/ r3? x:  I! I.I I9 Iل I I Q 6Z 6=F )f :[ :d : y? >B >>? `K   D; 5` 5] q tY te t, t0 " Y  / T JX& Lu, Rz t~ tR| ɗ$ T .{ δM δƂ δ δ? v˶ vB ϩ8'c ϩ8 5 ꚅ I* N /*D $~ m V: ye@k dZS ;l3 O \\ hx*] m{ wG {. {SW {ҵ |%X |%W 9  2A~z W .s ݒ' ݒc p _ _ %  m [ M nE JP) (( M M.4 ; 4_I 4\ ͘1/ ͠ ͠/ є9 ѩ! س Zc Z> Z 掺] ( 鷠% J? J 5.  K[ ,<Z ,<j -V -7 5ӊt =h =8 @l{ Jk J# J\ J Jz OG[, OGZ OGZx XM"R X g&z6d uA ~L :mT :f ^s & b p hJf~ `Q G J { ک) nZ: u Vu ȩu u ɠ- ɠ)* JL J, J13 :#7 Ս. { M s9P M# h k( o ܊K DX  #1 Q5 , gA %4H ] zg Apr WU ! T .*Y @ 5 D+^-B DZ V v [*7 ] i8:$\ j L: ^C ^v ^ ^s 8A / %h <; <B% <X <2 <2 <Gz SXM Sc$ SF إ5! @! .;R]>" ?B ei = J98Jh JcJYm!<*m^'A)(3(L1Y2*5J[UFG3 KOL,NTCWGVdijgrw3sAx?3u"$[yPo'-! 3W| 3 3R R zY&=֊4Z*j_4-  Vt4i!q5d555YPs 4&;I9tn`~aN!"jM m}v> Hv=mUN&`fPY*> Fd F&+1ukyI/J]5* is"Sobre o pgModelerAbout pgModeler AboutWidgetLModelador de Banco de Dados PostgreSQLPostgreSQL Database Modeler AboutWidgetUma funo de agregao que aceita os tipos <em><strong>tipoA</strong></em> e <em><strong>tipoB</strong></em> como entrada e cujo tipo de estado seja <em><strong>tipo_estado</strong></em>, deve obedecer s seguintes regras:<br/><br/> <strong> &nbsp;&nbsp;&nbsp; " Funo Final:</strong> <em>void funcao_final(<strong>tipo_estado</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp; " Funo Transio:</strong> <em><strong>tipo_estado</strong> funcao_transicao(<strong>tipo_estado</strong>, <strong>tipoA</strong>, <strong>tipoB</strong>)</em>%An aggregate function that accepts the types typeA and typeB as input types and which type of state is state_type, must obey the following rules:

   • Final Function: void final_function(state_type)
   • Transition Function: state_type transition_function(state_type, typeA, typeB)AggregateWidgetFuno Final:Final Function:AggregateWidget Estado da FunoFunction StateAggregateWidget$Entradas da FunoFuntion InputsAggregateWidget"Condio Inicial:Initial Condition:AggregateWidget0Tipo de Dados de EntradaInput Data TypeAggregateWidget,Operador de Ordenao:Sort Operator:AggregateWidget,Tipo de Dado de EstadoState Data TypeAggregateWidget ptAppearanceConfigWidgetNegritoBoldAppearanceConfigWidget Cores:Colors:AppearanceConfigWidget6Coluna (fk): Nome da colunaColumn (fk): Column nameAppearanceConfigWidget,Coluna (fk): DescritorColumn (fk): DescriptorAppearanceConfigWidget6Coluna (nn): Nome da colunaColumn (nn): Column nameAppearanceConfigWidget,Coluna (nn): DescritorColumn (nn): DescriptorAppearanceConfigWidget6Coluna (pk): Nome da colunaColumn (pk): Column nameAppearanceConfigWidget,Coluna (pk): DescritorColumn (pk): DescriptorAppearanceConfigWidget6Coluna (uq): Nome da colunaColumn (uq): Column nameAppearanceConfigWidget,Coluna (uq): DescritorColumn (uq): DescriptorAppearanceConfigWidget,Coluna: Nome da colunaColumn: Column nameAppearanceConfigWidget"Coluna: DescritorColumn: DescriptorAppearanceConfigWidgetZColuna: Includa / Herdada por relacionamento,Column: Included / Inherited by relationshipAppearanceConfigWidget"Coluna: ProtegidaColumn: ProtectedAppearanceConfigWidgetElemento:Element:AppearanceConfigWidget Fonte:Font:AppearanceConfigWidgetFormulrioFormAppearanceConfigWidget>Global: Descritor de restriesGlobal: Constraints descriptorAppearanceConfigWidget.Global: Estilo de fonteGlobal: Font styleAppearanceConfigWidget.Global: Arco do cadeadoGlobal: Lock arcAppearanceConfigWidget0Global: Corpo do cadeadoGlobal: Lock bodyAppearanceConfigWidget4Global: Seleo de objetosGlobal: Object selectionAppearanceConfigWidget0Global: Tipo dos objetosGlobal: Objects typeAppearanceConfigWidgetNGlobal: Caixa do informativo de posioGlobal: Position hint boxAppearanceConfigWidgetNGlobal: Texto do informativo de posioGlobal: Position hint textAppearanceConfigWidget"ndice: DescritorIndex: DescriptorAppearanceConfigWidgetndice: Nome Index: NameAppearanceConfigWidgetItlicoItalicAppearanceConfigWidgetJRelacionamento: Descritor do atributo"Relationship: Attribute descriptorAppearanceConfigWidgetBRelacionamento: Texto do atributoRelationship: Attribute textAppearanceConfigWidget2Relacionamento: DescritorRelationship: DescriptorAppearanceConfigWidget>Relacionamento: Caixa do rtuloRelationship: Label boxAppearanceConfigWidget>Relacionamento: Texto do rtuloRelationship: Label textAppearanceConfigWidget Regra: DescritorRule: DescriptorAppearanceConfigWidgetRegra: Nome Rule: NameAppearanceConfigWidget2Tabela: Caixa das colunasTable: Columns boxAppearanceConfigWidgetLTabela: Caixa dos atributos extendidosTable: Extended attributes boxAppearanceConfigWidget.Tabela: Nome do esquemaTable: Schema nameAppearanceConfigWidget,Tabela: Nome da tabelaTable: Table nameAppearanceConfigWidget.Tabela: Caixa do ttuloTable: Title boxAppearanceConfigWidget*Caixa de Texto: Corpo Textbox: BodyAppearanceConfigWidget$Gatilho: DescritorTrigger: DescriptorAppearanceConfigWidgetGatilho: Nome Trigger: NameAppearanceConfigWidgetSublinhado UnderlineAppearanceConfigWidgetJViso: Caixa dos atributos extendidosView: Extended attributes boxAppearanceConfigWidget<Viso: Descritor da refernciaView: Reference descriptorAppearanceConfigWidget4Viso: Coluna referenciadaView: Referenced columnAppearanceConfigWidget4Viso: Tabela referenciadaView: Referenced tableAppearanceConfigWidget8Viso: Caixa das refernciasView: References boxAppearanceConfigWidget,Viso: Nome do esquemaView: Schema nameAppearanceConfigWidgetBViso: Apelido da tabela / colunaView: Table / columns aliasAppearanceConfigWidget,Viso: Caixa do ttuloView: Title boxAppearanceConfigWidget(Viso: Nome da visoView: View nameAppearanceConfigWidget>Exceo desconhecida capturada!Unknown exception caught! Application&Aplicar&ApplyBaseForm&Cancelar&CancelBaseForm&OkBaseFormDilogoDialogBaseFormAgregao Aggregate BaseObject MoldeCast BaseObjectIntercalao Collation BaseObject ColunaColumn BaseObjectRestrio Constraint BaseObjectConverso Conversion BaseObjectBanco de DadosDatabase BaseObjectDomnioDomain BaseObject FunoFunction BaseObject ndiceIndex BaseObjectLinguagemLanguage BaseObjectOperadorOperator BaseObject(Classe de OperadoresOperator Class BaseObject*Famlia de OperadoresOperator Family BaseObjectParmetro Parameter BaseObjectPermisso Permission BaseObjectRelacionamento Relationship BaseObject PapelRole BaseObject RegraRule BaseObjectEsquemaSchema BaseObjectSequnciaSequence BaseObject TabelaTable BaseObject Espao de Tabela Tablespace BaseObjectCaixa de TextoTextbox BaseObjectGatilhoTrigger BaseObjectTipoType BaseObject Atributo de TipoType Attribute BaseObject VisoView BaseObjectnovo_objetonovos_objetos new_object BaseObjectIntercalao: Collation:BaseObjectWidgetComentrio:Comment:BaseObjectWidget,Desabilitar cdigo SQLDisable SQL codeBaseObjectWidget6Editar permisses do objetoEdit object's permissionsBaseObjectWidget"Editar permissesEdit permissionsBaseObjectWidget Nome:Name:BaseObjectWidgetProprietrio:Owner:BaseObjectWidgetbCampo requerido. Deix-lo em branco gerar erros!5Required field. Leaving this empty will raise errors!BaseObjectWidgetEsquema:Schema:BaseObjectWidgetEsp. de Tabela: Tablespace:BaseObjectWidgetEste objeto est protegido, assim nenhuma alterao no formulrio ser aplicada ao mesmo.FThis object is protected thus no change in form will be applied to it.BaseObjectWidgetValor(es)Value(s)BaseObjectWidget VersoVersionBaseObjectWidget coneiconeBaseObjectWidget rel_%1_%2BaseRelationship&Cancelar&Cancel BugReportForm CriarCreate BugReportFormtModelo de banco de dados (*.dbm);; Todos os arquivos (*.*)'Database model (*.dbm);;All files (*.*) BugReportFormCarregar modelo Load model BugReportFormRelatrioReport BugReportFormAtribuio Assignment CastWidgetMolde de Tipo: Cast Type: CastWidget Funo de Conv.:Conversion Func.: CastWidgetEntrada / SadaInput / Output CastWidget Tipo dado origemSource data type CastWidget"Tipo dado destinoTarget data type CastWidgetA funo a ser atribuda uma moldagem do <em><strong>tipoA</strong></em> para o <em><strong>tipoB</strong></em> deve possuir a seguinte assinatura: <em><strong>tipoB</strong> funcao(<strong>tipoA</strong>, integer, boolean)</em>.The function to be assigned to a cast from typeA to typeB must have the following signature: typeB function(typeA, integer, boolean). CastWidgetCodificao: Encoding:CollationWidget LC_COLLATE:CollationWidget LC_CTYPE:CollationWidgetLocalidade:Locale:CollationWidgetNo definido Not definedCollationWidgetOs campos <strong><em>Intercalao</em></strong>, <strong><em>Localidade</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> so mutuamente exclusivos, ento voc tem que definir apenas um deles a fim de manipular corretamente a intercalao.The fields Collation, Locale, LC_COLLATE & LC_CTYPE are mutually exclusive, so you have to set only one of them in order to properly handle a collation.CollationWidgetFormulrioFormColorPickerWidgetValor Padro:Default Value: ColumnWidget&Aplicar&ApplyConfigurationForm&Cancelar&CancelConfigurationFormQualquer modificao feita at agora na seo atual ser perdida! Deseja realmente restaurar as configuraes padro?tAny modification made until now in the current section will be lost! Do you really want to restore default settings?ConfigurationFormPadresDefaultsConfigurationForm GeralGeneralConfigurationFormPluginsPlug-insConfigurationForm2Configurao do pgModelerpgModeler ConfigurationConfigurationForm"Verificao de ACAC verificationConnectionsConfigWidgetAdicionarAddConnectionsConfigWidgetPermitirAllowConnectionsConfigWidgetCancelar edioCancel editionConnectionsConfigWidget(Certificado Cliente:Client Certificate:ConnectionsConfigWidgetChave Cliente: Client Key:ConnectionsConfigWidget&Apelido da Conexo:Connection Alias:ConnectionsConfigWidgetBD Conexo:Connection DB:ConnectionsConfigWidgetConexes: Connections:ConnectionsConfigWidget$Criar nova conexoCreate new connectionConnectionsConfigWidget4Apagar conexo selecionadaDelete selected connectionConnectionsConfigWidgetDesabilitarDisableConnectionsConfigWidget4Editar conexo selecionadaEdit selected connectionConnectionsConfigWidgetExportarExportConnectionsConfigWidgetForar GSSAPI Force GSSAPIConnectionsConfigWidget(Verificao CompletaFull verificationConnectionsConfigWidget GeralGeneralConnectionsConfigWidgetServidor/Porta: Host/Port:ConnectionsConfigWidget Senha: Password:ConnectionsConfigWidgetRequerirRequireConnectionsConfigWidget Cert. Revogados:Revoked Certs.:ConnectionsConfigWidget"Certificado Raiz:Root Certificate:ConnectionsConfigWidgetModo SSL: SSL Mode:ConnectionsConfigWidgetSucessoSuccessConnectionsConfigWidget TestarTestConnectionsConfigWidgetTempo limite:Timeout:ConnectionsConfigWidgetAtualizarUpdateConnectionsConfigWidgetUsurio:User:ConnectionsConfigWidgetsegundo(s) second(s)ConnectionsConfigWidget~/.postgresql/postgresql.crtConnectionsConfigWidget~/.postgresql/postgresql.keyConnectionsConfigWidget~/.postgresql/root.crlConnectionsConfigWidget~/.postgresql/root.crtConnectionsConfigWidget ColunaColumnConstraintWidgetColuna:Column:ConstraintWidgetColunasColumnsConstraintWidgetColunas que foram includas por relacionamento no podem ser adicionadas / removidas manualmente da chave primria. Se tais alteraes forem feitas elas podem gerar erros. Para criar chaves primrias usando colunas includas por relacionamentos use as seguintes opes: campo identificador, aba atributos & restries ou aba chave primria no formulrio de relacionamento.EColumns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form.ConstraintWidget$Tipo de Restrio:Constraint Type:ConstraintWidgetPostergvel: Deferrable:ConstraintWidgetPostergao: Deferral:ConstraintWidget"Excluir ElementosExclude ElementsConstraintWidgetExpresso: Expression:ConstraintWidgetFator Preenc.: Fill Factor:ConstraintWidgetIndexao: Indexing:ConstraintWidgetConfrontar:Match:ConstraintWidgetSem herana: No inherit:ConstraintWidget ON DELETE:ConstraintWidget ON UPDATE:ConstraintWidget*Colunas ReferenciadasReferenced ColumnsConstraintWidgetTabela:Table:ConstraintWidgetTipoTypeConstraintWidget Funo de Conv.:Conversion Func.:ConversionWidget"Converso Padro:Default Conversion:ConversionWidget&Codificao Origem:Source Encoding:ConversionWidget(Codificao Destino:Target Encoding:ConversionWidgetA funo a ser atribuda a uma converso de codificao deve possuir a seguinte assinatura: <em>void funcao(integer, integer, cstring, internal, integer)</em>.The function to be assigned to an encoding conversion must have the following signature: void function(integer, integer, cstring, internal, integer).ConversionWidgettModelo de banco de dados (*.dbm);; Todos os arquivos (*.*)'Database model (*.dbm);;All files (*.*)CrashHandlerFormDOopa! O pgModeler acaba de travar!Oops! pgModeler just crashed!CrashHandlerFormSalvar modelo Save modelCrashHandlerForm*Rastreamento de pilha Stack traceCrashHandlerFormFormulrioForm CsvLoadWidgetCarregarLoad CsvLoadWidget&Fechar&CloseDataManipulationFormAdicionar ItemAdd ItemDataManipulationForm ColunaColumnDataManipulationFormColuna:Column:DataManipulationFormRemover Item Remove ItemDataManipulationFormEsquema:Schema:DataManipulationFormTabela:Table:DataManipulationFormArgumentos ArgumentsDatabaseExplorerWidgetAtributo AttributeDatabaseExplorerWidgetPor valorBy valueDatabaseExplorerWidget.Recolher todos os itensCollapses all itemsDatabaseExplorerWidgetIntercalvel CollatableDatabaseExplorerWidgetIntercalao CollationDatabaseExplorerWidgetColunasColumnsDatabaseExplorerWidgetRestrio ConstraintDatabaseExplorerWidget PadroDefaultDatabaseExplorerWidgetDefinio DefinitionDatabaseExplorerWidgetDimenso DimensionDatabaseExplorerWidgetElementoElementDatabaseExplorerWidgetEncriptado EncryptedDatabaseExplorerWidgetEnumeraes EnumerationsDatabaseExplorerWidget EventoEventDatabaseExplorerWidget.Expandir todos os itensExpands all itemsDatabaseExplorerWidgetExpresso ExpressionDatabaseExplorerWidgetDisparoFiringDatabaseExplorerWidgetFormulrioFormDatabaseExplorerWidget FunoFunctionDatabaseExplorerWidgetLinguagemLanguageDatabaseExplorerWidgetComprimentoLengthDatabaseExplorerWidgetBibliotecaLibraryDatabaseExplorerWidgetNomeNameDatabaseExplorerWidgetOperadorOperatorDatabaseExplorerWidgetOperadores OperatorsDatabaseExplorerWidgetPermisses PermissionsDatabaseExplorerWidgetPreciso PrecisionDatabaseExplorerWidgetPreferido PreferredDatabaseExplorerWidgetRenomearRenameDatabaseExplorerWidget PapisRolesDatabaseExplorerWidgetEsquemaSchemaDatabaseExplorerWidgetArmazenamentoStorageDatabaseExplorerWidgetSubtipoSubtypeDatabaseExplorerWidgetSuperusurio SuperuserDatabaseExplorerWidget TabelaTableDatabaseExplorerWidget Espao de Tabela TablespaceDatabaseExplorerWidgetTipoTypeDatabaseExplorerWidget nicoUniqueDatabaseExplorerWidgetAtualizarUpdateDatabaseExplorerWidgetValidadeValidityDatabaseExplorerWidget&Fechar&CloseDatabaseImportFormCancelarCancelDatabaseImportForm.Recolher todos os itensCollapses all itemsDatabaseImportFormConexo: Connection:DatabaseImportFormBanco de DadosDatabaseDatabaseImportForm.Expandir todos os itensExpands all itemsDatabaseImportForm,Rtulo de progresso...Progress label...DatabaseImportFormAtributos AttributesDatabaseWidgetIntercalao: Collation:DatabaseWidgetConexes: Connections:DatabaseWidget PadroDefaultDatabaseWidgetCodificao: Encoding:DatabaseWidget LC_COLLATE:DatabaseWidget LC_CTYPE:DatabaseWidget Autor do Modelo: Model Author:DatabaseWidgetOpes:Options:DatabaseWidgetEsquema:Schema:DatabaseWidgetEsp. de Tabela: Tablespace:DatabaseWidgetDB Modelo: Template DB:DatabaseWidgetAtributos Attributes DomainWidgetValor Padro:Default Value: DomainWidgetExpresso Expression DomainWidgetExpresso: Expression: DomainWidgetNomeName DomainWidget Nome:Name: DomainWidgetFormulrioForm DonateWidgetAscendente AscendingElementsWidgetIntercalao CollationElementsWidgetIntercalao: Collation:ElementsWidgetColuna:Column:ElementsWidgetDescendente DescendingElementsWidgetElementoElementElementsWidgetExpresso ExpressionElementsWidgetExpresso: Expression:ElementsWidgetFormulrioFormElementsWidgetNoNoElementsWidgetNulos Primeiro Nulls FirstElementsWidgetNulos primeiro Nulls firstElementsWidgetOperadorOperatorElementsWidget(Classe de OperadoresOperator ClassElementsWidget*Classe de Operadores:Operator Class:ElementsWidgetOperador: Operator:ElementsWidgetOrdenaoSortingElementsWidgetOrdenao: Sorting:ElementsWidgetTipoTypeElementsWidgetSimYesElementsWidgetEvento:Event:EventTriggerWidgetFuno: Function:EventTriggerWidgetUma chave estrangeira no pode ser adicionado a um relacionamento pois esta criada automaticamente no momento da ligao do mesmo!iA foreign key can not be added to a relationship because is created automatically when this is connected! ExceptionJAlocao de objeto com tipo invlido!'Allocation of object with invalid type! ExceptionXAtribuio de funo com linguagem invlida!3Assignment of a function which language is invalid! ExceptionAtribuio de valor mnimo da seqncia maior do que o valor mximo!VAssignment of a minimum value to the sequence which is greater than the maximum value! ExceptionjAtribuio de incremento de seqncia com valor nulo!5Assignment of a null increment value to the sequence! ExceptiontAtribuio de preciso maior do que o comprimento do tipo!>Assignment of a precision greater than the length of the type! Exception~Atribuio de chave primria uma tabela a qual j possui uma!=Assignment of a primary key to a table which already has one! Exception^Atribuio de um pseudo-tipo ao tipo da coluna!6Assignment of a pseudo-type to the type of the column! ExceptionAtribuio de esquema seqncia o qual difere do esquema da tabela possuidora!XAssignment of a schema to the sequence which differs from the schema of the owner table! ExceptionnAtribuio de valor a um parmetro de conexo invlido!9Assignment of a value to an invalid connection parameter! ExceptionVAtribuio de expresso invlida ao objeto!2Assignment of an invalid expression to the object! ExceptionAtribuio de preciso invlida a um tipo time, timestamp ou interval. A preciso neste caso deve ser igual ou inferior a 6!Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! ExceptionAtribuio de valor invlido ao nmero de estratgia/suporte do elemento de classe de operadores!NAssignment of an invalid strategy/support number to an operator class element! ExceptionzAtribuio de valor invlido a um dos atributos da seqncia!AAssignment of an invalid value to one of the sequence attributes! ExceptiontAtribuio de um objeto o qual j pertence a outra tabela!>Assignment of an object that already belongs to another table! ExceptionPAtribuio de nome de arquivo DTD vazio!"Assignment of empty DTD file name! ExceptionfAtribuio de buffer de cdigo XML vazio ao parser!)Assignment of empty XML buffer to parser! ExceptionJAtribuio de nome vazio a um objeto!&Assignment of empty name to an object! ExceptionlAtribuio de nome vazio ao tipo de retorno de tabela!.Assignment of empty name to table return type! ExceptionTAtribuio de nome vazio declarao DTD!0Assignment of empty name to the DTD declaration! ExceptionXAtribuio de configurao invlida ao tipo!0Assignment of invalid configuration to the type! ExceptionvAtribuio de tamanho mximo invlido lista de operaes!5Assignment of invalid maximum size to operation list! ExceptionAtribuio de nome invlido tabela gerada por relacionamento N-N!HAssignment of invalid name to the table generated from N-N relationship! ExceptionRAtribuio de um tipo invlido ao objeto!)Assignment of invalid type to the object! ExceptionTAtribuio de linguagem com tipo invlido!4Assignment of language object which type is invalid! ExceptionfAtribuio de resultado de comando SQL no alocado!/Assignment of not allocated SQL command result! ExceptionHAtribuio de linguagem no alocada!%Assignment of not allocated language! ExceptionHAtribuio de um objeto no alocado!#Assignment of not allocated object! Exception`Atribuio de cache de seqncia com valor nulo!/Assignment of null cache value to the sequence! Exception`Atribuio de um objeto papel com tipo invlido!1Assignment of owner object which type is invalid! ExceptionfAtribuio de um dono a um objeto de tipo invlido!)Assignment of owner to an invalid object! ExceptionAtribuio de privilgio incompatvel com o tipo do objeto referenciado pela permisso!VAssignment of privilege incompatible with the type of object referenced by permission! ExceptiondAtribuio de um objeto esquema com tipo invlido!2Assignment of schema object which type is invalid! ExceptionpAtribuio de objeto espao de tabela com tipo invlido!2Assignment of tablespace object with invalid type! ExceptionLAtribuio de um objeto espao de tabela a uma restrio de tipo invlido! A restrio deve ser uma chave-primria ou nica para pode pertencer a um espao de tabela!Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique! Exception~Atribuio de um espao de tabela a um objeto de tipo invlido!.Assignment of tablespace to an invalid object! Exception|Tentativa de conexo sem parmetros de configurao definidos!;Attempt to connect without define configuration parameters! ExceptionRestries do tipo chave-primria, chave-estrangeira ou nica devem possuir pelo menos uma coluna relacionada s mesmas! Para chaves-estrangeira devem ser selecionadas, adicionalmente, as colunas referenciadas!Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns! ExceptionpInsero de elemento j existente na lista de elementos!>Insertion of element which already exists in the element list! ExceptionnInsero de item invlido na lista de atibutos do tipo!=Insertion of invalid item in the attributes list of the type! ExceptiontInsero de item invlido na lista de emumeraes do tipo!?Insertion of invalid item in the enumerations list of the type! ExceptionvInsero de item j existente na lista de atibutos do tipo!JInsertion of item which already exists in the attributes list of the type! Exception|Insero de item j existente na lista de enumeraes do tipo!LInsertion of item which already exists in the enumarations list of the type! ExceptionNo possvel criar arrays de domnios ou sequncias (dimenso >= 1)! O PostgreSQL ainda no implementa esta funcionalidade!}It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! ExceptionPObteno de um objeto com tipo invlido!'Obtaining an object of an invalid type! ExceptionTObteno de tipos com quantidade invlida!&Obtaining types with invalid quantity! ExceptionUm ou mais objetos foram invalidados e automaticamente removidos pois os mesmos referenciavam colunas de tabelas as quais foram includas atravs de relacionamentos e que deixaram de existir devido a desconexo ou excluso dos relacionamentos geradores de tais colunas!One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! ExceptionUm ou mais plugins no foram ativados devido a erros no processo de carregamento! Verifique a pilha de excees para mais detalhes.|One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. ExceptionPOperao sobre conexo no estabelecida!(Operation on connection not established! ExceptionOperao sobre rvore de elementos no alocada! necessrio carregar o buffer XML do parser e interpret-lo para que a rvore seja gerada!Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! ExceptionOperao com elemento o qual no faz parte da rvore de elementos carregada atualmente!ROperation with element which does not exists in the element tree currently loaded! Exception@Operao com objeto no alocado!$Operation with object not allocated! Exception\Operao com objeto(s) de tipo(s) invlido(s)!2Operation with object(s) which type(s) is invalid! ExceptionrOperao com elemento de rvore de elementos no alocado!(Operation with unallocated tree element! ExceptionjReferncia uma coluna da tupla com ndice invlido!2Reference to a column of tuple with invalid index! ExceptionfReferncia uma coluna da tupla com nome invlido!1Reference to a column of tuple with invalid name! ExceptionReferncia a uma coluna com ndice fora da capacidade da lista de colunas!LReference to a column which index is out of the capacity of the column list! ExceptionTReferncia a uma funo com tipo invlido!*Reference to a function with invalid type! ExceptionpReferncia a um argumento do operador com tipo invlido!;Reference to an argument of the operator with invalid type! ExceptionbReferncia a um evento no pertecente ao gatilho!8Reference to an event which does not belongs to trigger! ExceptionXReferncia a um tipo de privilgio invlido!'Reference to an invalid privilege type! ExceptionNReferncia a um tipo de papel invlido!"Reference to an invalid role type! ExceptionVReferncia a um operador com tipo invlido!+Reference to an operator with invalid type! ExceptionReferncia a tipo de dado definido pelo usurio o qual no existe no modelo!DReference to an user-defined data type that not exists in the model! ExceptionReferncia a tipo de dado com ndice fora da capacidade da lista de tipos de dados!MReference to data type with an index outside the capacity of data types list! ExceptionRReferncia a um objeto com tipo invlido!&Reference to object with invalid type! Exception<Remoo de objeto no alocado!#Removal of an object not allocated! ExceptionFRemoo de objeto de tipo invlido!&Removing an object of an invalid type! ExceptionO processo de exportao falhou devido a um erro disparado pelo servidor PostgreSQL na tentativa de execuo de um comando SQL. Para obter mais detalhes sobre erro cheque a pilha de excees! ** Comando SQL executado: ** %1The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 ExceptionpO relacionamento do tipo 1-1 onde ambas as tabelas so de participao obrigatria no implementado por necessitar de fuso entre tabelas o que quebra a modelagem feita pelo usurio!The relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user! ExceptionNo foi possvel alocar o resultado do comando SQL pois a resposta do SGBD no foi compreendida pelo cliente!uUnable to allocate the result of the SQL command because the response from the DBMS was not understood by the client! ExceptionVerso:Version:ExtensionWidgetFormulrioFormFindReplaceWidgetAtributos AttributesFunctionWidgetComportamento: Behavior:FunctionWidget ColunaColumnFunctionWidgetValor Padro Default ValueFunctionWidgetDefinio DefinitionFunctionWidget(Biblioteca Dinmica:Dynamic Library:FunctionWidget$Custo de Execuo:Execution Cost:FunctionWidgetTipo de Funo:Function Type:FunctionWidgetBiblioteca:Library:FunctionWidgetNomeNameFunctionWidgetParmetros ParametersFunctionWidget$Mtodo de Retorno:Return Method:FunctionWidget"Tabela de Retorno Return TableFunctionWidget$Linhas Retornadas:Rows Returned:FunctionWidgetSegurana: Security:FunctionWidgetConjuntoSetFunctionWidgetCdigo fonte: Source code:FunctionWidgetSmbolo:Symbol:FunctionWidgetTipoTypeFunctionWidgetA0 (841 x 1189 mm)GeneralConfigWidgetA1 (594 x 841 mm)GeneralConfigWidgetA2 (420 x 594 mm)GeneralConfigWidgetA3 (297 x 420 mm)GeneralConfigWidgetA4 (210 x 297 mm)GeneralConfigWidgetA5 (148 x 210 mm)GeneralConfigWidgetA6 (105 x 148 mm)GeneralConfigWidgetA7 (74 x 105 mm)GeneralConfigWidgetA8 (52 x 74 mm)GeneralConfigWidgetA9 (37 x 52 mm)GeneralConfigWidgetB0 (1030 x 1456 mm)GeneralConfigWidgetB1 (728 x 1030 mm)GeneralConfigWidgetB10 (32 x 45 mm)GeneralConfigWidgetB2 (515 x 728 mm)GeneralConfigWidgetB3 (364 x 515 mm)GeneralConfigWidgetB4 (257 x 364 mm)GeneralConfigWidgetB5 (182 x 257 mm)GeneralConfigWidgetB6 (128 x 182 mm)GeneralConfigWidgetB7 (91 x 128 mm)GeneralConfigWidgetB8 (64 x 91 mm)GeneralConfigWidgetB9 (45 x 64 mm)GeneralConfigWidgetMargem base Bottom marginGeneralConfigWidget Base:Bottom:GeneralConfigWidgetC5E (163 x 229 mm)GeneralConfigWidgetCentmetro CentimeterGeneralConfigWidget Cores:Colors:GeneralConfigWidgetComm10E (105 x 241 mm)GeneralConfigWidgetDLE (110 x 220 mm)GeneralConfigWidget0Executivo (191 x 254 mm)Executive (191 x 254 mm)GeneralConfigWidgetFolio (210 x 330 mm)GeneralConfigWidget Fonte:Font:GeneralConfigWidgetFormulrioFormGeneralConfigWidget GeralGeneralGeneralConfigWidgetPolegadasInchesGeneralConfigWidgetPaisagem LandscapeGeneralConfigWidgetLedger (432 x 279 mm)GeneralConfigWidgetMargem esquerda Left marginGeneralConfigWidget Esq.:Left:GeneralConfigWidgetLegal (216 x 356 mm)GeneralConfigWidget(Carta (216 x 279 mm)Letter (216 x 279 mm)GeneralConfigWidgetMilmetros MilimetersGeneralConfigWidget:Abrir gerenciador de arquivosOpen in file managerGeneralConfigWidget.Histrico de operaes:Operation history:GeneralConfigWidgetOpes:Options:GeneralConfigWidgetOrientao: Orientation:GeneralConfigWidget Papel:Paper:GeneralConfigWidget PxeisPixelsGeneralConfigWidgetRetratoPortraitGeneralConfigWidgetImprimir grade Print gridGeneralConfigWidget4Imprimir nmero de pginasPrint page numbersGeneralConfigWidgetMargem direita Right marginGeneralConfigWidget Dir.:Right:GeneralConfigWidget.Tablide (279 x 432 mm)Tabloid (279 x 432 mm)GeneralConfigWidgetMargem topo Top marginGeneralConfigWidget Topo:Top:GeneralConfigWidgetFormulrioFormHintTextWidgetAtributos Attributes IndexWidgetConcorrente Concurrent IndexWidgetElementosElements IndexWidgetAtual. Rpida Fast update IndexWidgetFator Preenc.: Fill Factor: IndexWidgetIndexao: Indexing: IndexWidgetOpes:Options: IndexWidget nicoUnique IndexWidgetAs funes a serem atribudas linguagem devem possuir, respectivamente, as seguintes assinaturas:<br/><br/> <strong>Funo Manipuladora:</strong> <em>language_handler funcao()</em><br/> <strong>Funo Validadora:</strong> <em>void funcao(oid)</em><br/> <strong>Funo em Linha:</strong> <em>void funcao(internal)</em>DThe functions to be assigned to the language should have, respectively, the following signatures:

Handler Function: language_handler function()
Validator Function: void function(oid)
Inline Function: void function(internal)LanguageWidgetConfivel:Trusted:LanguageWidget&Fechar&Close MainWindow&Editar&Edit MainWindow&Exportar&Export MainWindow&Arquivo&File MainWindow&Mostrar&Show MainWindow.Alinhar objetos gradeAlign objects position to grid MainWindowCancelarCancel MainWindow6Foram detectadas modificaes nas definies de papel/margem do modelo que podem provocar a impresso incorreta dos objetos. Deseja prosseguir com a impresso usando as novas configuraes? Para usar as configuraes padro clique em 'No', ou em 'Cancelar' para abortar a impresso.Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. MainWindowConfirmao Confirmation MainWindowCtrl+- MainWindowCtrl+0 MainWindowCtrl+= MainWindowCtrl+G MainWindowCtrl+H MainWindowCtrl+L MainWindowCtrl+N MainWindowCtrl+O MainWindowCtrl+P MainWindowCtrl+Q MainWindowCtrl+S MainWindow Ctrl+Shift+S MainWindowCtrl+W MainWindowCtrl+Y MainWindowCtrl+Z MainWindowtModelo de banco de dados (*.dbm);; Todos os arquivos (*.*)'Database model (*.dbm);;All files (*.*) MainWindowJImpresso do modelo de banco de dadosDatabase model printing MainWindowF1 MainWindowF10 MainWindow GeralGeneral MainWindowCarregar modelo Load model MainWindowNovoNew MainWindowNovo objeto New object MainWindowPlugins MainWindow&Salvar '%1' como...Save '%1' as... MainWindowSalvar todosSave all MainWindowSalvar modelo Save model MainWindowMostrar grade Show grid MainWindow<Mostra a viso geral do modeloShow the model overview MainWindowDMostrar os delimitadores da pginaShow the page delimiters MainWindowEsta ao abrir uma janela do navegador de internet! Deseja prosseguir?Edita as propriedades do objetoEdit the object properties ModelWidgetFCarregando modelo de banco de dadosLoading database model ModelWidget(Mover para o esquemaMove to schema ModelWidgetNovoNew ModelWidget Nem todos objetos foram colados ao modelo devido a erros retornados durante o processo! Consulte a pilha de erros para mais detalhes!zNot all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! ModelWidget ColarPaste ModelWidget$Colando objetos...Pasting objects... ModelWidgetPropriedades Properties ModelWidgetProtegerProtect ModelWidgetJProtege objeto(s) contra modificaes%Protects object(s) from modifications ModelWidget:Renomear rapidamente o objetoQuick rename the object ModelWidgetRenomearRename ModelWidgetBSalvando modelo de banco de dadosSaving database model ModelWidgetSelecionarSelect ModelWidget Selecionar todos Select all ModelWidget"Selecionar filhosSelect children ModelWidgetZSeleciona todos os objetos grficos no modelo.Selects all the graphical objects in the model ModelWidget ExibirShow ModelWidget>Mostra o cdigo fonte do objetoShow object source code ModelWidgetCdigo fonte Source code ModelWidgetTabelasTables ModelWidgetDesproteger Unprotect ModelWidgetIntercalao CollationNewObjectOverlayWidget ColunaColumnNewObjectOverlayWidgetRestrio ConstraintNewObjectOverlayWidget CopiarCopyNewObjectOverlayWidgetDomnioDomainNewObjectOverlayWidgetFormulrioFormNewObjectOverlayWidget FunoFunctionNewObjectOverlayWidget ndiceIndexNewObjectOverlayWidgetLinguagemLanguageNewObjectOverlayWidgetOperadorOperatorNewObjectOverlayWidgetPermisses PermissionsNewObjectOverlayWidget PapelRoleNewObjectOverlayWidget RegraRuleNewObjectOverlayWidgetEsquemaSchemaNewObjectOverlayWidget TabelaTableNewObjectOverlayWidget Espao de Tabela TablespaceNewObjectOverlayWidgetCaixa de TextoTextboxNewObjectOverlayWidgetGatilhoTriggerNewObjectOverlayWidgetTipoTypeNewObjectOverlayWidget EditarEditNumberedTextEditorCarregarLoadNumberedTextEditorDependncias DependenciesObjectDepsRefsWidget ObjetoObjectObjectDepsRefsWidgetObjeto Pai Parent ObjectObjectDepsRefsWidgetTipo Pai Parent TypeObjectDepsRefsWidgetReferncias ReferencesObjectDepsRefsWidgetTipoTypeObjectDepsRefsWidgetFormulrioFormObjectFinderWidget ObjetoObjectObjectFinderWidgetObjeto Pai Parent ObjectObjectFinderWidgetTipo Pai Parent TypeObjectFinderWidgetSelecionarSelectObjectFinderWidgetTipoTypeObjectFinderWidgetCancelarCancelObjectRenameWidgetFormulrioFormObjectRenameWidgetRenomearRenameObjectRenameWidget para:to:ObjectRenameWidgetLimpar campo Clear fieldObjectSelectorWidgetFormulrioFormObjectSelectorWidget"Selecionar Objeto Select ObjectObjectSelectorWidgetAdicionar ItemAdd ItemObjectsTableWidgetConfirmao ConfirmationObjectsTableWidgetEditar Item Edit ItemObjectsTableWidgetFormulrioFormObjectsTableWidget Mover para baixo Move DownObjectsTableWidgetMover para cimaMove UpObjectsTableWidget&Mover para o incio Move to startObjectsTableWidgetRemover Item Remove ItemObjectsTableWidgetAtualizar Item Update ItemObjectsTableWidget0OperationListWidget1OperationListWidget:Apagar histrico de operaesDelete operation historyOperationListWidgetApagar o histrico de operaes executadas uma ao irreversvel, deseja realmente prosseguir?ZDelete the executed operations history is an irreversible action, do you want to continue?OperationListWidget(Operaes ExecutadasExecuted OperationsOperationListWidgetNome: %1Name: %1OperationListWidgetObjeto: %1 Object: %1OperationListWidgetDExcluso de histrico de operaesOperation history exclusionOperationListWidgetOperao: %1 Operation: %1OperationListWidgetOperaes: Operations:OperationListWidgetPosio: Position:OperationListWidgetRefazerRedoOperationListWidgetDesfazerUndoOperationListWidget criadocreatedOperationListWidgetmodificadomodifiedOperationListWidget movidomovedOperationListWidgetremovidoremovedOperationListWidgetClasse Padro:Default Class:OperatorClassWidget"Tipo de Elemento: Element Type:OperatorClassWidgetElementosElementsOperatorClassWidget FunoFunctionOperatorClassWidgetFuno: Function:OperatorClassWidgetIndexao: Indexing:OperatorClassWidget ObjetoObjectOperatorClassWidgetFamlia de Op.: Op. Family:OperatorClassWidgetOperadorOperatorOperatorClassWidget*Famlia de OperadoresOperator FamilyOperatorClassWidgetOperador: Operator:OperatorClassWidgetArmazenamentoStorageOperatorClassWidget*Tipo de Armazenamento Storage TypeOperatorClassWidget$Suporte/EstratgiaSupport/StrategyOperatorClassWidget&Suporte/Estratgia:Support/Strategy:OperatorClassWidgetTipoTypeOperatorClassWidgetIndexao: Indexing:OperatorFamilyWidgetAvanadoAdvancedOperatorWidgetArgumentos ArgumentsOperatorWidgetHASHESOperatorWidgetJuno:Join:OperatorWidget.Tipo Argumento EsquerdaLeft Argument TypeOperatorWidgetMERGESOperatorWidgetNegador:Negator:OperatorWidgetFun. Operador:Operator Func.:OperatorWidgetOpes:Options:OperatorWidgetRestrito: Restrict:OperatorWidget,Tipo Argumento DireitaRight Argument TypeOperatorWidgetPara criar um operador unrio necessrio especificar como <strong><em>'any'</em></strong> um de seus argumentos. Adicionalmente, a funo que define o operador deve possuir apenas um parmetro e este, por sua vez, deve ter o tipo de dado igual ao tipo de dado do argumento do operador unrio.To create a unary operator it is necessary to specify as 'any' one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator.OperatorWidgetValor Padro:Default Value:ParameterWidgetINParameterWidget Modo:Mode:ParameterWidgetOUTParameterWidget&Adicionar PermissoAdd PermissionPermissionWidget"Cancelar OperaoCancel OperationPermissionWidgetCascataCascadePermissionWidget$Previso de Cdigo Code PreviewPermissionWidget,Desabilitar cdigo SQLDisable SQL codePermissionWidget"Editar permissesEdit permissionsPermissionWidget GRANT OPTIONPermissionWidgetID:PermissionWidgetIdPermissionWidgetNomeNamePermissionWidgetPermisses PermissionsPermissionWidgetPrivilgio PrivilegePermissionWidgetPrivilgios PrivilegesPermissionWidget PapisRolesPermissionWidget&Atualizar PermissoUpdate PermissionPermissionWidget<interface da linha de comando. command line interface. PgModelerCLI6Opes da exportao SGBD: DBMS export options:  PgModelerCLIBInformao de conexo incompleta!"Incomplete connection information! PgModelerCLIdArquivo de entrada deve ser diferente do de sada!)Input file must be different from output! PgModelerCLI<Opo '%1' no aceita valores.#Option '%1' does not accept values. PgModelerCLIBIniciando exportao de modelo...Starting model export... PgModelerCLI6Opo '%1' no reconehcida.Unrecognized option '%1'. PgModelerCLI6Uso: pgmodeler-cli [OPES]Usage: pgmodeler-cli [OPTIONS] PgModelerCLIPValor no specificado para a opo '%1'.$Value not specified for option '%1'. PgModelerCLIAutor: %1 Author: %1PgModelerPlugin(Informao do PluginPlugin InformationPgModelerPluginVerso: %1 Version: %1PgModelerPluginTipo de Dado Data TypePgSQLTypeWidgetDimenso DimensionPgSQLTypeWidgetFormulrioFormPgSQLTypeWidgetFormato:Format:PgSQLTypeWidgetIntervalo: Interval:PgSQLTypeWidgetL:PgSQLTypeWidgetComprimentoLengthPgSQLTypeWidgetMPgSQLTypeWidgetP:PgSQLTypeWidgetPreciso PrecisionPgSQLTypeWidgetSRID:PgSQLTypeWidgetEspacial:Spatial:PgSQLTypeWidgetFuso horrio: Timezone:PgSQLTypeWidget Tipo:Type:PgSQLTypeWidgetVariao: Variation:PgSQLTypeWidgetZPgSQLTypeWidget[ ]:PgSQLTypeWidgetFormulrioFormPluginsConfigWidgetBibliotecaLibraryPluginsConfigWidget$Plugins carregadosLoaded plug-insPluginsConfigWidget:Abrir gerenciador de arquivosOpen in file managerPluginsConfigWidget4Diretrio raiz de plugins:Plug-ins root directory:PluginsConfigWidgetPluginPluginsConfigWidget VersoVersionPluginsConfigWidgetNomeName PolicyWidget PapisRoles PolicyWidget%1 (linha: %2) %1 (line: %2)QObject&novo_banco_de_dados new_databaseQObject%1_copia_de_%2 %1_copies_%2 Relationship %1_tem_muitos_%2%1_has_many_%2 Relationship%1_tem_um_%2 %1_has_one_%2 Relationship%1_herda_de_%2%1_inherits_%2 Relationship.muitos_%1_tem_muitos_%2many_%1_has_many_%2 Relationship CopiarCopyRelationshipConfigWidget PadroDefaultRelationshipConfigWidgetPostergvel: Deferrable:RelationshipConfigWidgetPostergao: Deferral:RelationshipConfigWidgetFormulrioFormRelationshipConfigWidgetGeneralizaoGeneralizationRelationshipConfigWidget requerido is requiredRelationshipWidget1-nRelationshipWidgetALLRelationshipWidgetAvanadoAdvancedRelationshipWidgetAtributo AttributeRelationshipWidgetAtributos AttributesRelationshipWidgetCOMMENTSRelationshipWidget CONSTRAINTSRelationshipWidgetCardinalidade: Cardinality:RelationshipWidgetRestrio ConstraintRelationshipWidgetRestries ConstraintsRelationshipWidgetOpes de Cpia Copy OptionsRelationshipWidgetDEFAULTSRelationshipWidget PadroDefaultRelationshipWidgetPostergvel: Deferrable:RelationshipWidgetPostergao: Deferral:RelationshipWidgetJRelacionamento de Dependncia / CpiaDependency / Copy relationshipRelationshipWidget GeralGeneralRelationshipWidgetRRelacionamento de generalizao (herana))Generalization relationship (inheritance)RelationshipWidget INCLUDINGRelationshipWidgetINDEXESRelationshipWidgetIdentificador IdentifierRelationshipWidgetHRelacionamento de muitos para muitosMany to many relationshipRelationshipWidgetNomeNameRelationshipWidgetxNome da tabela gerada pelo relacionamento muitos para muitos:Name of the table generated from many to many relationshipRelationshipWidget@Relacionamento de um para muitosOne to many relationshipRelationshipWidget8Relacionamento de um para umOne to one relationshipRelationshipWidgetChave primria Primary keyRelationshipWidget"Tabela Receptora:Receiver Table:RelationshipWidget$Tabela Referncia:Reference Table:RelationshipWidget$Tab. Referenciada:Referenced Table:RelationshipWidgetVRelacionamento gerado via chave estrangeira&Relationship generated via foreign keyRelationshipWidgetSTORAGERelationshipWidgetTabela 1:Table 1:RelationshipWidgetTabela 2:Table 2:RelationshipWidget|Esta aba avanada mostra os objetos (colunas ou tabela) auto criados pela conexo do relacionamento, bem como as chaves estrangeiras que representam a ligao entre as tabelas participantes.This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables.RelationshipWidgetTipoTypeRelationshipWidgetUsar padres Use defaultsRelationshipWidget"[DST] requerido[DST] is requiredRelationshipWidget"[SRC] requerido[SRC] is requiredRelationshipWidgetdepRelationshipWidgetfkRelationshipWidgetn-nRelationshipWidgetAtributos Attributes RoleWidgetConexes: Connections: RoleWidgetEncriptado Encrypted RoleWidgetMembro de Member of RoleWidgetMembrosMembers RoleWidget Membros (Admin.)Members (Admin.) RoleWidget Senha: Password: RoleWidget PapelRole RoleWidgetSuperusurio Superuser RoleWidgetValidadeValidity RoleWidget$Expr. Condicional:Conditional Expr.: RuleWidgetEvento:Event: RuleWidgetTipo Execuo:Execution Type: RuleWidgetComando SQL: SQL Command: RuleWidgetComando SQL SQL command RuleWidgetPara criar uma regra que no execute ao alguma (<strong>DO NOTHING</strong>) basta no especificar comandos na tabela de comandos SQL.To create a rule that does not perform any action (DO NOTHING) simply do not specify commands in the SQL commands table. RuleWidgetFormulrioFormSQLExecutionWidgetCarregarLoadSQLExecutionWidget SalvarSaveSQLExecutionWidgetSalvar comoSave asSQLExecutionWidgetAtributos Attributes SQLToolWidgetFormulrioForm SQLToolWidgetFormulrioFormSceneInfoWidget*Cor de preenchimento: Fill color: SchemaWidget"Mostrar retnguloShow rectangle SchemaWidget Cache:Cache:SequenceWidgetCclica:Cyclic:SequenceWidgetIncremento: Increment:SequenceWidgetMximo:Maximum:SequenceWidgetMnimo:Minimum:SequenceWidgetIncio:Start:SequenceWidgetAdicionarAddSnippetsConfigWidgetCancelar edioCancel editionSnippetsConfigWidget$Criar nova conexoCreate new connectionSnippetsConfigWidget4Editar conexo selecionadaEdit selected connectionSnippetsConfigWidgetFormulrioFormSnippetsConfigWidget GeralGeneralSnippetsConfigWidgetAtualizarUpdateSnippetsConfigWidgetr-- Cdigo SQL no disponvel para este tipo de objeto. --2-- SQL code unavailable for this type of object --SourceCodeWidget.Gerando cdigo fonte...Generating source code...SourceCodeWidget PostgreSQLSourceCodeWidgetSQLSourceCodeWidgetVCdigo SQL (*.sql);;Todos os Arquivos (*.*)!SQL code (*.sql);;All files (*.*)SourceCodeWidget8Visualizao de cdigo fonteSource code visualizationSourceCodeWidgetVerso:Version:SourceCodeWidgetXMLSourceCodeWidgetconecdigo iconecodigoSourceCodeWidget ObjetoObjectSwapObjectsIdsWidgetObjeto Pai Parent ObjectSwapObjectsIdsWidgetTipo Pai Parent TypeSwapObjectsIdsWidgetTipoTypeSwapObjectsIdsWidgetnova_tabela new_tableTable CopiarCopyTableDataWidget ColarPasteTableDataWidget CopiarCopy TableWidgetValor Padro Default Value TableWidget EventoEvent TableWidgetEventosEvents TableWidgetExecuo Execution TableWidgetDisparoFiring TableWidgetIndexaoIndexing TableWidgetNomeName TableWidgetNoNo TableWidget ON DELETE TableWidget ON UPDATE TableWidgetPaiParent TableWidgetTab. Refer. Refer. Table TableWidget PapisRoles TableWidgetEsquemaSchema TableWidgetTipoType TableWidgetSimYes TableWidgetDiretrio: Directory:TablespaceWidgetFormulrioFormTablespaceWidget$Executando tarefasExecuting tasksTaskProgressWidget<Aguardando a tarefa iniciar...Waiting task to start...TaskProgressWidgetNegritoBold TextboxWidget Fonte:Font: TextboxWidgetItlicoItalic TextboxWidget.Selecionar cor de textoSelect text color TextboxWidgetSublinhado Underline TextboxWidgetArgumento: Argument: TriggerWidgetArgumentos Arguments TriggerWidget ColunaColumn TriggerWidgetColuna:Column: TriggerWidgetColunasColumns TriggerWidgetCondio: Condition: TriggerWidgetRestrio Constraint TriggerWidgetDELETE TriggerWidgetPostergvel: Deferrable: TriggerWidgetEvento:Event: TriggerWidgetExecuo: Excution: TriggerWidget FOR EACH ROW TriggerWidgetFuno: Function: TriggerWidgetINSERT TriggerWidgetOpes:Options: TriggerWidgetTab. Refer.: Refer. Table: TriggerWidgetTRUNCATE TriggerWidgetTipoType TriggerWidgetUPDATE TriggerWidgetANALYZE: TypeWidgetAlinhamento: Alignment: TypeWidgetAtributos Attributes TypeWidgetTipo Base Base Type TypeWidgetPor valorBy value TypeWidgetFun. Cannica:Canonical Func.: TypeWidgetCategoria: Category: TypeWidgetIntercalvel Collatable TypeWidgetIntercalao Collation TypeWidgetIntercalao: Collation: TypeWidgetConfigurao:Configuration: TypeWidgetValor Padro:Default Value: TypeWidgetDelimitador: Delimiter: TypeWidgetTipo Elemento Element Type TypeWidgetEnumerao Enumeration TypeWidgetEnumerao: Enumeration: TypeWidgetEnumeraes Enumerations TypeWidgetFunes Functions TypeWidgetINPUT: TypeWidgetComp. Interno:Internal Length: TypeWidgetTipo Como Like Type TypeWidgetNomeName TypeWidget Nome:Name: TypeWidgetOUTPUT: TypeWidget*Classe de Operadores:Operator Class: TypeWidgetOpes:Options: TypeWidgetPreferido Preferred TypeWidgetRECV: TypeWidgetExtensoRange TypeWidgetSEND: TypeWidgetArmazenamento:Storage: TypeWidgetSubtipoSubtype TypeWidget$Fun. Dif. Subtipo:Subtype Diff Func.: TypeWidget TPMOD_IN: TypeWidget TPMOD_OUT: TypeWidgetAs funes para serem atribudas a um tipo extenso devem ter as seguintes assinaturas:<br/><br/><strong>Cannica:</strong> <em>any funcao(any)</em> <br/><strong>Dif. Subtipo:</strong> <em>double precision funcao(subtipo, subtipo)</em>The functions to be assigned to a range type should have the following signatures:

Canonical: any function(any)
Subtype Diff: double precision function(subtype, subtype) TypeWidgetAs funes a serem atribudas ao tipo devem ser escritas em linguagem C, e possurem respectivamente as seguintes assinaturas:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any funcao(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring funcao(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byte funcao(any)</em></td> <td><strong>RECV:</strong> <em>any funcao(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer funcao(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring funcao(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean funcao(internal)</em></td> <tr> </table>The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:
INPUT: any function(cstring, oid, integer) OUTPUT: cstring function(any)
SEND: byta function(any) RECV: any function(internal, oid, integer)
TPMOD_IN: integer function(cstring[]) TPMOD_OUT: cstring function(integer)
ANALYZE: boolean function(internal)
 TypeWidgetTipoType TypeWidgetchar TypeWidgetdouble precision TypeWidgetinteger TypeWidgetsmallint TypeWidget/* No foi possvel gerar o cdigo SQL. Certifique-se de que todos os atributos estejam corretamente preenchidos! S/* Could not generate the SQL code. Make sure all attributes are correctly filled!  ViewWidgetApelidoAlias ViewWidgetApelido Col. Alias Col. ViewWidget$Previso de Cdigo Code Preview ViewWidget Col./Expr. ViewWidget ColunaColumn ViewWidget$Apelido de Coluna: Column Alias: ViewWidgetColuna:Column: ViewWidget EventoEvent ViewWidgetEventosEvents ViewWidgetExecuo Execution ViewWidgetExpresso Expression ViewWidget*Apelido de Expresso:Expression Alias: ViewWidgetExpresso: Expression: ViewWidgetDisparoFiring ViewWidgetndicesIndexes ViewWidgetIndexaoIndexing ViewWidget Modo:Mode: ViewWidgetNomeName ViewWidgetTab. Refer. Refer. Table ViewWidget Tipo Referncia:Reference Type: ViewWidgetReferncias References ViewWidget RegrasRules ViewWidget$Apelido de Tabela: Table Alias: ViewWidget&Expresso de TabelaTable Expression ViewWidgetTabela:Table: ViewWidgetGatilhosTriggers ViewWidgetUsado em:Used in: ViewWidget$Definio da VisoView Definition ViewWidgetFormulrioForm WelcomeWidgetpgmodeler-0.9.2/lang/pt_BR.ts000066400000000000000000014523671360462764600160370ustar00rootroot00000000000000 AboutWidget About pgModeler Sobre o pgModeler PostgreSQL Database Modeler Modelador de Banco de Dados PostgreSQL Open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand, let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards. pgModeler is proudly a brazilian software! Hide this widget ... (BUILD_NUM) License 0.0.0 build: <html><head/><body><p><a href="http://pgmodeler.com.br"><span style=" text-decoration: underline; color:#2980b9;">https://pgmodeler.io</span></a></p></body></html> <html><head/><body><p>Copyright 2006-2018 - Raphael Araújo e Silva &lt;<a href="mailto:raphael@pgmodeler.com.br"><span style=" text-decoration: underline; color:#0057ae;">raphael@pgmodeler.io</span></a>&gt;</p></body></html> AggregateWidget Final Function: Função Final: Sort Operator: Operador de Ordenação: Initial Condition: Condição Inicial: Funtion Inputs Entradas da Função Function State Estado da Função Input Data Type Tipo de Dados de Entrada State Data Type Tipo de Dado de Estado An aggregate function that accepts the types <em><strong>typeA</strong></em> and <em><strong>typeB</strong></em> as input types and which type of state is <em><strong>state_type</strong></em>, must obey the following rules: <br/><br/> <strong> &nbsp;&nbsp;&nbsp;• Final Function:</strong> <em>void final_function(<strong>state_type</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp;• Transition Function:</strong> <em><strong>state_type</strong> transition_function(<strong>state_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em> Uma função de agregação que aceita os tipos <em><strong>tipoA</strong></em> e <em><strong>tipoB</strong></em> como entrada e cujo tipo de estado seja <em><strong>tipo_estado</strong></em>, deve obedecer às seguintes regras:<br/><br/> <strong> &nbsp;&nbsp;&nbsp;• Função Final:</strong> <em>void funcao_final(<strong>tipo_estado</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp;• Função Transição:</strong> <em><strong>tipo_estado</strong> funcao_transicao(<strong>tipo_estado</strong>, <strong>tipoA</strong>, <strong>tipoB</strong>)</em> Transition Func.: AppearanceConfigWidget Form Formulário Element: Elemento: Global: Font style Global: Estilo de fonte Global: Constraints descriptor Global: Descritor de restrições Global: Object selection Global: Seleção de objetos Global: Position hint text Global: Texto do informativo de posição Global: Position hint box Global: Caixa do informativo de posição Global: Objects type Global: Tipo dos objetos Global: Lock arc Global: Arco do cadeado Global: Lock body Global: Corpo do cadeado Table: Schema name Tabela: Nome do esquema Table: Table name Tabela: Nome da tabela Table: Columns box Tabela: Caixa das colunas Table: Extended attributes box Tabela: Caixa dos atributos extendidos Table: Title box Tabela: Caixa do título Rule: Name Regra: Nome Rule: Descriptor Regra: Descritor Index: Name Índice: Nome Index: Descriptor Índice: Descritor Trigger: Name Gatilho: Nome Trigger: Descriptor Gatilho: Descritor View: Schema name Visão: Nome do esquema View: View name Visão: Nome da visão View: References box Visão: Caixa das referências View: Title box Visão: Caixa do título View: Table / columns alias Visão: Apelido da tabela / coluna View: Referenced column Visão: Coluna referenciada View: Referenced table Visão: Tabela referenciada View: Reference descriptor Visão: Descritor da referência Textbox: Body Caixa de Texto: Corpo Column: Column name Coluna: Nome da coluna Column: Descriptor Coluna: Descritor Column: Included / Inherited by relationship Coluna: Incluída / Herdada por relacionamento Column: Protected Coluna: Protegida Column (pk): Column name Coluna (pk): Nome da coluna Column (pk): Descriptor Coluna (pk): Descritor Column (fk): Column name Coluna (fk): Nome da coluna Column (fk): Descriptor Coluna (fk): Descritor Column (uq): Column name Coluna (uq): Nome da coluna Column (uq): Descriptor Coluna (uq): Descritor Column (nn): Column name Coluna (nn): Nome da coluna Column (nn): Descriptor Coluna (nn): Descritor Relationship: Descriptor Relacionamento: Descritor Relationship: Label text Relacionamento: Texto do rótulo Relationship: Label box Relacionamento: Caixa do rótulo Relationship: Attribute text Relacionamento: Texto do atributo Relationship: Attribute descriptor Relacionamento: Descritor do atributo Font: Fonte: pt Bold Negrito Italic Itálico Colors: Cores: Underline Sublinhado View: Extended attributes box Visão: Caixa dos atributos extendidos Tag: Name Tag: Body Placeholder: Body Constraint: Name Constraint: Descriptor Application Unknown exception caught! Exceção desconhecida capturada! Failed to create initial configuration in `%1'! Check if the current user has write permission over that path and at least read permission over `%2'. BaseConfigWidget A backup of the previous settings was saved into <strong>%1</strong>! BaseForm Dialog Diálogo &Apply &Aplicar &Cancel &Cancelar &Ok %1 properties BaseObject Column Coluna Constraint Restrição Function Função Trigger Gatilho Index Índice Rule Regra Table Tabela View Visão Domain Domínio Schema Esquema Aggregate Agregação Operator Operador Sequence Sequência Role Papel Conversion Conversão Cast Molde Language Linguagem Type Tipo Tablespace Espaço de Tabela Operator Family Família de Operadores Operator Class Classe de Operadores Database Banco de Dados Relationship Relacionamento Textbox Caixa de Texto Permission Permissão Parameter Parâmetro Collation Intercalação Type Attribute Atributo de Tipo new_object novo_objeto novos_objetos Extension Event Trigger Tag Basic Relationship Policy Generic SQL BaseObjectView SQL off BaseObjectWidget Name: Nome: icone Versão em inglês está errada! ícone Comment: Comentário: Tablespace: Esp. de Tabela: Owner: Proprietário: Schema: Esquema: This object is protected thus no change in form will be applied to it. Este objeto está protegido, assim nenhuma alteração no formulário será aplicada ao mesmo. Value(s) Valor(es) Version Versão Edit permissions Editar permissões Disable SQL code Desabilitar código SQL Collation: Intercalação: Required field. Leaving this empty will raise errors! Campo requerido. Deixá-lo em branco gerará erros! Edit object's permissions Editar permissões do objeto Disables the generated SQL code using comment tokens (--). This will disable the code of all child and referrer objects. Append or prepend a set of SQL commands to the object's definition. Custom SQL ID: The <em style='color: %1'><strong>highlighted</strong></em> fields in the form or one of their values are available only on specific PostgreSQL versions. Generating SQL code for versions other than those specified in the fields' tooltips may create incompatible code. BaseRelationship rel_%1_%2 BaseTableView Toggles the extended attributes display Connected rels: %1 BugReportForm Bug Report Bug report &Cancel &Cancelar Create Criar Use the form below to generate a complete bug report. Please, try to be as clear as possible when describing the actions that can reproduce the bug. Additionally, it's important to attach a sample database model so that the bug can be quickly discovered and fixed! Report Relatório Issue details Output: Select the report's output folder ... <html><head/><body><p>If you prefer it's possible to report this issue anytime on pgModeler's project repository at <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html> Database Model Attach the below database model file to be debugged. Attach a different database model Bug report successfuly generated! Please, send the file <strong>%1</strong> to <em>%2</em> in order be analyzed. Thank you for the collaboration! Load model Carregar modelo Database model (*.dbm);;All files (*.*) Modelo de banco de dados (*.dbm);; Todos os arquivos (*.*) Select report output folder BulkDataEditWidget Bulk data edit CastWidget Cast Type: Molde de Tipo: Assignment Atribuição Input / Output Entrada / Saída Source data type Tipo dado origem Target data type Tipo dado destino The function to be assigned to a cast from <em><strong>typeA</strong></em> to <em><strong>typeB</strong></em> must have the following signature: <em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>. A função a ser atribuída à uma moldagem do <em><strong>tipoA</strong></em> para o <em><strong>tipoB</strong></em> deve possuir a seguinte assinatura: <em><strong>tipoB</strong> funcao(<strong>tipoA</strong>, integer, boolean)</em>. I&mplicit Conversion Func.: Função de Conv.: E&xplicit CodeCompletionWidget Makes the widget closable only by ESC key or mouse click on other controls. SQL Keyword (no items found.) Make &persistent CollationWidget Locale: Localidade: Encoding: Codificação: LC_COLLATE: LC_CTYPE: The fields <strong><em>Collation</em></strong>, <strong><em>Locale</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> are mutually exclusive, so you have to set only one of them in order to properly handle a collation. Os campos <strong><em>Intercalação</em></strong>, <strong><em>Localidade</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> são mutuamente exclusivos, então você tem que definir apenas um deles a fim de manipular corretamente a intercalação. Not defined Não definido ColorPickerWidget Form Formulário Generate random color(s) Alt+R Select color ColumnWidget Default Value: Valor Padrão: E&xpression: &NOT NULL Se&quence: Edit the underlying sequence's attributes Edit sequence Identity: ConfigurationForm pgModeler Configuration Configuração do pgModeler &Apply &Aplicar &Cancel &Cancelar Defaults Padrões General Geral Plug-ins Plugins Any modification made until now in the current section will be lost! Do you really want to restore default settings? Qualquer modificação feita até agora na seção atual será perdida! Deseja realmente restaurar as configurações padrão? Relationships Appearance Connections Snippets In some cases restore the default settings related to it may solve the problem. Would like to do that? Restore ConnectionsConfigWidget Connections: Conexões: Create new connection Criar nova conexão Cancel edition Cancelar edição Edit selected connection Editar conexão selecionada Delete selected connection Apagar conexão selecionada Connection Alias: Apelido da Conexão: Connection DB: BD Conexão: Host/Port: Servidor/Porta: User: Usuário: Password: Senha: Timeout: Tempo limite: second(s) segundo(s) SSL Mode: Modo SSL: Disable Desabilitar Allow Permitir Require Requerir AC verification Verificação de AC Full verification Verificação Completa Client Certificate: Certificado Cliente: ~/.postgresql/postgresql.crt Client Key: Chave Cliente: ~/.postgresql/postgresql.key Root Certificate: Certificado Raiz: ~/.postgresql/root.crt Revoked Certs.: Cert. Revogados: ~/.postgresql/root.crl Force GSSAPI Forçar GSSAPI Add Adicionar Update Atualizar Test Testar Success Sucesso Edit database connections Duplicate the selected connection General Geral Other params: Specify additional connection parameters in the form [param]=[value]. These parameters are described in the <strong>libpq</strong> chapter at PostgreSQL docs. Default for: Automatically browses the named database when using this connection to manage databases on <strong>Manage</strong> view. Auto browse Diff Export Exportar Import Validation Security Kerberos Server: Indicates in which operations (diff, export, import or validation) the connection is used if none is explicitly specified by the user. There is a connection being created or edited! Do you want to save it? Found %1 connection(s) No connections found Edit connections Connection successfully established! Server details: PID: `%1' Protocol: `%2' Version: `%3' ConstraintWidget Constraint Type: Tipo de Restrição: Fill Factor: Fator Preenc.: Match: Confrontar: Deferrable: Postergável: Deferral: Postergação: ON DELETE: ON UPDATE: Columns Colunas Column: Coluna: Referenced Columns Colunas Referenciadas Table: Tabela: Column Coluna Type Tipo No inherit: Sem herança: Exclude Elements Excluir Elementos Columns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form. Colunas que foram incluídas por relacionamento não podem ser adicionadas / removidas manualmente da chave primária. Se tais alterações forem feitas elas podem gerar erros. Para criar chaves primárias usando colunas incluídas por relacionamentos use as seguintes opções: campo identificador, aba atributos & restrições ou aba chave primária no formulário de relacionamento. This attribute cannot be changed once the object is created. Expression: Expressão: Indexing: Indexação: ConversionWidget Source Encoding: Codificação Origem: Target Encoding: Codificação Destino: Default Conversion: Conversão Padrão: The function to be assigned to an encoding conversion must have the following signature: <em>void function(integer, integer, cstring, internal, integer)</em>. A função a ser atribuída a uma conversão de codificação deve possuir a seguinte assinatura: <em>void funcao(integer, integer, cstring, internal, integer)</em>. Conversion Func.: Função de Conv.: CrashHandlerForm Crash Handler Stack trace Rastreamento de pilha Input: Load report file for analysis Save the attached model file on the filesystem pgModeler bug report (*.bug);;All files (*.*) Load report Save model Salvar modelo Database model (*.dbm);;All files (*.*) Modelo de banco de dados (*.dbm);; Todos os arquivos (*.*) Crash handler Bug report analysis mode activated. Oops! pgModeler just crashed! Oopa! O pgModeler acaba de travar! We apologize for what happened! It is clear that a nasty bug caused that. Please fill out the form below describing your actions before pgModeler quit unexpectedly. This will help on bug extermination and improve the software. CsvLoadWidget Form Formulário Load CSV CSV File: Select output file ... Separator: Use the first row as column names in the CSV file. By unchecking this option the first row is used as data. Columns in the first row Load Carregar Semicolon (;) Comma (,) Space Tabulation Other ; Text delimiter: " Load CSV file Comma-separted values (*.csv);;All files (*.*) CustomSQLWidget Add custom SQL code SQL code Puts an SELECT command template at current cursor position. &SELECT Puts an INSERT command template at current cursor position. &INSERT Puts an UPDATE command template at current cursor position. &UPDATE Puts an DELETE command template at current cursor position. &DELETE &Clear Append SQL Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command. Append at end of model definition. Prepend SQL Prepend at beginning of model definition. <html><head/><body><p>Use custom commands with extreme caution because you can change the semantics of the entire model when running SQL validation or export processes. Additionally, depending on the amount of commands, those processes can have their performance sensibly degradated.</p></body></html> Generic INSERT Include serial columns Exclude serial columns Generic SELECT Table SELECT Generic UPDATE Table UPDATE Generic DELETE Table DELETE DataManipulationForm Data Manipulation &Close &Fechar Refresh listing F5 Save changes Ctrl+S Export results to CSV file Ctrl+X Undo modifications Ctrl+Z Add empty rows Ins Mark the selected rows to be deleted Del Duplicate the selected rows Ctrl+D Filter the result set Table: Tabela: Schema: Esquema: in Hide views Filter expression Order && Limit results (Use <strong>0</strong> for no limit) Limit in: Add Item Adicionar Item Remove Item Remover Item Clear the order by columns list Move selected item up Move selected item down ASC DESC Column: Coluna: <strong>WARNING: </strong> There are some changed rows waiting the commit! Do you really want to discard them and retrieve the data now? Rows returned: <strong>%1</strong>&nbsp;&nbsp;&nbsp; <em>(Limit: <strong>%1</strong>)</em> none No objects found Found %1 object(s) Views can't have their data handled through this grid, this way, all operations are disabled. The selected table doesn't owns a primary key! Updates and deletes will be performed by considering all columns as primary key. <strong>WARNING:</strong> those operations can affect more than one row. This row is marked to be %1 deleted updated inserted [binary data] <strong>WARNING:</strong> Once commited its not possible to undo the changes! Proceed with saving? delete update insert <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> Copy items on the grid Paste items on the grid Ctrl+V Browse referenced tables Change the values of all selected cells at once Ctrl+E Add new rows from a CSV file Copy as CSV Copy as text Copy items Pase items Browse tables Duplicate row(s) Delete row(s) Edit cell(s) Column Coluna Referenced tables (none) Referrer tables DatabaseExplorerWidget Form Formulário Open the grid to visualize or edit data Data &Grid Alt+G Open a new SQL execution pane ... Ctrl+F6 Update the objects tree Drop this database Expands all items Expandir todos os itens Collapses all items Recolher todos os itens Filters the currently loaded items in the tree by using a pattern and matching their names. If <strong>By OID</strong> is checked the pattern is interpreted as an integer value that represents the object id (OID). <br><br/><strong>HINT:</strong> if you need to search the entire database use the full refresh (<strong>Ctrl+F5</strong>) prior the filtering. Filter: By OID Attribute Atributo Value Show raw attributes (not found, OID: %1) -- Source code not generated! Hit F7 or middle-click the item to load it. -- Admin. roles Alignment Analyze func. Arg. count Arg. default count Arg. defaults Arg. modes Arg. names Arg. types Behavior type By value Por valor Cast type Category Collatable Intercalável Collation Intercalação Comment Commutator Op. Configuration Conn. limit Constraint Restrição Create DB Create role Curr. version Default Padrão Default value Definition Definição Delimiter Dest. type Dimension Dimensão Directory Dest. encoding Element Elemento Encoding Encrypted Encriptado Enumerations Enumerações Exec. cost Expression Expressão Op. family Final func. Function Função Func. type Handler func. Handles type Hashes Index type Inherit Ini. condition Inline func. Input func. Internal length Interval type I/O cast Join func. Language Linguagem LC COLLATE LC CTYPE Leak proof Left type Length Comprimento Library Biblioteca Can login Materialized Member roles Merges Name Nome Negator op. Not null Object type OID With OIDs Old version Operator Operador Operator func. Output func. Owner Owner column Parents Password Permissions Permissões Precision Precisão Preferred Preferido Range attributes Receive func. Ref. roles Replication Restriction func. Return type Returns SETOF Right type Rows amount Schema Esquema Security type Send func. Sort op. Source type Src. encoding State type Storage Armazenamento Superuser Superusuário Tablespace Espaço de Tabela Type mod. in func. Type mod. out func. Transition func. Trusted Type Tipo Type attribute Types Unlogged Validator func. Validity Validade Windows func. false true Cache value Cycle Increment Max. value Min. value Start value Last value Subtype Subtipo Op. class Canonical func. Subtype diff func. Deferrable For each row Firing Disparo On insert On delete On update On truncate Arguments Argumentos Table Tabela Trigger func. Columns Colunas Condition Deferment Event Evento Execution mode Commands Position Comparison type Ref. columns Expressions Fill factor No inherit Op. classes Operators Operadores Ref. table Unique Único Predicate Collations Inherited Snippets Drop object Drop cascade Truncate Trunc. cascade Show data Reload properties Update Atualizar Rename Renomear Source code Quick refresh Full refresh Do you really want to drop the object <strong>%1</strong> <em>(%2)</em>? Do you really want to <strong>cascade</strong> drop the object <strong>%1</strong> <em>(%2)</em>? This action will drop all the other objects that depends on it. Do you really want to truncate the table <strong>%1</strong>? Do you really want to <strong>cascade</strong> truncate the table <strong>%1</strong>? This action will truncate all the tables that depends on it? Src. table: %1 Src. column(s): %2 Ref. table: %1 Ref. column(s): %2 -- Source code genaration for buil-in and base types currently unavailable -- -- Source code unavailable for the object %1 (%2). -- Toggle the display of filter widget as well the system/extension objects. Sort items alphabetically. When unchecked, items are sorted by OID. Sort alphabetically Client encoding Configuration file Data directory Dynamic library path Dynamic shared memory Hba file Listen addresses Max. connections Listen port Server encoding SSL SSL ca file SSL cert file SSL crl file SSL key file Server version Ident file Password encryption Connection ID Server PID Server protocol Referrers Identity Command USING expr. CHECK expr. Roles Papéis RLS enabled RLS forced Show objects filter Show system objects Show extension objects -- Source code unavailable for this kind of object -- Also restart sequences Warning You're running a demonstration version! The data manipulation feature is available only in the full version! <strong>CAUTION:</strong> You are about to drop the entire database <strong>%1</strong>! All data will be completely wiped out. Do you really want to proceed? DatabaseImportForm Settings Options Connection: Conexão: Resolve some of the object's dependencies by querying the catalog when a needed object does not exists on the loaded set. In some cases it's necessary to combine this option with others below. This option does not applies to database level objects like role, tablespace and language as well for data types, extensions. Automatically resolve dependencies Random colors will be assigned to imported relationships facilitating the identification of links between tables mainly in large models. Random colors for relationships Enables the import of system built-in objects. It's recommend to select only those objects that are directly referenced by the ones to be imported. WARNING: Try to import a huge set of system objects can bloat the resultant model or even crash pgModeler due to memory/cpu overuse. Import system objects Enables the import of objects created by extensions. Generally there is no need to check this option but if there are objects in the database that directly references this category of objects this mode must be enabled. Import extension objects pgModeler ignores import errors and will try to create as many as possible objects. By checking this option the import operation will be not aborted but an incomplete model will be constructed. This option generates a log file on pgModeler's temp directory. Ignore import errors All catalog queries as well the created objects' source code are printed to standard output (stdout). Debug mode Create all imported objects in the current working model instead of create a new one. Import objects to the working model Database Banco de Dados Filter: Filter object by it's OID By OID Select all objects ... Clear object selection Expands all items Expandir todos os itens Collapses all items Recolher todos os itens Output Progress label... Rótulo de progresso... Cancel Cancelar &Import &Close &Fechar <strong>ATTENTION:</strong> You are about to import objects to the current working model! This action will cause irreversible changes to it even in case of critical errors during the process. Do you want to proceed? Importing process aborted! Importing process canceled by user! Importing process sucessfuly ended! No databases found Found %1 database(s) Retrieving objects from database... Retrieving cluster level objects... Retrieving objects of schema `%1'... This is a PostgreSQL built-in data type and cannot be imported. This is a pgModeler's built-in object. It will be ignored if checked by user. Import database Retrieving objects of `%1' (%2)... DatabaseImportHelper Retrieving system objects... `%1' Retrieving objects... `%1' Creating object `%1' (%2)... Import failed to recreate some objects in `%1' tries. Creating permissions for object `%1' (%2)... Creating columns permissions... Updating relationships of `%1' (%2)... Validating relationships... The database import ended but some errors were generated and saved into the log file `%1'. This file will last until pgModeler quit. Creating table inheritances... Destroying unused detached columns... Assigning sequences to columns... Creating object `%1' (%2), oid `%3'... Trying to recreate object `%1' (%2), oid `%3'... DatabaseModel The demonstration version can create only `%1' instances of each object type! You've reach this limit for the type: `%2' Loading: `%1' (%2) Validating relationships... Saving object `%1' (%2) Saving metadata of the object `%1' (%2) Metadata file successfully saved! Process successfully ended but no metadata was saved! Creating object `%1' (%2) Object `%1' (%2) already exists. Ignoring. Loading metadata for object `%1' (%2) Object `%1' (%2) not found. Ignoring metadata. Metadata file successfully loaded! Generating %1 code: `%2' (%3) DatabaseWidget Template DB: DB Modelo: Model Author: Autor do Modelo: Encoding: Codificação: LC_COLLATE: Connections: Conexões: LC_CTYPE: Default Padrão Attributes Atributos Default Objects Tablespace: Esp. de Tabela: Schema: Esquema: Collation: Intercalação: Owner: The fields <strong>LC_COLLATE</strong> and <strong>LC_CTYPE</strong> have pre-configured values based upon the running system. You can freely modify those values if you intend to export the model to another host. Use the above fields to specify the default attributes assigned to new objects created on the database model. Leaving a field empty will cause PostgreSQL to use the default values when exporting the model. Options: Opções: Allow connections Is template DomainWidget Default Value: Valor Padrão: Name: Nome: Attributes Atributos Not null Check constraints Expression: Expressão: Name Nome Expression Expressão DonateWidget Form Formulário Donate to pgModeler Hide this widget ... <html><head/><body><p>pgModeler is brought to you thanks to a <span style=" font-style:italic;">great effort to create and distribute a quality product</span>. This project is reaching out levels of maturity never imagined. All this is the result of a joint work between its author and the <span style=" font-weight:600;">Open Source community</span>. <br/><br/>This software has a long way to go yet and with your help we'll keep maintaining the good job and bringing new improvements on each release. If you did like pgModeler and thinks it deserves a contribution please make a donation!</p></body></html> I want to help! ElementsWidget Form Formulário Column: Coluna: Expression: Expressão: Collation: Intercalação: Operator Class: Classe de Operadores: Operator: Operador: Sorting: Ordenação: Ascending Ascendente Descending Descendente Nulls first Nulos primeiro Element Elemento Type Tipo Operator Class Classe de Operadores Sorting Ordenação Nulls First Nulos Primeiro Collation Intercalação Operator Operador Expression Expressão Yes Sim No Não EventTriggerWidget Event: Evento: Function: Função: Filter Tag: Tag command Exception Assignment of a pseudo-type to the type of the column! Atribuição de um pseudo-tipo ao tipo da coluna! Assignment of a precision greater than the length of the type! Atribuição de precisão maior do que o comprimento do tipo! Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! Atribuição de precisão inválida a um tipo time, timestamp ou interval. A precisão neste caso deve ser igual ou inferior a 6! Reference to a column which index is out of the capacity of the column list! Referência a uma coluna com índice fora da capacidade da lista de colunas! Assignment of not allocated object! Atribuição de um objeto não alocado! Removing an object of an invalid type! Remoção de objeto de tipo inválido! Obtaining an object of an invalid type! Obtenção de um objeto com tipo inválido! Assignment of empty name to table return type! Atribuição de nome vazio ao tipo de retorno de tabela! Reference to an event which does not belongs to trigger! Referência a um evento não pertecente ao gatilho! Assignment of a function which language is invalid! Atribuição de função com linguagem inválida! Assignment of empty name to an object! Atribuição de nome vazio a um objeto! Assignment of schema object which type is invalid! Atribuição de um objeto esquema com tipo inválido! Assignment of tablespace object with invalid type! Atribuição de objeto espaço de tabela com tipo inválido! Assignment of tablespace to an invalid object! Atribuição de um espaço de tabela a um objeto de tipo inválido! Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique! Atribuição de um objeto espaço de tabela a uma restrição de tipo inválido! A restrição deve ser uma chave-primária ou única para pode pertencer a um espaço de tabela! Assignment of owner object which type is invalid! Atribuição de um objeto papel com tipo inválido! Assignment of owner to an invalid object! Atribuição de um dono a um objeto de tipo inválido! Reference to a function with invalid type! Referência a uma função com tipo inválido! Reference to an argument of the operator with invalid type! Referência a um argumento do operador com tipo inválido! Reference to an operator with invalid type! Referência a um operador com tipo inválido! Reference to an invalid role type! Referência a um tipo de papel inválido! Assignment of an object that already belongs to another table! Atribuição de um objeto o qual já pertence a outra tabela! Assignment of a schema to the sequence which differs from the schema of the owner table! Atribuição de esquema à seqüência o qual difere do esquema da tabela possuidora! Assignment of an invalid value to one of the sequence attributes! Atribuição de valor inválido a um dos atributos da seqüência! Assignment of a minimum value to the sequence which is greater than the maximum value! Atribuição de valor mínimo da seqüência maior do que o valor máximo! Assignment of a null increment value to the sequence! Atribuição de incremento de seqüência com valor nulo! Assignment of null cache value to the sequence! Atribuição de cache de seqüência com valor nulo! Allocation of object with invalid type! Alocação de objeto com tipo inválido! Assignment of not allocated language! Atribuição de linguagem não alocada! Assignment of language object which type is invalid! Atribuição de linguagem com tipo inválido! Reference to data type with an index outside the capacity of data types list! Referência a tipo de dado com índice fora da capacidade da lista de tipos de dados! Assignment of invalid type to the object! Atribuição de um tipo inválido ao objeto! Obtaining types with invalid quantity! Obtenção de tipos com quantidade inválida! Insertion of item which already exists in the attributes list of the type! Inserção de item já existente na lista de atibutos do tipo! Insertion of invalid item in the attributes list of the type! Inserção de item inválido na lista de atibutos do tipo! Insertion of item which already exists in the enumarations list of the type! Inserção de item já existente na lista de enumerações do tipo! Insertion of invalid item in the enumerations list of the type! Inserção de item inválido na lista de emumerações do tipo! Assignment of invalid configuration to the type! Atribuição de configuração inválida ao tipo! Assignment of an invalid strategy/support number to an operator class element! Atribuição de valor inválido ao número de estratégia/suporte do elemento de classe de operadores! Insertion of element which already exists in the element list! Inserção de elemento já existente na lista de elementos! Removal of an object not allocated! Remoção de objeto não alocado! Operation with object(s) which type(s) is invalid! Operação com objeto(s) de tipo(s) inválido(s)! Reference to object with invalid type! Referência a um objeto com tipo inválido! Operation with object not allocated! Operação com objeto não alocado! The relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user! O relacionamento do tipo 1-1 onde ambas as tabelas são de participação obrigatória não é implementado por necessitar de fusão entre tabelas o que quebra a modelagem feita pelo usuário! Assignment of an invalid expression to the object! Atribuição de expressão inválida ao objeto! Assignment of a primary key to a table which already has one! Atribuição de chave primária à uma tabela a qual já possui uma! A foreign key can not be added to a relationship because is created automatically when this is connected! Uma chave estrangeira não pode ser adicionado a um relacionamento pois esta é criada automaticamente no momento da ligação do mesmo! Reference to an user-defined data type that not exists in the model! Referência a tipo de dado definido pelo usuário o qual não existe no modelo! Assignment of invalid maximum size to operation list! Atribuição de tamanho máximo inválido à lista de operações! One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! Um ou mais objetos foram invalidados e automaticamente removidos pois os mesmos referenciavam colunas de tabelas as quais foram incluídas através de relacionamentos e que deixaram de existir devido a desconexão ou exclusão dos relacionamentos geradores de tais colunas! Reference to an invalid privilege type! Referência a um tipo de privilégio inválido! Assignment of privilege incompatible with the type of object referenced by permission! Atribuição de privilégio incompatível com o tipo do objeto referenciado pela permissão! It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! Não é possível criar arrays de domínios ou sequências (dimensão >= 1)! O PostgreSQL ainda não implementa esta funcionalidade! Assignment of invalid name to the table generated from N-N relationship! Atribuição de nome inválido à tabela gerada por relacionamento N-N! Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns! Restrições do tipo chave-primária, chave-estrangeira ou única devem possuir pelo menos uma coluna relacionada às mesmas! Para chaves-estrangeira devem ser selecionadas, adicionalmente, as colunas referenciadas! The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 O processo de exportação falhou devido a um erro disparado pelo servidor PostgreSQL na tentativa de execução de um comando SQL. Para obter mais detalhes sobre erro cheque a pilha de exceções! ** Comando SQL executado: ** %1 One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. Um ou mais plugins não foram ativados devido a erros no processo de carregamento! Verifique a pilha de exceções para mais detalhes. Assignment of empty XML buffer to parser! Atribuição de buffer de código XML vazio ao parser! Assignment of empty DTD file name! Atribuição de nome de arquivo DTD vazio! Assignment of empty name to the DTD declaration! Atribuição de nome vazio à declaração DTD! Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! Operação sobre árvore de elementos não alocada! É necessário carregar o buffer XML do parser e interpretá-lo para que a árvore seja gerada! Operation with unallocated tree element! Operação com elemento de árvore de elementos não alocado! Operation with element which does not exists in the element tree currently loaded! Operação com elemento o qual não faz parte da árvore de elementos carregada atualmente! Assignment of a value to an invalid connection parameter! Atribuição de valor a um parâmetro de conexão inválido! Operation on connection not established! Operação sobre conexão não estabelecida! Attempt to connect without define configuration parameters! Tentativa de conexão sem parâmetros de configuração definidos! Assignment of not allocated SQL command result! Atribuição de resultado de comando SQL não alocado! Unable to allocate the result of the SQL command because the response from the DBMS was not understood by the client! Não foi possível alocar o resultado do comando SQL pois a resposta do SGBD não foi compreendida pelo cliente! Reference to a column of tuple with invalid index! Referência à uma coluna da tupla com índice inválido! Reference to a column of tuple with invalid name! Referência à uma coluna da tupla com nome inválido! Assignment of a not allocated column to object `%1' (%2)! Assignment of a not allocated schema to object `%1' (%2)! The object `%1' (%2) has inconsistent SQL or XML definition! The object `%1' (%2) already exists on `%3' (%4)! The object `%1' (%2) cannot be assigned because there is already exists in the container object `%3'! Assigning object of an invalid type! The insertion of the parameter `%1' will not be possible because there is another parameter with same name in the function `%2'! The insertion of the table return type `%1' will not be possible because there is another return type with the same name in the `%2'! Reference to a parameter which index is out of the parameter list bounds! The column `%1' cannot be assigned to the trigger `%2' because they belongs to different parent tables! Assignment of a not allocated function to object `%1' (%2)! Assignment of a function which return type is different from `%1'! Assignment of a function which parameter count is invalid to the object `%1' (%2)! Event trigger function must be coded in any language other than SQL! Assignment of not allocated table to object `%1' (%2)! Reference to an argument which index is out of argument list bounds! Assignment of a name which contains invalid characters! Assignment of a name which length exceeds the maximum of 63 characters! Assignment of appended or prepended SQL to an invalid object! Assignment of value to an invalid option type on role! The insertion of the role `%1' is not possible because this is already being referenced by role `%2'! Reference redundancy detected by having the role `%1' referencing the role `%2'! The role `%1' can not be listed as a member of itself! Reference to a role which index is out of role list bounds! Insertion of empty command to the rule! Reference to a command which index is out of the command list bounds! Is not possible to create a self generalization/copy relationship! The table can not inherit or copy their own attributes! Assignment of a start value to the sequence which is extrapolating the range defined by minimum and maximum values! Assignment of owner table which is not in the same schema as the sequence `%1'! Assignment of owner table which does not belong to the same owner of the sequence `%1'! Assignment of a nonexistent owner column to the sequence `%1'! Assignment of an owner column to the sequence `%1' that is not related to any table! Reference to a label which index is out of labels list bounds! Assignment of a function with invalid return type to object `%1' (%2)! Assignment of a function with invalid parameter(s) type(s) to object `%1' (%2)! Assignment of a null type to object `%1' (%2)! Assignment of an empty directory to object `%1' (%2)! Reference to an attribute which index is out of the attributes list bounds! Reference to an enumeration which index is out of the enumerations list bounds! Assignment of an operator which input type count is invalid to aggregate function! Assignment of an operator which types of arguments is invalid! Assignment of system reserved name to the object `%1' (%2)! One function with invalid configuration is been used by the object `%1' (%2)! Reference to an element which index is out of element list bounds! Reference to an object which index is out of object list bounds! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4)! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4) that belongs to `%5' (%6)! The creation of the relationship `%1' between the table `%2' and `%3' can not be done because one does not have a primary key. If the relationship is of the type n-n both tables must have primary keys! Identifier relationship can not be created for a self relationship, relationships of the type n-n, copy or generalization! Unable to create a copy relationship because the column `%1' in table `%2' already exists in table `%3'! Unable to create the generalization relationship because the column `%1' in table `%2' can not be merged with the column `%3' of table `%4' because they have incompatible types! Unable to create the generalization relationship because the constraint `%1' in table `%2' can not be merged with the constraint `%3' of table `%4' due to their incompatible composition! An attribute can not be added to a copy or generalization relationship! The object `%1' (%2) is referencing the object `%3' (%4) which was not found in the model! Unable to write the file or directory `%1'! Make sure the output directory exists, or if the user has write permissions over it! Unable to write the file `%1' due to one or more errors in the definition generation process! The configuration of the relationship `%1' generates a redundancy between the relationships `%2'. Redundancy on identifier or generalization/copy relationships are not accepted since they result in incorrect column spreading making the model inconsistent! The primary key `%1' can only be allocated if declared within a block of code that defines a table or relationship! Insertion of a role which already exists in the role list of the permission! There is already a permission on object `%1' (%2) which has one or more equal roles from those present on permission to be assigned to the object! A permission is referencing the object `%1' (%2) which was not found in the model! The object `%1' (%2) can not be created because its not being assigned to any schema! The tablespace `%1' can not be inserted into the model because it points to the same directory as the tablespace `%2'! The function `%1' can not get a source code as a definition because its language is set to C. Use the attributes symbol and dynamic library instead! The function `%1' can have the attributes symbol and dynamic library configured only if the language is set to C. For all other cases you must specify a source code that defines it in the DBMS! The operator `%1' can not be assigned as a comutator of operator `%2' because it has incompatible settings! The operator `%1' can not be assigned as negator of operator `%2' because it has incompatible settings! The type `%1' can not self refer in the attributes `element' or `copy type' or be used as a data type of an attribute in the configuration of a composite type! Assignment of invalid element to type `%1'! Assignment of invalid alignment to type `%1'! The relationship `%1' can not make use of the special primary key because it is marked as identifier or it is a self relationship! The object `%1' (%2) can not be edited or deleted because it was automatically included through a relationship! If the object is an attribute or constraint the modifications must be done on the relationship editing form. The object `%1' (%2) can not be deleted because it is protected! The group `%1' has already been declared earlier! The group `%1' can not be built in the groups declaration block (%2)! The group `%1' was built but not declared in the groups declaration block (%2)! The group `%1' can not be built without possessing child elements! The group `%1' can not be built once more because this was done in previous blocks! The group `%1' has been declared but not built! Reference to a column of the objects table with invalid index! Reference to a row of the objects table with invalid index! The object `%1' (%2) can not be manipulated because it is reserved to PostgreSQL! This object is present in the database model only as a reference! The new configuration of the function invalidates the object `%1' (%2)! In this case it is needed to undo the relationship between the affected object and function in order to the new configuration to take effect! A view reference must be used in at least one these SQL scopes: View Definition, SELECT-FROM, FROM-WHERE or After WHERE! Could not find the default settings file `%1'! To restore default settings check the existence of the file and try again! Could not load the plugin `%1' from the library `%2'! Message returned by plugin manager: `%3' Error while interpreting XML buffer at line %1 column %2. Message generated by the parser: %3. %4 Attempt to start a connection already stablished! Could not connect to the database. Message returned: `%1' Unable to allocate command result for the SQL because the server has generated a fatal error! Message returned by the DBMS: `%1' Reference to a tuple with an invalid index or the result is empty (no tuples)! Reference to a column of a tuple which was not yet initialized (tuple navigation not started)! Could not execute the SQL command. Message returned: `%1' Invalid use of a view reference as whole SQL definition! The assigned reference must be an expression! Assignment of a second definition expression to the view! It is not possible mix ordinary references (SELECT-FROM, FROM-WHERE, After WHERE) with references used as view SQL definition! Assignment of collation object which type is invalid! At the moment pgModeler does not support the creation of primary keys which some columns were generated by relationship connection. To create primary keys with this feature you can use the field `Identifier' or the tab `Primary key' on relationship editing form! Collations must be created at least with attributes LC_COLLATE and LC_CTYPE defined! The object `%1' (%2) cannot reference itself! This operation is not permitted for this kind of object! Only operator families which uses `btree' as indexing method are accepted by operator class elements! Reference to an invalid copy table option! Copy relationship between tables `%1' and `%2' cannot be done because the first one already copies attributes from `%3'! Tables can have only one copy table! The INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers! The TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table! The INSTEAD OF mode cannot be used on view triggers that executes for each statement! Constraint triggers can only be executed on AFTER events and for each row! A view trigger cannot be AFTER/BEFORE when it executes for each row! A trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event! Assignment of a column which has no parent table to the object `%1' (%2)! Only constraint triggers can be deferrable or reference another table! Reference to a function id which is incompatible with the user define type configuration! The operator class assigned to the object `%1' (%2) must use `btree' as indexing method! The validation process failed due to an error triggered by the validation helper. For more details about the error check the exception stack! The extension `%1' is registered as a data type and cannot have the attribute `handles datatype' modified! The fk relationship `%1' cannot be created because the foreign-key that represents it was not created on table `%2'! Assignement of an invalid object name pattern to the relationship `%1'! Reference to an invalid object name pattern id on the relationship `%1'! Invalid use of variadic parameter mode! This mode can be used only with an array or "any" data type! Mixing incompatibles DBMS export modes: `ignore object duplications', `drop database' or `drop objects' cannot be used with `simulate export'! Mixing incompatibles DROP options: `drop database' and `drop objects' cannot be used at the same time! Invalid object id swapping operation! The objects involved are the same! Invalid object id swapping operation! The database itself, tablespaces or roles cannot have the ids swapped! The widget already has a parent and cannot be assigned to a different object! Could not load the database model file `%1'. Check the error stack to see details. Try to run `pgmodeler-cli --fix-model' in order to correct the structure of the file if that is the case. The column `%1' cannot reference it's parent table `%2' as data type! Operation with an invalid element id `%1'! Reference to an invalid color id `%1' for element `%2'! Assignment of an invalid object to `%1' (%2)! The assigned object must be of type `%3'. The sequence `%1' can't be assigned to the column `%2' because the data type of the latter is incompatible. The type used must be an integer one! The option to generate temporary object names can only be used in simulation mode! It's not possible convert the type of the column `%1' to serial! It must have an `integer' based type and its default value must be a call to `nextval(seq_name::regclass)' function or a sequence object must be directly assigned to the column! Could not assign the variable `%1' to event trigger's filter. Currently, PostgreSQL supports only the `TAG' variable! Could not perform the `%1' operation on `%2' using the data on row `%3'! All changes were rolled back. ** Returned error ** %4 Malformed unescaped value on row `%1' column `%2'! Trying to undo/redo an invalid operation over an object that does not exists anymore or can't be handled! The operation history will be cleaned up. The object `%1' (%2) can't be handled because some needed fields are not set! Please, make sure to fill at least the requires fields in order to properly create or update the object. A relationship can only be swapped by other object of the same kind! A parent table of `%1' which OID is `%2' was not found in the set of imported objects! The enumeration `%1' can't be assigned to the type `%2' because contains invalid characters! The enumeration `%1' can't be assigned to the type `%2' because is too long! The connection was idle for too long and was automatically closed! The connection was unexpectedly closed by the database server `%1' at port `%2'! There is already a relationship between `%1' (%2) and `%3' (%4) in the model! When using relationships of the type generalization, copy and one-to-one there can't be other relationships linked to the pair of tables. Unable to load the configuration file `%1'! Please check if file exists in its folder and/or if it is not corrupted! Invalid syntax in file `%1', line %2, column %3! Invalid instruction `%1' on file `%2', line %3, column %4! Unknown attribute `%1' in file `%2', line %3, column %4! Invalid metacharacter `%1' in file `%2', line %3, column %4! Invalid operator `%1' in comparison expression, file `%2', line %3, column %4! Attribute `%1' with an undefined value in file `%2', line %3, column %4! Attribute `%1' with an invalid name in file `%2', line %3, column %4! Could not access the file or directory `%1'! Make sure that it exists or if the user has access permissions on it! Could not load file `%1'. The same appears to be inconsistent or one of its dependencies (DTD files) has errors or is missing! Unsupported PostgreSQL version (%1) detected! Valid versions are between %2 and %3. The object `%1' (%2), oid `%3', could not be imported due to one or more errors! Check the exception stack for more details. `HINT:' if the object somehow references objects in `pg_catalog' or `information_schema' consider enable the importing of system objects. Failed to drop the database `%1' because it is defined as the default database for the connection `%2'! The column `%1' must be `NOT NULL' because it composes the primary key of the table `%2'. You need to remove the column from the mentioned contraint in order to disable the `NOT NULL' on it! The identity column `%1' has an invalid data type! The data type must be `smallint', `integer' or `bigint'. Reference to an invalid affected command in policy `%1'! Reference to an invalid special role in policy `%1'! ExtensionWidget Version: Versão: Old Version: This attribute cannot be changed once the object is created. Handles data type FindReplaceWidget Form Formulário Replace one occurrence Replace Replace all occurrences Replace All Replace the selection and find the next one Replace && Find Replace: Find: Find previous Shift+F3 Find next F3 Case sensitive Regular expression Whole words Hide this widget ... FunctionWidget Attributes Atributos Behavior: Comportamento: Rows Returned: Linhas Retornadas: Execution Cost: Custo de Execução: Return Method: Método de Retorno: Function Type: Tipo de Função: Set Conjunto Return Table Tabela de Retorno Security: Segurança: Parameters Parâmetros Definition Definição Dynamic Library: Biblioteca Dinâmica: Symbol: Símbolo: Library: Biblioteca: Source code: Código fonte: Column Coluna Type Tipo Name Nome Default Value Valor Padrão Si&mple Tab&le Windown Func. Leakproof Mode Language: GeneralConfigWidget Form Formulário Milimeters Milímetros Pixels Píxeis Inches Polegadas Centimeter Centímetro A0 (841 x 1189 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) B0 (1030 x 1456 mm) B1 (728 x 1030 mm) B10 (32 x 45 mm) B2 (515 x 728 mm) B3 (364 x 515 mm) B4 (257 x 364 mm) B5 (182 x 257 mm) B6 (128 x 182 mm) B7 (91 x 128 mm) B8 (64 x 91 mm) B9 (45 x 64 mm) C5E (163 x 229 mm) Comm10E (105 x 241 mm) DLE (110 x 220 mm) Executive (191 x 254 mm) Executivo (191 x 254 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Legal (216 x 356 mm) Letter (216 x 279 mm) Carta (216 x 279 mm) Tabloid (279 x 432 mm) Tablóide (279 x 432 mm) Paper: Papel: Orientation: Orientação: Operation history: Histórico de operações: Print grid Imprimir grade Left: Esq.: Left margin Margem esquerda Top: Topo: Top margin Margem topo Right: Dir.: Right margin Margem direita Bottom: Base: Bottom margin Margem base Landscape Paisagem Portrait Retrato Print page numbers Imprimir número de páginas General && Design General Geral Check if there is a new version on server Design Disable antialiasing for lines and texts improving performance when handling huge models. Disable render smoothness Triggers a dialog asking the user to validate the model before a save, export or diff operation. Validate before save, export or diff Start move the canvas when the cursor is on the canvas edges Move canvas by keep mouse on corners Graphical objects (table, views and textboxes) will be created in a single step without the need to click on canvas Simplify creation of graphical objects After loading the model the last zoom and position on canvas will be restored Save and restore last position and zoom When enabled this option creates a placeholder object at the previous table's position when starting to move it. This will cause graphical updates on relationship lines to be performed only when the drag & drop action is done improving the performance. Disabling placeholders will cause those updates to be executed every time the table's position changes a single pixel (classical behavior). Use placeholders when moving tables Hide the portion of table which represent triggers, indexes and rules Hide table extended attributes Hide the object which represents the tag assigned to the table Hide table tags Hide the object that represents the relationship name Hide relationship name Toggles the code completion in all fields that accepts the input of SQL commands. Enable SQL code completion Printing && Code Code style Size: Font: Fonte: Colors: Cores: Options: Opções: Display line numbers Highlight lines at cursor's position pt Custom tab width: Printing Custom Unity: Custom Size: Width: Height: Page Margins: Line numbers' font color Line numbers' background color Highlighted line color The little brown fox jumps over the lazy dog Minimum object opacity (%): Defines the minimum opacity percentage applied to the objects when using the fade out feature. A zero opacity causes the object to be completely hidden not being possible to interact with it in the canvas area. Canvas grid size: Defines the vertical and horizontal grid size. This value affects the spacing of objects when using object grid alignment feature. By default the range selection is triggered with Shift + left click. By checking this option range selection will be activated only with a single click and move. Trigger range selection with a single click Defines the maximum amount of elements held in the operation history. Once reached the maximum number the history is automatically cleaned. Defines the period when the opened models will be saved automatically. Autosave interval (minutes): Replaces any straight line in relationship by curved ones in order to improve the model's visualization. Use curved lines for relationships Souce code editor args: lines Clear the entire SQL comand history. Clear history Open in file manager Abrir gerenciador de arquivos Overrides the default user interface language defined by the system. Requires restarting the program. <strong>NOTE:</strong> UI translations are third party collaborations thus any typo or mistake should be reported directly to their respective maintainers. SQL history max. length: Check updates at startup User interface language: Browse the source code editor application Souce code editor: Configurations directory: System default All files (*.*) Load file GenericSQLWidget SQL code HintTextWidget Form Formulário IndexWidget Fill Factor: Fator Preenc.: Indexing: Indexação: Options: Opções: Concurrent Concorrente Unique Único Fast update Atual. Rápida Elements Elementos Attributes Atributos Buffering Predicate: LanguageWidget Trusted: Confiável: The functions to be assigned to the language should have, respectively, the following signatures:<br/><br/> <strong>Handler Function:</strong> <em>language_handler function()</em><br/> <strong>Validator Function:</strong> <em>void function(oid)</em><br/> <strong>Inline Function:</strong> <em>void function(internal)</em> As funções a serem atribuídas à linguagem devem possuir, respectivamente, as seguintes assinaturas:<br/><br/> <strong>Função Manipuladora:</strong> <em>language_handler funcao()</em><br/> <strong>Função Validadora:</strong> <em>void funcao(oid)</em><br/> <strong>Função em Linha:</strong> <em>void funcao(internal)</em> Validator Func.: Handler Func.: Inline Func.: MainWindow pgModeler - PostgreSQL Database Modeler pgModeler - Modelador de Banco de Dados PostgreSQL &File &Arquivo &Edit &Editar &Show &Mostrar Plugins New Novo Ctrl+N Ctrl+S Zoom in Aumentar Zoom Ctrl+= Zoom out Diminuir Zoom Zoom - Zoom - Ctrl+- Ctrl+O Ctrl+Q Ctrl+P Ctrl+Z Ctrl+Y Ctrl+Shift+S Show grid Mostrar grade Ctrl+G Ctrl+W Ctrl+0 Align objects position to grid Alinhar objetos à grade Show the page delimiters Mostrar os delimitadores da página Ctrl+L Save all Salvar todos Show the model overview Mostra a visão geral do modelo F1 Save model Salvar modelo Save '%1' as... Salvar '%1' como... Database model (*.dbm);;All files (*.*) Modelo de banco de dados (*.dbm);; Todos os arquivos (*.*) Database model printing Impressão do modelo de banco de dados Confirmation Confirmação Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. Foram detectadas modificações nas definições de papel/margem do modelo que podem provocar a impressão incorreta dos objetos. Deseja prosseguir com a impressão usando as novas configurações? Para usar as configurações padrão clique em 'Não', ou em 'Cancelar' para abortar a impressão. Load model Carregar modelo This action will open a web browser window! Want to proceed? Esta ação abrirá uma janela do navegador de internet! Deseja prosseguir? Ctrl+H F10 Saving temp. models Toogle the model validation widgets &Validation Alt+V Toggle the object finder Find Object Ctrl+F Toggle the operation history widget &Operations Alt+O Toggle the model objects widget O&bjects Alt+B He&lp Pl&ugins General Geral Controls &New New model &Save &Zoom in Zoo&m out &Load Sa&ve as E&xit Exit pgModeler &About pgModeler F4 &Print Print model &Undo Undo operation &Redo Redo operation &Export &Exportar Export the current opened model in different modes Ctrl+Shift+E &Show grid &Close &Fechar Close current model &Normal zoom &Align to grid Show &delimiters &Settings Edit pgModeler settings F12 &Overview &Support Access the support page New object Novo objeto Access the list of loaded plugins &Recent Models Load recently opened model &Import Import existing database to new model (reverse engineering) Ctrl+Shift+I Rest&ore Session &Fix a model New version found! Update for the current version is available on project's site &Check for update action_main_menu Main menu Show expanded Expands the main menu bar in classical mode Hide main menu Hides the main menu bar and put the action on a separated action Ctrl+Shift+H &Diff Ctrl+Shift+D Welcome Welcome screen Shift+W Design Design database models Shift+D Manage Manage existent databases Shift+M &Bug report Report a bug Donate Help pgModeler by donating! Objects me&tadata Objects metadata (Demo) Save modified model(s) The following models were modified but not saved: %1. Do you really want to quit pgModeler? Clear Menu The demonstration version can create only `one' instance of database model! The model <strong>%1</strong> was modified! Do you really want to close without save it? Warning You're running a demonstration version! The model saving feature is available only in the full version! <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! It's recommended to validate it before save in order to create a consistent model otherwise the generated file will be broken demanding manual fixes to be loadable again! Save anyway Validate <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the export process it's recommended to validate in order to correctly create the objects on database server! Export anyway <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the diff process it's recommended to validate in order to correctly analyze and generate the difference between the model and a database! Diff anyway Could not load the database model file `%1'. Check the error stack to see details. You can try to fix it in order to make it loadable again. Fix model Cancel Cancelar Access support page (no samples found) You're running a demonstration version! Note that you'll be able to create only <strong>%1</strong> instances of each type of object and some key features will be disabled or limited!<br/><br/>You can purchase a full binary copy or get the source code at <a href='http://pgmodeler.com.br'>pgmodeler.com.br</a>. <strong>NOTE:</strong> pgModeler is an open source software, but purchasing binary copies or providing some donations will support the project and cover all development costs.<br/><br/> <strong>HINT:</strong> in order to test all features it's recommended to use the <strong>demo.dbm</strong> model located in </strong>Sample models</strong> at <strong>Welcome</strong> view.<br/><br/><br/><br/> save export diff Executing pending <strong>%1</strong> operation... Determine the changes between model/database and another database Arrange objects Rearrange objects over the canvas Grid Hierarchical Scattered Rearrange objects over the canvas is an irreversible operation! Would like to proceed? Messagebox Dialog Diálogo msg Exceptions Exceções Show raw text errors or information. Show/hide exceptions stack. ... &Yes &Sim &No &Não Cancel Cancelar &Ok &Cancel &Cancelar Error Erro Alert Alerta Information Informação Confirmation Confirmação MetadataHandlingForm Handle metadata &Apply &Aplicar &Cancel &Cancelar Handle objects metadata Settings Extract from: Loading a metadata file to the current model is an irreversible operation so be sure to specify a backup file before proceed. Options Handles the following database model attributes in the metadata file: author, zoom factor, last position and default objects. Database model metadata Handles the objects' positioning in the metadata file. Objects' positioning Handles the objects' custom colors in the metadata file. Currently available only for relationships and schemas. Custom object's colors Handles the objects' protection status in the metadata file. Objects' protection status Handles the objects' SQL disabled status in the metadata file. Objects' SQL disabled status Handles the objects' custom SQL commands in the metadata file. Custom SQL commands Textbox objects Tag objects Backup file: Select file ... Apply to: Operation: Output Progress label... Rótulo de progresso... model not saved yet The backup file cannot be the same as the input model! Extracting metadata to file `%1' Saving backup metadata to file `%1' Applying metadata from file `%1' Metadata processing aborted! Objects metadata file (*.omf);;All files (*.*) Handles the objects' fade out status in the metadata file. Objects' fade out status Save tags to the output file when extracting metadata. When loading the file, the tags are recreated and duplicated ones are ignored. Save textboxes to the output file when extracting metadata. When loading the file, the textboxes are recreated and duplicated ones are ignored. Handles the tables' and views' extended attributes display status in the metadata file. Tables' extended attributes display Save generic SQL objects to the output file when extracting metadata. When loading the file, the objects are recreated and duplicated ones are ignored. Generic SQL objects Extracts the objects' metadata from the loaded models and apply to the current focused model. A backup file can be specified to where the focused model's current metadata will be saved. &Extract and restore Extracts the objects metadata from one of the loaded models saving the info to a backup file. Extract &only Reads the objects' metadata from a previously saved backup file and apply to the current model. &Restore a backup file ModelDatabaseDiffForm Settings Connection: Conexão: Database: Ignores as many as possible errors on import step. This option generates an incomplete diff. Ignore import errors Clears the data of all tables which will have columns modified. This is useful to avoid errors related to type casting. <strong>WARNING:</strong> DO NOT use this option on production servers and always make a backup before use it. Import system (built-in) objects. Use this if the import step is returning errors related to missing objects. Import system objects Import objects created by extensions. Use this if the import step is returning errors even importing built in ones. Import extension objects For DROP command, the objects that depends on an object to be dropped will be deleted as well. For TRUNCATE command, tables that are linked to a table to be truncated will be truncate too. <strong>NOTE:</strong> this option can affect more objects than listed in the output or diff preview. Drop or truncate in cascade mode Permissions already set on database objects will be kept.The ones configured on the model will be applied to the database. Keep object's permissions Database cluster level objects like roles and tablespaces will not be dropped. Keep cluster objects Recreate only unmodifiable objects Instead of use an ALTER command to modify certain kind of objects a DROP and CREATE will be used in order to do a full modification. This option does not affects the database object. Force recreation of objects Ignores errors generated by duplicated objects when exporting the diff to database. Ignore duplicity errors Serial columns are converted to integer and having the default value changed to <strong>nextval(sequence)</strong> function call. By default, a new sequence is created for each serial column but checking this option sequences matching the name on column's default value will be reused and will not be dropped. Reuse sequences on serial columns No command to rename the destination database will be generated even the model's name differ from database name. Preserve database name Avoid the generation of DROP commands for objects that exists in database but not in the model. This is useful when diff a partial model against the complete database. Do not drop missing objects Diff mode Override the PostgreSQL version when generating the diff. The default is to use the same version as the input database. Use PostgreSQL: Compares the model and the input database storing the diff in a SQL file for later usage. Store in S&QL file File: Arquivo: Select output file ... Compares the model and the input database generating a diff and applying it directly to the latter. <strong>WARNING:</strong> this mode causes irreversible changes on the database and in case of failure the original structure is not restored, so make sure to have a backup before proceed. Appl&y on server Output Changes: Cancel Cancelar Progress label... Rótulo de progresso... Step label... <html><head/><body><p>Objects marked with an <span style=" font-weight:600;">ALTER</span> may not be effectively changed unless that the differences detected are in attributes that can be modified through ALTER commands otherwise no operationwill be performed or, if the force recreation is checked, the object will be dropped and created again.</p></body></html> Objects to be created 0 Objects to be dropped Possible objects to be changed Ignored objects (system ones or with sql disabled) Diff Preview &Apply diff &Generate &Close &Fechar Waiting process to start... Confirmation Confirmação <strong>WARNING:</strong> The generated diff is ready to be exported! Once started this process will cause irreversible changes on the database. Do you really want to proceed? Apply diff Preview diff Diff process paused. Waiting user action... Saving diff to file <strong>%1</strong> Diff process sucessfully ended! No operations left. Operation cancelled by the user. Process aborted due to errors! -- SQL code purposely truncated at this point in demo version! -- No differences were detected between model and database. -- Error code <strong>%1</strong> found and ignored. Proceeding with export. Save diff as... SQL code (*.sql);;All files (*.*) Código SQL (*.sql);;Todos os Arquivos (*.*) Diff tool Generate diff code Source database Current model: (model) Compare to Diff Froce the generation of DROP commands for columns and constraints that exist in database but not in the model. This is useful when diff a partial model against the complete database and the user needs to drop columns and constraint but preserve the rest of the objects. Drop missing columns and constraints Truncate tables before alter columns Import && Export Import Export Exportar This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes model not saved yet (none) Step %1/%2: Importing database <strong>%3</strong>... Step %1/%2: Comparing <strong>%3</strong> and <strong>%4</strong>... Step %1/%2: Exporting diff to database <strong>%3</strong>... ModelExportForm File: Arquivo: Select target file Selecionar arquivo de destino ... PostgreSQL: PostgreSQL version in which the SQL code should be generated Versão do PostgreSQL no qual o código SQL deve ser gerado Show grid Mostrar grade Connection: Conexão: Ignore object duplicity Ignorar duplicidade de objetos Progress label... Rótulo de progresso... &Export &Exportar &Close &Fechar Initializing model export... Iniciando exportação do modelo... Saving file '%1' Salvando arquivo '%1' Exporting process sucessfuly ended! Processo de exportação finalizado com sucesso! Export model as... Exportar modelo como... Export model Settings Database server pgModeler ignores errors generated by duplicated objects and creates only that ones which does not exists in the database. This option may be used when an object was created after a previous model export. PostgreSQL version in which the SQL code should be generated. It is recommended to select this option only when the version of the DBMS, somehow, is not identifiable or if you need to generate a specific version of SQL code for test purposes. If <strong>DB</strong> is checked pgModeler will destroy the database if already exists on the server. When <strong>Objects</strong> is checked pgModeler will execute the DROP command attached to SQL-enabled objects. <strong>WARNING:</strong> this option leads to data loss so make sure to have a backup first. Drop: DB Ob&jects pgModeler will destroy the database if already exists on the server. Make sure to have a backup before use this option because all data will be lost. Graphics file Type: Tipo: Zoom: Show delimiters Exporting the model page by page will generate files with a <strong>_p[n]</strong> suffix where <strong>n</strong> is the page id. Check if the current user has write permission on output folder. Page by page SQL file Output Cancel Cancelar Error code <strong>%1</strong> found and ignored. Proceeding with export. Exporting process aborted! SQL script (*.sql);;All files (*.*) Portable Network Graphics (*.png);;All files (*.*) Scalable Vector Graphics (*.svg);;All files (*.*) Exporting process canceled by user! This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes I&mage (PNG) &Vectorial (SVG) ModelExportHelper Generating SQL code for PostgreSQL `%1' Output SQL file `%1' successfully written. Rendering objects to page %1/%2. Output image `%1' successfully written. Exporting model to SVG file. SVG representation of database model SVG file generated by pgModeler Output file `%1' successfully written. Starting export to DBMS. PostgreSQL version detection overridden. Using version `%1'. PostgreSQL `%1' server detected. Generating temporary names for database, roles and tablespaces. Enabling the SQL code for database `%1' to avoid errors. Ignoring object duplication errors. Ignoring the following error code(s): `%1'. Trying to drop database `%1'. Simulation mode activated. Creating object `%1' (%2) Creating database `%1' Connecting to database `%1' Generating SQL for `%1' objects... Destroying objects created on the server. Restoring original names of database, roles and tablespaces. Renaming `%1' (%2) to `%3' Dropping object `%1' (%2) Changing object `%1' (%2) Running auxiliary command. ModelFixForm Model file fix Fix model file <html><head/><body><p>[pgmodeler-cli not found error]</p></body></html> pgmodeler-cli: Browse for pgmodeler-cli tool ... The specified file is not the pgModeler command line tool (pgmodeler-cli). Input file: Output file: Fix tries: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Waiting process to start...</span></p></body></html> Select input file Select output file Load fixed model when finish In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. <strong>NOTE:</strong> relationships may lost their graphical configuration like custom points and line color. &Fix &Close &Fechar Waiting process to start... Could not locate <strong>%1</strong> tool on <strong>%2</strong>. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below. pgModeler command line tool (%1) ModelNavigationWidget Form Formulário Previous model Ctrl+Left Ctrl+Esquerda Next model Ctrl+Right Ctrl+Direita Close model Fechar modelo ... Alt+C (model not saved yet) ModelObjectsWidget Model Objects Objetos do Modelo 1 Object Objeto Type Tipo Parent Object Objeto Pai Parent Type Tipo Pai Select All Selecionar Todos Clear All Desselecionar Todos Select Selecionar Cancel Cancelar Objects view configuration Configuração da visão de objetos ... Tree view Visão em árvore List view Visão em lista Expands all items Expandir todos os itens Collapses all items Recolher todos os itens New Novo Hide this widget ID Return Esc Filter: By ID Visible object types Model objects ModelOverviewWidget Model overview Visão geral do modelo Failed to generate the overview image. The requested size %1 x %2 was too big and there was not enough memory to allocate! ModelRestorationForm Model restoration Restauração de modelos &Restore &Restaurar &Cancel &Cancelar pgModeler was not closed properly in a previous execution and some models were still being edited. Click <strong>Restore</strong> to reopen the models or <strong>Cancel</strong> to abort the restoration. pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler. Keep temporary models in case of restoration failure Database Banco de Dados File Arquivo Modified Size ModelValidationHelper There are pending errors! SQL validation will not be executed. Operation canceled by the user. ModelValidationWidget Form Formulário Hide this widget ... Enables the validation of SQL code in DBMS. This process requires the use of a pre-configured connection. SQL validation will occur only in the last step (when all objects were validated) or when there are no warnings. SQL Validation: Connection to be used in the SQL validation PostgreSQL version pgModeler will generate unique and temporary names for database, role and tablespace objects. This option avoids object duplication errors when running the SQL validation. Use unique temporary names for cluster level objects Clear validation results Clear Try to resolve the reported issues. Ctrl+S Change the creation order for two objects by swapping their ids Va&lidate Warnings: does not prevents model to be saved. 0 Errors: model will not be saved while there are validation errors. Cancel the SQL validation in progress. Cancel Cancelar Esc Try to apply a fix on the selected validation info. Options Autodetect The object <strong>%1</strong> <em>(%2)</em> [id: %3] is being referenced by <strong>%4</strong> object(s) before its creation. The object <strong>%1</strong> <em>(%2)</em> [id: %3]%4 is referencing columns created by <strong>%5</strong> relationship(s) but is created before them. The object <strong>%1</strong> <em>(%2)</em> has a name that conflicts with <strong>%3</strong> object's name(s). The relationship <strong>%1</strong> [id: %2] is in a permanent invalidation state and needs to be relocated. SQL validation failed due to error(s) below. <strong>NOTE:</strong><em> These errors does not invalidates the model but may affect operations like <strong>export</strong> and <strong>diff</strong>.</em> <strong>HINT:</strong> try to swap the relationship by another ones that somehow are linked to it through generated columns or constraints to solve this issue. Note that other objects may be lost in the swap process. <em>The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!</em> Conflicting object: <strong>%1</strong> <em>(%2)</em>. Relationship: <strong>%1</strong> [id: %2]. Referrer object: <strong>%1</strong> <em>(%2)</em> [id: %3]. SQL validation not executed! No connection defined. Database model successfully validated. Running SQL commands on server... Processing object: %1 Apply fixes Swap ids The column <strong>%1</strong> on <strong>%2</strong> <em>(%3)</em> is referencing the geospatial data type <strong>%4</strong> but the <strong>postgis</strong> extension is not present in the model! <strong>HINT:</strong> Create the extension in the model or let it be created by applying the needed fixes. ModelWidget Copy Copiar Source code Código fonte Show object source code Mostra o código fonte do objeto Properties Propriedades Edit the object properties Edita as propriedades do objeto Protect Proteger Unprotect Desproteger Protects object(s) from modifications Protege objeto(s) contra modificações Delete Apagar Select all Selecionar todos Selects all the graphical objects in the model Seleciona todos os objetos gráficos no modelo Paste Colar Cut Recortar Add a new object in the model Adiciona um novo objeto no modelo Rename Renomear Quick rename the object Renomear rapidamente o objeto Move to schema Mover para o esquema Edit permissions Editar permissões Change owner Mudar proprietário Select children Selecionar filhos Loading database model Carregando modelo de banco de dados Saving database model Salvando modelo de banco de dados Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. Copiar também todas dependências dos objetos selecionados? Isso minimiza a quebra de referências quando os objetos copiados forem colados em outro modelo. Pasting objects... Colando objetos... Not all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! Nem todos objetos foram colados ao modelo devido a erros retornados durante o processo! Consulte a pilha de erros para mais detalhes! Do you really want to delete the selected object? Deseja realmente apagar o objeto selecionado? (no objects) (sem objetos) Constraints Restrições One to One (1-1) One to Many (1-n) Many to Many (n-n) Inheritance <strong>ATTENTION:</strong> The database model is protected! Operations that could modify it are disabled! Source Alt+S Space Del Del. cascade Shift+Del Ctrl+A Convert Ctrl+C Ctrl+V Ctrl+X Deps && Referrers New Novo Quick Quick action for the selected object F2 Set tag Ctrl+E Open relationship Custom SQL Alt+Q Convert to sequence Convert to serial Break line Remove points Enable SQL Disable SQL 90° (vertical) 90° (horizontal) 90° + 90° (vertical) 90° + 90° (horizontal) Zoom: %1% Do you really want to convert the relationship into an intermediate table? Do you want to %1 the selected schema's children too? protect unprotect Validating object: `%1' (%2) Generating XML for: `%1' (%2) Pasting object: `%1' (%2) <strong>CAUTION:</strong> You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed? <strong>CAUTION:</strong> Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? <strong>CAUTION:</strong> Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details. Edit data Select tagged Select Selecionar Duplicate Ctrl+D Extended attributes Show Exibir Hide Jump to table Schemas rectangles Fade in/out Fade in Fade out Relationships Swap ids Edit the objects creation order by swapping their ids All objects Schemas Tables Tabelas Views Textboxes None ModelsDiffHelper Processing object `%1' (%2)... Skipping object `%1' (%2)... Processing diff infos... Processing `%1' info for object `%2' (%3)... No differences between the model and database. Preparing diff code... NewObjectOverlayWidget Form Formulário Tag Cast A Textbox Caixa de Texto Tablespace Espaço de Tabela Schema Esquema Language Linguagem Role Papel Event Trigger Domain Domínio Conversion Aggregate Collation Intercalação Table Tabela Type Tipo Op. Family Sequence Extension Function Função View Permissions Permissões Op. Class Operator Operador Constraint Restrição Column Coluna Index Índice Trigger Gatilho Rule Regra Many-to-many One-to-many One-to-one Inheritance Copy Copiar G K H J D E F L O U I R S Q T P M Y W 9 Z X C V B 1 2 3 5 4 0 Generic SQL Policy 8 NumberedTextEditor Upper case Lower case Ident right Ident left Load Carregar Load the object's source code from an external file Edit Editar Edit the source code in the preferred external editor Clear SQL file (*.sql);;All files (*.*) Load file The source editor `%1' is running on `pid: %2'. Could not start the source code editor application `%1'! Make to sure that the source editor path defined in the general settings points to a valid executable and the current user has permission to run the application. Error message returned: `%2' ObjectDepsRefsWidget Dependencies Dependências Object Objeto Type Tipo Parent Object Objeto Pai Parent Type Tipo Pai References Referências Object's dependencies & references ID Exclude indirect dependencies Include indirect references This object does not exists anymore. The dependencies and references listing are disabled. ObjectFinderWidget Form Formulário Pattern: Defines the search filter Filter Clears the search results Clear ... Hide this widget Regular Expression Exact Match Select All Clear All Case Sensitive ID Object Objeto Type Tipo Parent Object Objeto Pai Parent Type Tipo Pai Find Found <strong>%1</strong> object(s). No objects found. (Un)selects the graphical objects in the results grid Select Selecionar Fades outs all the graphical objects in the results grid (or those not listed). The current fade in/out state of all objects is modified. Fade out Listed Not listed ObjectRenameWidget Form Formulário .... to: para: Rename Renomear Cancel Cancelar ObjectSelectorWidget Form Formulário Clear field Limpar campo Select Object Selecionar Objeto Select %1 ObjectsTableWidget Form Formulário Add Item Adicionar Item Ins Remove Item Remover Item Del Update Item Atualizar Item Alt+R Remove All Shift+Del Duplicate item Ctrl+D Edit Item Editar Item Space Move Up Mover para cima Ctrl+Up Move Down Mover para baixo Ctrl+Down Move to start Mover para o início Ctrl+Home Move to end Ctrl+End, Ctrl+S Confirmation Confirmação Do you really want to remove the selected item? Do you really want to remove all the items? OperationList (invalid object) OperationListWidget Executed Operations Operações Executadas 1 Operations: Operações: 0 Position: Posição: Delete operation history Apagar histórico de operações Undo Desfazer Redo Refazer Object: %1 Objeto: %1 Name: %1 Nome: %1 created criado removed removido modified modificado moved movido Operation: %1 Operação: %1 Operation history exclusion Exclusão de histórico de operações Delete the executed operations history is an irreversible action, do you want to continue? Apagar o histórico de operações executadas é uma ação irreversível, deseja realmente prosseguir? Hide this widget ... OperatorClassWidget Default Class: Classe Padrão: Indexing: Indexação: Elements Elementos Operator Operador Function Função Storage Armazenamento Function: Função: Operator: Operador: Support/Strategy: Suporte/Estratégia: Storage Type Tipo de Armazenamento Object Objeto Type Tipo Support/Strategy Suporte/Estratégia Element Type: Tipo de Elemento: Op. Family: Família de Op.: Operator Family Família de Operadores OperatorFamilyWidget Indexing: Indexação: OperatorWidget HASHES Options: Opções: MERGES Arguments Argumentos Join: Junção: Right Argument Type Tipo Argumento Direita Left Argument Type Tipo Argumento Esquerda To create a unary operator it is necessary to specify as <strong><em>'any'</em></strong> one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator. Para criar um operador unário é necessário especificar como <strong><em>'any'</em></strong> um de seus argumentos. Adicionalmente, a função que define o operador deve possuir apenas um parâmetro e este, por sua vez, deve ter o tipo de dado igual ao tipo de dado do argumento do operador unário. Advanced Avançado Restrict: Restrito: Negator: Negador: Operator Func.: Fun. Operador: Commutator: ParameterWidget Default Value: Valor Padrão: Mode: Modo: IN OUT VARIADIC PermissionWidget Roles Papéis ID: Permissions Permissões Add Permission Adicionar Permissão Update Permission Atualizar Permissão Cancel Operation Cancelar Operação Privileges Privilégios Privilege Privilégio GRANT OPTION Id Disable SQL code Desabilitar código SQL Cascade Cascata Edit permissions Editar permissões &Grant Re&voke Code Preview Previsão de Código -- No permissions defined for the specified object! /* Could not generate the SQL code preview for permissions! Name Nome Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. PgModelerCLI Unrecognized option '%1'. Opção '%1' não reconehcida. Value not specified for option '%1'. Valor não specificado para a opção '%1'. Option '%1' does not accept values. Opção '%1' não aceita valores. Usage: pgmodeler-cli [OPTIONS] Uso: pgmodeler-cli [OPÇÕES] command line interface. interface da linha de comando. DBMS export options: Opções da exportação SGBD: Input file must be different from output! Arquivo de entrada deve ser diferente do de saída! Incomplete connection information! Informação de conexão incompleta! Starting model export... Iniciando exportação de modelo... General options: PNG and SVG export options: Miscellaneous options: There are no connections configured. Invalid zoom specified! Invalid action specified to update mime option! Starting model fixing... Starting mime update... Model successfully fixed! Extracting objects' XML... Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted! Recreating objects... ** Object(s) that couldn't fixed: WARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2) Database model files (.dbm) are already associated to pgModeler! There is no file association related to pgModeler and .dbm files! Mime database operation: %1 Can't erase the file %1! Check if the current user has permissions to delete it and if the file exists. Running update-mime-database command... Connection aliased as '%1' was not found in the configuration file. PostgreSQL Database Modeler Project - pgmodeler.io Copyright 2006-2018 Raphael A. Silva <raphael@pgmodeler.io> This CLI tool provides several operations over models and databases without the need to perform them in pgModeler's graphical interface. All available options are described below. %1, %2 [FILE] Input model file (.dbm). This is mandatory for fix, export operations. %1, %2 [DBNAME] Input database name. This is mandatory for import operation. %1, %2 [FILE] Output file. This is mandatory for fixing model or exporting to file, png or svg. %1, %2 Try to fix the structure of the input model file in order to make it loadable again. %1, %2 [NUMBER] Model fix tries. When reaching the maximum count the invalid objects will be discarded. %1, %2 Export the input model to a sql script file. %1, %2 Export the input model to a png image. %1, %2 Export the input model to a svg file. %1, %2 Export the input model directly to a PostgreSQL server. %1, %2 Import a database to an output file. %1, %2 Compares a model and a database or two databases generating the SQL script to synch the latter in relation to the first. %1, %2 Force the PostgreSQL version of generated SQL code. %1, %2 Silent execution. Only critical messages and errors are shown during process. %1, %2 Show this help menu. Connection options: %1, %2 List available connections in file %3. %1, %2 [ALIAS] Connection configuration alias to be used. %1, %2 [HOST] PostgreSQL host in which a task will operate. %1, %2 [PORT] PostgreSQL host listening port. %1, %2 [USER] PostgreSQL username. %1, %2 [PASSWORD] PostgreSQL user password. %1, %2 [DBNAME] Connection's initial database. %1, %2 Draws the grid in the exported image. %1, %2 Draws the page delimiters in the exported image. %1, %2 Each page will be exported in a separated png image. (Only for PNG images) %1, %2 [FACTOR] Applies a zoom (in percent) before export to png image. Accepted zoom interval: %3-%4 (Only for PNG images) %1, %2 Ignores errors related to duplicated objects that eventually exist in the server. %1, %2 [CODES] Ignores additional errors by their codes. A comma-separated list of alphanumeric codes should be provided. %1, %2 Drop the database before execute a export process. %1, %2 Runs the DROP commands attached to SQL-enabled objects. %1, %2 Simulates an export process by executing all steps but undoing any modification in the end. %1, %2 Generates temporary names for database, roles and tablespaces when in simulation mode. Database import options: %1, %2 Ignore all errors and try to create as many as possible objects. %1, %2 Import system built-in objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Import extension objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Run import in debug mode printing all queries executed in the server. Diff options: %1, %2 [DBNAME] The database used in the comparison. All the SQL code generated is applied to it. %1, %2 Save the generated diff code to output file. %1, %2 Apply the generated diff code on the database server. %1, %2 Don't preview the generated diff code when applying it to the server. %1, %2 Drop cluster level objects like roles and tablespaces. %1, %2 Revoke permissions already set on the database. New permissions configured in the input model are still applied. %1, %2 Drop missing objects. Generates DROP commands for objects that are present in the input model but not in the compared database. %1, %2 Force the drop of missing columns and constraints. Causes only columns and constraints to be dropped, other missing objects aren't removed. %1, %2 Rename the destination database when the names of the involved databases are different. %1, %2 Don't drop or truncate objects in cascade mode. %1, %2 Truncate tables prior to alter columns. Avoids errors related to type casting when the new type of a column isn't compatible to the old one. %1, %2 Don't reuse sequences on serial columns. Drop the old sequence assigned to a serial column and creates a new one. %1, %2 Don't force the recreation of objects. Avoids the usage of a DROP and CREATE commands to create a new version of the objects. %1, %2 Don't recreate the unmodifiable objects. These objects are the ones which can't be changed via ALTER command. %1, %2 [ACTION] Handles the file association to .dbm files. The ACTION can be [%3 | %4]. ** The diff process allows the usage of the following options related to import and export operations: * Export: * Import: ** When running the diff using two databases (%1 and %2) there's the need to specify two connections/aliases. If only one connection is set it will be used to import the input database as well to retrieve database used in the comparison. A second connection can be specified by appending a 1 on any connection configuration parameter listed above. Available connections (alias : connection string) No operation mode was specified! Export, fix model, import database, diff and update mime operations can't be used at the same time! Multiple export mode was specified! No input file was specified! No input database was specified! No output file was specified! No input file or database was specified! The input file and database can't be used at the same time! No database to be compared was specified! No diff action (save or apply) was specified! No output file for the diff code was specified! ** Error code `%1' found and ignored. Proceeding with export. ** Command: %1 Loading input file: %1 Fixed model file: %1 Export to PNG image: %1 Export to SVG file: %1 Export to SQL script file: %1 Export to DBMS: %1 Export successfully ended! Starting database import... Input database: %1 Saving the imported database to file... Import successfully ended! Starting diff process... Input model: %1 Compare to: %1 Loading input model... Importing the database `%1'... Comparing the generated models... No differences were detected. Saving diff to file `%1' ** WARNING: You are about to apply the generated diff code to the server. Data can be lost in the process! ** Proceed with the diff applying? (yes/no) > yes no Diff code not applied to the server. Applying diff to the database `%1'... Diff successfully ended! Mime database successfully updated! PgModelerPlugin Plugin Information Informação do Plugin Version: %1 Versão: %1 Author: %1 Autor: %1 PgModelerUiNS Do you want to apply the <strong>SQL %1 status</strong> to the object's references too? This will avoid problems when exporting or validating the model. disabling enabling PgSQLTypeWidget Form Formulário Data Type Tipo de Dado SRID: Variation: Variação: Z M Precision Precisão Spatial: Espacial: Dimension Dimensão Format: Formato: Timezone: Fuso horário: Type: Tipo: P: Length Comprimento L: Interval: Intervalo: [ ]: NONE PluginsConfigWidget Form Formulário Plug-ins root directory: Diretório raiz de plugins: Open in file manager Abrir gerenciador de arquivos Loaded plug-ins Plugins carregados Plugin Version Versão Library Biblioteca PolicyWidget Basics Command: Permissive Roles Papéis Expressions USING: CHECK: Name Nome Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. QObject new_database novo_banco_de_dados %1 (line: %2) %1 (linha: %2) Relationship %1_has_one_%2 %1_tem_um_%2 %1_has_many_%2 %1_tem_muitos_%2 many_%1_has_many_%2 muitos_%1_tem_muitos_%2 %1_inherits_%2 %1_herda_de_%2 %1_copies_%2 %1_copia_de_%2 RelationshipConfigWidget Form Formulário Connection Mode Connect FK to PK columns Connect tables' center points FK Settings && Patterns Foreign key settings Deferral: Postergação: Deferrable: Postergável: ON DELETE: ON UPDATE: Name patterns Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Foreign Key (Source): Relationship type: Pattern for columns generated based upon target table's pk (n-n). Column (Target): One to one (1:1) One to many (1:n) Many to many (n:n) Generalization Generalização Copy Copiar Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Column (Source): Pattern for foreign key generated based upon target table's pk (n-n). Foreign Key (Target): Pattern for unique key generated by the relationship. Unique Key Name: Pattern for primary key generated by identifier relationship. Primary Key Name: Primary Key Column: Default Padrão This mode renders the relationships in crow's foot notation which has a better semantics and readability. It also determines the optimal point where the relationship is connected on the tables' edges taking their position into account. Crow's foot notation This mode determines the optimal point where the relationship is connected on the tables' edges taking their position into account. It implies the usage of the classical ER notation. Connect tables' edges This mode is available only for <strong>one-to-one</strong>, <strong>one-to-many</strong> and <strong>fk relationships</strong> but provides a better semantics when linking tables by placing the lines on the exact point where the relationship occurs. It implies the usage of the classical ER notation. This mode is the classical one. It connects the relationship to tables through their central points. It implies the usage of the classical ER notation. RelationshipWidget General Geral One to one relationship Relacionamento de um para um One to many relationship Relacionamento de um para muitos 1-n Many to many relationship Relacionamento de muitos para muitos n-n Generalization relationship (inheritance) Relacionamento de generalização (herança) Dependency / Copy relationship Relacionamento de Dependência / Cópia dep Relationship generated via foreign key Relacionamento gerado via chave estrangeira fk Identifier Identificador Table 1: Tabela 1: Table 2: Tabela 2: Cardinality: Cardinalidade: [SRC] is required [SRC] é requerido [DST] is required [DST] é requerido Name of the table generated from many to many relationship Nome da tabela gerada pelo relacionamento muitos para muitos Deferrable: Postergável: Deferral: Postergação: Attributes Atributos Constraints Restrições Primary key Chave primária Advanced Avançado Attribute Atributo Type Tipo Constraint Restrição Name Nome This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables. Esta aba avançada mostra os objetos (colunas ou tabela) auto criados pela conexão do relacionamento, bem como as chaves estrangeiras que representam a ligação entre as tabelas participantes. is required é requerido Reference Table: Tabela Referência: Receiver Table: Tabela Receptora: Copy Options Opções de Cópia INDEXES COMMENTS INCLUDING DEFAULTS CONSTRAINTS Use defaults Usar padrões ALL STORAGE Name Patterns Use the values defined on settings dialogs for the fields below Use global settings for these fields Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Column (Source): Pattern for columns generated based upon target table's pk (n-n). Column (Target): Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Foreign Key (Source): Pattern for foreign key generated based upon target table's pk (n-n). Foreign Key (Target): Pattern for primary key generated by identifier relationship. Primary Key Name: Pattern for unique key generated by the relationship. Unique Key Name: Primay Key Column: Gen. Table Name: Rel. Type: Foreign key Settings ON DELETE: ON UPDATE: &1-1 &gen The receiver's primary key will be composed by the generated foreign key columns. Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key. Single PK column Custom Color: E&XCLUDING Use the special primary key if you want to include a primary key containing generated columns to the receiver table. <strong>Important:</strong> if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key. Available tokens to define name patterns:<br/> <strong>%1</strong> = Reference (source) primary key column name. <em>(Ignored on constraint patterns)</em><br/> <strong>%2</strong> = Reference (source) table name.<br/> <strong>%3</strong> = Receiver (destination) table name.<br/> <strong>%4</strong> = Generated table name. <em>(Only for n:n relationships)</em> Default Padrão Referer View: Referer view references one or more columns of a table to construct it's own columns. Referenced table has its columns referenced by a view in order to construct the columns of this latter. Referer Table: Referer table references one or more columns of a table through foreign keys. This is the (n) side of relationship. Referenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship. Referenced Table: Tab. Referenciada: Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship. Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship. In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table. ResultSetModel [binary data] RoleWidget Password: Senha: Connections: Conexões: Attributes Atributos Superuser Superusuário Members Membros Member of Membro de Members (Admin.) Membros (Admin.) Role Papel Validity Validade Encrypted Encriptado yyyy-MMM-dd hh:mm:ss Assigning <strong><em>-1</em></strong> to <strong><em>Connections</em></strong> creates a role without connection limit.<br/> Unchecking <strong><em>Validity</em></strong> creates an role that never expires. Inherit permissions Can create database Bypass RLS Can use replication Can login Can create role RuleWidget Event: Evento: Execution Type: Tipo Execução: Conditional Expr.: Expr. Condicional: SQL Command: Comando SQL: SQL command Comando SQL To create a rule that does not perform any action (<strong>DO NOTHING</strong>) simply do not specify commands in the SQL commands table. Para criar uma regra que não execute ação alguma (<strong>DO NOTHING</strong>) basta não especificar comandos na tabela de comandos SQL. Commands SQLExecutionWidget Form Formulário Save SQL commands Search in SQL code Alt+F Run the specified SQL command Run SQL F6 Clear sql input field and results Clear All Export results to a CSV file Snippe&ts E&xport Toggles the output pane &Output Alt+O Results ... Messages History SQL file (*.sql);;All files (*.*) [binary data] No results retrieved or changes done due to the error above. Messages (%1) Results (%1) Rows affected Rows retrieved Load SQL commands Save CSV file Comma-separated values file (*.csv);;All files (*.*) The SQL input field and the results grid will be cleared! Want to proceed? Copy selection Clear history Close the current SQL script SQL script currently handled (not saved) Handle external SQL script &Script Fi&nd Alt+T Alt+X Current working database Load Carregar Save Salvar Save as Salvar como [%1]: SQL command successfully executed in <em><strong>%2</strong></em>. <em>%3 <strong>%4</strong></em> Plain format CVS format This action will wipe out all the SQL commands history for all connections! Do you really want to proceed? Save history Reload history Find in history Hide find tool This action will wipe out all the SQL commands history for the current connection! Do you really want to proceed? SQLToolWidget Form Formulário Database explorer Disconnect from all databases ... Update the database list Toggle the object's attributes grid Attributes Atributos Alt+R Toggle the display of source code pane Source code SQL execution Warning <strong>ATTENTION:</strong> Disconnect from all databases will close any opened tab in this view! Do you really want to proceed? SceneInfoWidget Form Formulário Current position of the mouse in the canvas - Current zoom factor Currently selected object(s) Dimensions of the selected object(s) No selection N/A Sel. objects: %1 SchemaWidget Show rectangle Mostrar retângulo Fill color: Cor de preenchimento: SequenceWidget Cyclic: Cíclica: Start: Início: Maximum: Máximo: Minimum: Mínimo: Increment: Incremento: Cache: Cache: Owner Col.: Defualt values: User defined SnippetsConfigWidget Form Formulário Label: Applies to: ID: Create new connection Criar nova conexão Cancel edition Cancelar edição Edit selected connection Editar conexão selecionada Delete selected connection Remove All Shift+Del Snippets: Parse the snippet in order to check if there are syntax errors. Parse Add Adicionar Update Atualizar Parsable or dynamic snippets are written in the <strong>schema micro language</strong> syntax. When using a parsable snippet the attributes surrounded in <strong>{}</strong> will be replaced by the selected object's matching attributes. Parsable When handling parsable snippets empty attributes will be replaced by a value in the format <strong>{attribute}</strong>. Note that this option can affect the semantics of the resulting snippet. Placeholders Filter: General purpose All snippets /* Error parsing the snippet '%1': %2 */ Duplicated snippet id <strong>%1</strong> detected. Please, specify a different one! Invalid ID pattern detected <strong>%1</strong>. This one must start with at leat one letter and be composed by letters, numbers and/or underscore! Empty label for snippet <strong>%1</strong>. Please, specify a value for it! Empty code for snippet <strong>%1</strong>. Please, specify a value for it! The dynamic snippet contains syntax error(s). Additional info: <br/><em>%1</em> Do you really want to remove all snippets? No syntax errors found in the snippet. General Geral SourceCodeWidget Version: Versão: PostgreSQL iconecodigo íconecódigo SQL XML Source code visualization Visualização de código fonte Generating source code... Gerando código fonte... -- SQL code unavailable for this type of object -- -- Código SQL não disponível para este tipo de objeto. -- Code display: Original Original + depedencies' SQL Original + children's SQL Save the SQL code to a file. Save SQL <strong>Original:</strong> displays only the original object's SQL code.<br/><br/> <strong>Dependencies:</strong> displays the original code including all dependencies needed to properly create the selected object.<br/><br/> <strong>Children:</strong> displays the original code including all object's children SQL code. This option is used only by schemas, tables and views. Save SQL code as... SQL code (*.sql);;All files (*.*) Código SQL (*.sql);;Todos os Arquivos (*.*) -- NOTE: the code below contains the SQL for the selected object -- as well for its dependencies and children (if applicable). -- -- This feature is only a convinience in order to permit you to test -- the whole object's SQL definition at once. -- -- When exporting or generating the SQL for the whole database model -- all objects will be placed at their original positions. -- SQL code purposely truncated at this point in demo version! <!-- XML code preview disabled in demonstration version --> SwapObjectsIdsWidget Change objects creation order Create: ID: Before: Swap the values of the fields Swap values Change the objects creation order is an irreversible operation and cause the operations history to be automatically erased. Note that the creation order configured in this form is not definitive and may change after a model validation. Swap the object ids changing their creation order Swap ids Filter: ID Object Objeto Type Tipo Parent Object Objeto Pai Parent Type Tipo Pai Table new_table nova_tabela In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2' TableDataWidget Edit table data Add empty rows Ins Add an empty column Remove all rows from the grid preserving columns Shift+Del Delete the selected rows Del Duplicate the selected rows Ctrl+D Delete the selected columns Remove all columns (and rows) from the grid Ctrl+Shift+Del Delete columns is an irreversible action! Do you really want to proceed? Remove all rows is an irreversible action! Do you really want to proceed? Remove all columns is an irreversible action! Do you really want to proceed? Unknown column Duplicated column Copy items on the grid Copy Copiar Add row Delete column Paste items on the grid Paste Colar Ctrl+V Fills the grid using a CSV file <html><head/><body><p>Some invalid or duplicated columns were detected. In order to solve this issue double-click the header of the highlighted ones in order to define the correct name in which the data belongs to or delete the entire column. Note that these columns are completely ignored when generating the <span style=" font-weight:600;">INSERT</span> commands.</p></body></html> Add column Duplicate rows Change the values of all selected cells at once Bulk data edit Ctrl+E Delete all columns Delete rows <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> Delete all rows TableObjectView Relationship: %1 TableWidget Name Nome Type Tipo Default Value Valor Padrão ON DELETE ON UPDATE Refer. Table Tab. Refer. Firing Disparo Events Eventos Execution Execução Event Evento Indexing Indexação Schema Esquema Parent Pai Copy Copiar Options Tag: With OID Generate ALTER for columns/constraints Unlogged &Columns Co&nstraints Tri&ggers &Rules &Indexes &Tables Edit data Define initial data for the table Enable row level security Force RLS for owner &Policies PK Attribute(s) It is not possible to mark a column as primary key when the table already has a primary key which was created by a relationship! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. It is not possible to mark a column created by a relationship as primary key! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. Command Permissive USING expression CHECK expression Roles Papéis Yes Sim No Não TablespaceWidget Form Formulário Directory: Diretório: TagWidget Colors Body: Title: Schema name: Table name: Extended body: TaskProgressWidget Executing tasks Executando tarefas Waiting task to start... Aguardando a tarefa iniciar... TextboxWidget Bold Negrito Italic Itálico Underline Sublinhado Select text color Selecionar cor de texto Font: Fonte: Text pt Color: TriggerWidget Event: Evento: INSERT DELETE UPDATE TRUNCATE Deferrable: Postergável: Columns Colunas Column: Coluna: Arguments Argumentos Argument: Argumento: Function: Função: Column Coluna Type Tipo Constraint Restrição FOR EACH ROW Refer. Table: Tab. Refer.: Condition: Condição: Options: Opções: Excution: Execução: TypeWidget Configuration: Configuração: Base Type Tipo Base Enumeration Enumeração Enumerations Enumerações Enumeration: Enumeração: Attributes Atributos Internal Length: Comp. Interno: Storage: Armazenamento: Category: Categoria: Delimiter: Delimitador: Alignment: Alinhamento: char smallint integer double precision Default Value: Valor Padrão: Functions Funções INPUT: OUTPUT: RECV: SEND: TPMOD_IN: TPMOD_OUT: ANALYZE: Like Type Tipo Como Element Type Tipo Elemento Name Nome Type Tipo The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table> As funções a serem atribuídas ao tipo devem ser escritas em linguagem C, e possuírem respectivamente as seguintes assinaturas:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any funcao(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring funcao(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byte funcao(any)</em></td> <td><strong>RECV:</strong> <em>any funcao(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer funcao(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring funcao(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean funcao(internal)</em></td> <tr> </table> Range Extensão Options: Opções: By value Por valor Preferred Preferido Collatable Intercalável Name: Nome: Collation: Intercalação: Subtype Diff Func.: Fun. Dif. Subtipo: Operator Class: Classe de Operadores: Canonical Func.: Fun. Canônica: Subtype Subtipo Collation Intercalação The functions to be assigned to a range type should have the following signatures:<br/><br/><strong>Canonical:</strong> <em>any function(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision function(subtype, subtype)</em> As funções para serem atribuídas a um tipo extensão devem ter as seguintes assinaturas:<br/><br/><strong>Canônica:</strong> <em>any funcao(any)</em> <br/><strong>Dif. Subtipo:</strong> <em>double precision funcao(subtipo, subtipo)</em> Co&mposite UpdateNotifierWidget Update Notifier Update found! Hide this widget ... Released in: mmm dd, yyyy New version: 0.0.0 Changelog Redirects to purchase page. Get binary package Redirects to GitHub source repository. Get source code Failed to check updates No updates found You are running the most recent pgModeler version! No update needed. The update notifier failed to check for new versions! A HTTP status code was returned: <strong>%1</strong> The update notifier failed to check for new versions! Please, verify your internet connectivity and try again! Connection error returned: <em>%1</em> - <strong>%2</strong>. ViewWidget References Referências Column Coluna Expression Expressão Used in: Usado em: Table: Tabela: Table Alias: Apelido de Tabela: Column: Coluna: Column Alias: Apelido de Coluna: Expression: Expressão: Expression Alias: Apelido de Expressão: Code Preview Previsão de Código Col./Expr. Alias Apelido Alias Col. Apelido Col. Reference Type: Tipo Referência: View Definition Definição da Visão Triggers Gatilhos Rules Regras Table Expression Expressão de Tabela Name Nome Refer. Table Tab. Refer. Firing Disparo Events Eventos Execution Execução Event Evento /* Could not generate the SQL code. Make sure all attributes are correctly filled! /* Não foi possível gerar o código SQL. Certifique-se de que todos os atributos estejam corretamente preenchidos! Options Tag: Mode: Modo: Ordinary Recursi&ve &Materialized With no data The element will be used as part of the SELECT statement to retrieve columns or expressions that will compose the view's columns SELECT ... The element will be used as part of the WHERE clause in form of conditional expression WHERE ... The element is used in the FROM portion of the command in order to reference tables or construct JOIN statements FROM ... The element's expression is used exclusively as the view's definition The element will be appended to the very end of the view's definition. This is useful when using GROUP BY/HAVING statements End expression Indexes Índices Flags: SF FW AW EX VD To reference all columns in a table (*) just do not fill the field <strong>Column</strong>, this is the same as write <em><strong>[schema].[table].*</strong></em> Indexing Indexação WelcomeWidget Form Formulário New model Open model Sample models Recent models Last session pgmodeler-0.9.2/lang/zh_CN.qm000066400000000000000000002151301360462764600160010ustar00rootroot00000000000000nG'GII@QIByJ8OJJcJJMzaMzƼMz MzPS8PShPS TXT!TxTX\ Yqc]0_H_Bjq>t6$-$yZyyͷyy%S֍ ֍$֍6w֍< ֍E8֍FU֍n"֍|֍֍w֍c֍V֍֍֍5֍5֍ȭ֍:֍`֍i֍ڏ֍֍ݠ֍֍85t65tB5tٜH5=6H5DH5p*H5H5H5bH5H5H5%%%G%/%gB-{:zeWe2e@ eHdeqe6eee3eeԙeee|eį~  ytq9**W*%+g336v9;H5yT:ToTZ)TZTTE TVV6VWzYb>YbYbYbYu $YXZg6ZgZg)Zy%Zy%?Zy%Z,\\ʀ\Z.eA o-2oERtlkh^yxQaLoϋys|EvCᬱ5M=MMB9z <pu$!ayY$22uy8RYC^j^laQee$x{ywzQy|{yt^sdŀyvƠkcI j  QfD ?J O2 Z4؎S:eJ.lJZ(DQKXkyvaf>RxLDGXEv/i%!0w9w9%2w9\676@6&66^6VbR _nßs5s ~Ŗ*sŖQ**3A?Вq nًo1S[ys`<n3AP 8 6 C1[E/)h)h&3?UsVZywt1Tt1)`mi$UBՆ)ܸZh;#&Ìղ^:^|<MΔ$ΔΔWΔ ;yr(y` ˧&Ѥ(@N` $` Blu ^u I@IdIIIIIIb<><>0o<>7t<>n<>G<>d<>\,uZ* ɓ%H}ODu7'  8 9,GG~W:W47r7#Rl}M|ezHzzų&ų9v*v-АG;АG}АG+q  b3ZzQzt} $ h|VД8‰kʔF,N<,Nk/3 (2B~3H^3H3H3HE9'!d:ʔFI/UXAY Y Y &Y Y chlZVnLZnLZCzp3s̄!W{y{OH5>NH5H5v z j31V1>161++ +҅Z{yz29Tz5XQd"g3ƨ-ƨ@<ƨ޺gsqeѵuѵuŵp1K% T_-. <9V#CQYCZ>_pNgxwo dwo|M!KZjAiAH H/t/U!ltl;ȐȐ=iȐG'Ȑ]Ȑ!ɓ?`ɓn֣ے$ےeے6:8;Ȕ./N\1,23Ww5jO?:l,:;x=;BC+^G4GcJj0}w|6w|"ap'7ړ2fsBoI` CI` ` ` X` ` x^* rLf1e!k4 j;}Y~Sa'~+E+JG+J@/y@q/y֞8&9pU;zʴ5#Q.;Q.DQ.F"Q.ώnLO:۲ʁjL8I,nAsAAsDLAsnTAsAsAs(As_As@# TYz $R #i - %> - % - %ڽ 0M C_k Oy Oy; b+e e!g h> kJy vm |~3 v  9 C  k TO E Ee ʮ NJ19 NJ NJJ r ze _!Sj Z) j$פ ~ #N )`=_ *paf 6 G M(2# M(# M(M MJq T Z# ZB[ _1Q ci*` ci*z c0 c9 c cZ0 cZ7 cZE cZ cZ d.V e7; e g@ iH o^Ņ r3) r3 I I I%j I I I Q[ )Y y >, > _Cf ?* ' -D t:d tB- t tЫ  :+ z @  J Lu Rzq1 t t ɗ . δ δ v v ϩ8 ϩ8 ꚅd NR /*O $~` q Vzz ye*< ;l O~ \ hx* m{h wG { {5 {j h*      2AQ 9 Ϟ ݒ+ ݒG  > ` 6 dc P b Jg ( &m ͘1S ͠+ ͠u є% ѩU" ZA Z Z& 掺o J3 ^ 5 o K ,<; ,<E -8 - =h =\o @lO Jkcf J J  ܊0 D y Y #! QU $ C %ґ Ǩ zD AI ! 6; .*p D+^Ι V Me [*Y ] } i8: ^ ^ ^ ^ 8Ac /_% %h <& <+ <| < <M < إӒ @ ? )_ A UJ$JD{JJ!<*'Aa(q5JG3 KOlLNT-WGdi j[rwhsAN>{uiun[yw@xjgb 39 35 35  zZRi!J45A555Ps4&8I9tE`~ajMmQwvpmU$Nʯ`toPxY*( / 0^+1Lkys֣\֣\֣\v֣\c J]5w if 0.0.00.0.0 AboutWidgetQsN pgModelerAbout pgModeler AboutWidget$PostgreSQL epcn^^j!]QwPostgreSQL Database Modeler AboutWidgetlZTQepcS|{W <em><strong>typeA</strong></em> T <em><strong>typeB</strong></em> O\N:Qe|{W ^vN|{Wr`N: <em><strong>state_type</strong></em>, Qep_Ř{u_YN R<br/><br/> <strong> &nbsp;&nbsp;&nbsp; "g~YtQep</strong> <em>void final_function(<strong>state_type</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp; " n!YtQep</strong> <em><strong>state_type</strong> transition_function(<strong>state_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em>%An aggregate function that accepts the types typeA and typeB as input types and which type of state is state_type, must obey the following rules:

   • Final Function: void final_function(state_type)
   • Transition Function: state_type transition_function(state_type, typeA, typeB)AggregateWidgetg~YtQepFinal Function:AggregateWidgetQepr`Function StateAggregateWidgetQepQeFuntion InputsAggregateWidget Qeepcn|{WInput Data TypeAggregateWidget c^dO\{&Sort Operator:AggregateWidget r`epcn|{WState Data TypeAggregateWidgetpt ptAppearanceConfigWidget|OSBoldAppearanceConfigWidgetrColors:AppearanceConfigWidgetR(FK)RT yColumn (fk): Column nameAppearanceConfigWidgetR(FK)cϏ{&Column (fk): DescriptorAppearanceConfigWidgetR(NN)RT yColumn (nn): Column nameAppearanceConfigWidgetR(NN)cϏ{&Column (nn): DescriptorAppearanceConfigWidgetR(PK)RT yColumn (pk): Column nameAppearanceConfigWidgetR(PK)cϏ{&Column (pk): DescriptorAppearanceConfigWidgetR(UQ)RT yColumn (uq): Column nameAppearanceConfigWidgetR(UQ)cϏ{&Column (uq): DescriptorAppearanceConfigWidget RRT yColumn: Column nameAppearanceConfigWidget RcϏ{&Column: DescriptorAppearanceConfigWidgetRST+W(/~bQs|,Column: Included / Inherited by relationshipAppearanceConfigWidget RQObColumn: ProtectedAppearanceConfigWidgetQC} Element:AppearanceConfigWidget[WOSFont:AppearanceConfigWidgetFormFormAppearanceConfigWidgetQh\@~g_cϏ{&Global: Constraints descriptorAppearanceConfigWidgetQh\@[WOSh7_Global: Font styleAppearanceConfigWidget Qh\@sGlobal: Lock arcAppearanceConfigWidget Qh\@OSGlobal: Lock bodyAppearanceConfigWidgetQh\@[a bGlobal: Object selectionAppearanceConfigWidgetQh\@[a|{WGlobal: Objects typeAppearanceConfigWidgetQh\@OMncy:hFGlobal: Position hint boxAppearanceConfigWidgetQh\@OMncy:Q[Global: Position hint textAppearanceConfigWidget }"_cϏ{&Index: DescriptorAppearanceConfigWidget }"_T y Index: NameAppearanceConfigWidgeteOSItalicAppearanceConfigWidgetQs|\^`'cϏ{&"Relationship: Attribute descriptorAppearanceConfigWidgetQs|\^`'Q[Relationship: Attribute textAppearanceConfigWidget Qs|cϏ{&Relationship: DescriptorAppearanceConfigWidget Qs|h{~hFRelationship: Label boxAppearanceConfigWidgetQs|h{~Q[Relationship: Label textAppearanceConfigWidget RcϏ{&Rule: DescriptorAppearanceConfigWidget RT y Rule: NameAppearanceConfigWidgethRhFTable: Columns boxAppearanceConfigWidgethbi\U\^`'hFTable: Extended attributes boxAppearanceConfigWidget hj!_T yTable: Schema nameAppearanceConfigWidget hhT yTable: Table nameAppearanceConfigWidget hhhFTable: Title boxAppearanceConfigWidget eg,hFhFOS Textbox: BodyAppearanceConfigWidgetSVhcϏ{&Trigger: DescriptorAppearanceConfigWidget SVhT y Trigger: NameAppearanceConfigWidgetN R~ UnderlineAppearanceConfigWidgetV_u(cϏ{&View: Reference descriptorAppearanceConfigWidget V_u(RView: Referenced columnAppearanceConfigWidget V_u(hView: Referenced tableAppearanceConfigWidget V_u(hFView: References boxAppearanceConfigWidgetVj!_T yView: Schema nameAppearanceConfigWidgetVh/RR+T View: Table / columns aliasAppearanceConfigWidget VhhFView: Title boxAppearanceConfigWidgetVVT yView: View nameAppearanceConfigWidgetcUcIR0g*w_^8Unknown exception caught! Application ^u((&A)&ApplyBaseForm Sm(&C)&CancelBaseForm xn[(&O)&OkBaseForm DialogDialogBaseFormZT Aggregate BaseObject|{WlcbCast BaseObjectRColumn BaseObject~g_ Constraint BaseObjectxlcb Conversion BaseObjectepcn^Database BaseObjectWDomain BaseObjectQepFunction BaseObject}"_Index BaseObjectLanguage BaseObjectdO\{&Operator BaseObjectdO\{&|{Operator Class BaseObjectdO\{&eOperator Family BaseObjectSep Parameter BaseObjectgCP Permission BaseObject҂rRole BaseObjectRRule BaseObjectj!_Schema BaseObject^RSequence BaseObjecthTable BaseObjecthzz Tablespace BaseObjecteg,hFTextbox BaseObjectSVhTrigger BaseObject|{WType BaseObjectVView BaseObjectYlComment:BaseObjectWidget[avgCPEdit object's permissionsBaseObjectWidgetgCPEdit permissionsBaseObjectWidgetIDID:BaseObjectWidgetT yName:BaseObjectWidgetb@g Owner:BaseObjectWidgetj!_Schema:BaseObjectWidgethzz Tablespace:BaseObjectWidget,kd[aYNSObr` el[[^u(NOUOe90FThis object is protected thus no change in form will be applied to it.BaseObjectWidgetP<Value(s)BaseObjectWidgetrHg,VersionBaseObjectWidget iconeiconeBaseObjectWidget Sm(&C)&Cancel BugReportFormR^Create BugReportForm4epcn^j!W (*.dbm);; b@g eN (*.*)'Database model (*.dbm);;All files (*.*) BugReportFormbS_j!W Load model BugReportFormbTJReport BugReportForm_:R6lcb Assignment CastWidgetQe / QInput / Output CastWidget SYepcn|{WSource data type CastWidget vhepcn|{WTarget data type CastWidget4\<em><strong>|{W A</strong></em>lcbb <em><strong>|{W B</strong></em>vQep{~T <em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>.The function to be assigned to a cast from typeA to typeB must have the following signature: typeB function(typeA, integer, boolean). CastWidgetx Encoding:CollationWidgetLC_COLLATE: LC_COLLATE:CollationWidgetLC_CTYPE: LC_CTYPE:CollationWidget Alt+RAlt+RColorPickerWidgetFormFormColorPickerWidget؋P<Default Value: ColumnWidget ^u((&A)&ApplyConfigurationForm Sm(&C)&CancelConfigurationForm0_SRMRb@PZvOe9\ON"Y1`bY R0؋nTtAny modification made until now in the current section will be lost! Do you really want to restore default settings?ConfigurationForm؋DefaultsConfigurationForm^8GeneralConfigurationFormcNPlug-insConfigurationFormpgModeler MnpgModeler ConfigurationConfigurationFormCAAC verificationConnectionsConfigWidgete^AddConnectionsConfigWidgetQAAllowConnectionsConfigWidgetSmCancel editionConnectionsConfigWidget [b7zNfClient Certificate:ConnectionsConfigWidget [b7z[Ɣ Client Key:ConnectionsConfigWidget cR+T Connection Alias:ConnectionsConfigWidget cepcn^Connection DB:ConnectionsConfigWidgetc Connections:ConnectionsConfigWidget ^zecCreate new connectionConnectionsConfigWidgetR d N-vcDelete selected connectionConnectionsConfigWidgetyu(DisableConnectionsConfigWidget N-vcEdit selected connectionConnectionsConfigWidget[QExportConnectionsConfigWidget_:R6 GSSAPI Force GSSAPIConnectionsConfigWidgetSTFull verificationConnectionsConfigWidget^8GeneralConnectionsConfigWidget N;g:/zS Host/Port:ConnectionsConfigWidget[x Password:ConnectionsConfigWidget_ŗRequireConnectionsConfigWidget ]T NfRevoked Certs.:ConnectionsConfigWidgeth9NfRoot Certificate:ConnectionsConfigWidgetSSL j!_ SSL Mode:ConnectionsConfigWidgetbRSuccessConnectionsConfigWidgetmKTestConnectionsConfigWidgeteTimeout:ConnectionsConfigWidgetfeUpdateConnectionsConfigWidgetu(b7User:ConnectionsConfigWidgety(s) second(s)ConnectionsConfigWidget8~/.postgresql/postgresql.crt~/.postgresql/postgresql.crtConnectionsConfigWidget8~/.postgresql/postgresql.key~/.postgresql/postgresql.keyConnectionsConfigWidget,~/.postgresql/root.crl~/.postgresql/root.crlConnectionsConfigWidget,~/.postgresql/root.crt~/.postgresql/root.crtConnectionsConfigWidgetRColumnConstraintWidgetRColumn:ConstraintWidgetRColumnsConstraintWidget ~g_|{WConstraint Type:ConstraintWidgetS^: Deferrable:ConstraintWidget^ Deferral:ConstraintWidget XkQEV[P Fill Factor:ConstraintWidgetON DELETE ON DELETE:ConstraintWidgetON UPDATE ON UPDATE:ConstraintWidget_u(RReferenced ColumnsConstraintWidgethTable:ConstraintWidget|{WTypeConstraintWidget ؋lcbDefault Conversion:ConversionWidget SYxSource Encoding:ConversionWidget vhxTarget Encoding:ConversionWidgetxlcbvQep{~T <em>void function(integer, integer, cstring, internal, integer)</em>0The function to be assigned to an encoding conversion must have the following signature: void function(integer, integer, cstring, internal, integer).ConversionWidget4epcn^j!W (*.dbm);; b@g eN (*.*)'Database model (*.dbm);;All files (*.*)CrashHandlerForm"||pgModeler ])nNOops! pgModeler just crashed!CrashHandlerFormO[Xj!W Save modelCrashHandlerForm Xhߎ*O`o Stack traceCrashHandlerFormFormForm CsvLoadWidgetbS_Load CsvLoadWidget SpaceSpace CsvLoadWidget Qs(&C)&CloseDataManipulationFormmRyvAdd ItemDataManipulationFormRColumnDataManipulationFormRColumn:DataManipulationForm Ctrl+SCtrl+SDataManipulationForm Ctrl+ZCtrl+ZDataManipulationFormDelDelDataManipulationFormF5F5DataManipulationFormInsInsDataManipulationFormydyv Remove ItemDataManipulationFormj!_Schema:DataManipulationFormhTable:DataManipulationFormSep ArgumentsDatabaseExplorerWidget\^`' AttributeDatabaseExplorerWidgetRColumnsDatabaseExplorerWidget~g_ ConstraintDatabaseExplorerWidget؋DefaultDatabaseExplorerWidget[NI DefinitionDatabaseExplorerWidget~^ DimensionDatabaseExplorerWidgetQC} ElementDatabaseExplorerWidgetgN> EnumerationsDatabaseExplorerWidgetNNEventDatabaseExplorerWidgeth_ ExpressionDatabaseExplorerWidgetSFiringDatabaseExplorerWidgetFormFormDatabaseExplorerWidgetQepFunctionDatabaseExplorerWidgetLanguageDatabaseExplorerWidget^LengthDatabaseExplorerWidget R`c^LibraryDatabaseExplorerWidgetT yNameDatabaseExplorerWidgetdO\{&OperatorDatabaseExplorerWidgetdO\{& OperatorsDatabaseExplorerWidgetgCP PermissionsDatabaseExplorerWidget|^ PrecisionDatabaseExplorerWidgetT}T RenameDatabaseExplorerWidget҂rRolesDatabaseExplorerWidgetj!_SchemaDatabaseExplorerWidgetnNx Source codeDatabaseExplorerWidget[XPStorageDatabaseExplorerWidget~u(b7 SuperuserDatabaseExplorerWidgethTableDatabaseExplorerWidgethzz TablespaceDatabaseExplorerWidget|{WTypeDatabaseExplorerWidgetfeUpdateDatabaseExplorerWidgetTl`'ValidityDatabaseExplorerWidget Qs(&C)&CloseDatabaseImportFormSmCancelDatabaseImportFormc Connection:DatabaseImportFormepcn^DatabaseDatabaseImportFormYth{~...Progress label...DatabaseImportForm\^`' AttributesDatabaseWidgetc Connections:DatabaseWidget؋DefaultDatabaseWidgetx Encoding:DatabaseWidgetLC_COLLATE: LC_COLLATE:DatabaseWidgetLC_CTYPE: LC_CTYPE:DatabaseWidget j!WO\ Model Author:DatabaseWidget yOptions:DatabaseWidgetb@g Owner:DatabaseWidgetj!_Schema:DatabaseWidgethzz Tablespace:DatabaseWidget epcn^j!g Template DB:DatabaseWidget\^`' Attributes DomainWidget؋P<Default Value: DomainWidgeth_ Expression DomainWidgetT yName DomainWidgetT yName: DomainWidgetFormForm DonateWidgetSG^ AscendingElementsWidgetRColumn:ElementsWidgetM^ DescendingElementsWidgetQC} ElementElementsWidgeth_ ExpressionElementsWidgetFormFormElementsWidgetT&NoElementsWidgetNull PAssignment of a precision greater than the length of the type! ExceptionhvN;.][XW(=Assignment of a primary key to a table which already has one! ExceptionR|{WN N:O*|{W6Assignment of a pseudo-type to the type of the column! Exception^Rj!_Nhj!_N NXAssignment of a schema to the sequence which differs from the schema of the owner table! Exception ~NN*eeHvcSepRMNN*P<9Assignment of a value to an invalid connection parameter! Exception[avh_eeH2Assignment of an invalid expression to the object! Exception`|{W time timestamp b interval v|^neeH0|^_Ř{\N{IN 6Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! Exception dO\{&|{QC} v{Vue/e/cPAssignment of an object that already belongs to another table! ExceptionRMNN*zz DTD eNT "Assignment of empty DTD file name! Exception RMzzv} XML [X~ىgVh)Assignment of empty XML buffer to parser! Exception[aT yN N:zz&Assignment of empty name to an object! ExceptionhvVP<|{WvT yN N:zz.Assignment of empty name to table return type! ExceptionRMzzv}T y~ DTD Xf0Assignment of empty name to the DTD declaration! Exception|{WvMneeH0Assignment of invalid configuration to the type! ExceptiondO\RhvgY'PInsertion of element which already exists in the element list! ExceptioncQe|{W\^`'RhvyveeH=Insertion of invalid item in the attributes list of the type! ExceptioncQe|{WgN>RhvyveeH?Insertion of invalid item in the enumerations list of the type! Exception"cQevyv][XW(N|{W\^`'Rh JInsertion of item which already exists in the attributes list of the type! Exception cQevyv][XW(N|{WgN>RhLInsertion of item which already exists in the enumarations list of the type! ExceptionLelR^~ep > = 1Wb^Rep~PostgreSQL \g*[skdR}It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! ExceptionN SeeH|{Wv[a'Obtaining an object of an invalid type! ExceptionkcxnSv|{WvepeeH&Obtaining types with invalid quantity! ExceptionlNN*bYN*[aeeH ^vRR dN0VN:NN_u(vhRb@W(vQs|]~N [XW(N u1NcN-ebcdubvROne or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! Exception>cNR}Su NN*bYN*cNlg om;`ŋgw _^8O`o0|One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. Exceptiong*bRc(Operation on connection not established! ExceptionTdO\W(g*RMvQC} hN _Ř{QH}Qe XML gVh[X^vbgLg h7hbMubOperation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! Exception(dO\vQC} W(_SRM}QevQC} hN-N [XW(ROperation with element which does not exists in the element tree currently loaded! ExceptioneldO\g*RMv[a$Operation with object not allocated! ExceptiondO\[av|{WeeH2Operation with object(s) which type(s) is invalid! ExceptiondO\W(g*RMvhQC} N (Operation with unallocated tree element! Exception_u(vNRQC~}"_eeH2Reference to a column of tuple with invalid index! Exception_u(vNRQC~T [WeeH1Reference to a column of tuple with invalid name! ExceptionN _u(N W(RRhN-vRLReference to a column which index is out of the capacity of the column list! Exception_u(NeeHvQep|{W*Reference to a function with invalid type! Exception_u(NeeHvdO\{&Sep|{W;Reference to an argument of the operator with invalid type! ExceptionN _u(N \^NSVhvNN8Reference to an event which does not belongs to trigger! Exception_u(NeeHvgCP|{W'Reference to an invalid privilege type! Exception_u(NeeHv҂r|{W"Reference to an invalid role type! Exception_u(NeeHvdO\{&|{W+Reference to an operator with invalid type! Exception"_u(vu(b7[NI|{WN [XW(Nj!WDReference to an user-defined data type that not exists in the model! Exception(_u(vepcn|{WN W(epcn|{WRhvVQMReference to data type with an index outside the capacity of data types list! Exception_u([av|{WeeH&Reference to object with invalid type! ExceptionN ydg*RMv[a#Removal of an object not allocated! ExceptionN ydeeH|{Wv[a&Removing an object of an invalid type! Exception[QY1% PostgreSQL g RVhbgL SQL T}NeSu`ŋgw Vv_^8O`o bgLv SQL S %1The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 ExceptionX_:R6bgLN$h 1-1 Qs|vR\g*[s VN:[~Tj!WN-u1u(b7[NIvN$NNvRyvhThe relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user! Exception>elՃ_ SQL T}N~g VN:g RVhzvS͙[b7zelՋR+uUnable to allocate the result of the SQL command because the response from the DBMS was not understood by the client! ExceptionrHg,Version:ExtensionWidgetF3F3FindReplaceWidgetFormFormFindReplaceWidget\^`' AttributesFunctionWidgetLN: Behavior:FunctionWidgetRColumnFunctionWidget؋P< Default ValueFunctionWidget[NI DefinitionFunctionWidgetR`^Dynamic Library:FunctionWidget bgL_Execution Cost:FunctionWidget Qep|{WFunction Type:FunctionWidget^Library:FunctionWidgetT yNameFunctionWidgetSep ParametersFunctionWidget VelReturn Method:FunctionWidgetVވh Return TableFunctionWidget VވLepRows Returned:FunctionWidget[Qh Security:FunctionWidgetSetFunctionWidgetnNx Source code:FunctionWidget{&SSymbol:FunctionWidget|{WTypeFunctionWidgetpt ptGeneralConfigWidget$A0 (841 x 1189 mm)A0 (841 x 1189 mm)GeneralConfigWidget"A1 (594 x 841 mm)A1 (594 x 841 mm)GeneralConfigWidget"A2 (420 x 594 mm)A2 (420 x 594 mm)GeneralConfigWidget"A3 (297 x 420 mm)A3 (297 x 420 mm)GeneralConfigWidget"A4 (210 x 297 mm)A4 (210 x 297 mm)GeneralConfigWidget"A5 (148 x 210 mm)A5 (148 x 210 mm)GeneralConfigWidget"A6 (105 x 148 mm)A6 (105 x 148 mm)GeneralConfigWidget A7 (74 x 105 mm)A7 (74 x 105 mm)GeneralConfigWidgetA8 (52 x 74 mm)A8 (52 x 74 mm)GeneralConfigWidgetA9 (37 x 52 mm)A9 (37 x 52 mm)GeneralConfigWidget&B0 (1030 x 1456 mm)B0 (1030 x 1456 mm)GeneralConfigWidget$B1 (728 x 1030 mm)B1 (728 x 1030 mm)GeneralConfigWidget B10 (32 x 45 mm)B10 (32 x 45 mm)GeneralConfigWidget"B2 (515 x 728 mm)B2 (515 x 728 mm)GeneralConfigWidget"B3 (364 x 515 mm)B3 (364 x 515 mm)GeneralConfigWidget"B4 (257 x 364 mm)B4 (257 x 364 mm)GeneralConfigWidget"B5 (182 x 257 mm)B5 (182 x 257 mm)GeneralConfigWidget"B6 (128 x 182 mm)B6 (128 x 182 mm)GeneralConfigWidget B7 (91 x 128 mm)B7 (91 x 128 mm)GeneralConfigWidgetB8 (64 x 91 mm)B8 (64 x 91 mm)GeneralConfigWidgetB9 (45 x 64 mm)B9 (45 x 64 mm)GeneralConfigWidgetN  Bottom marginGeneralConfigWidgetN Bottom:GeneralConfigWidget$C5E (163 x 229 mm)C5E (163 x 229 mm)GeneralConfigWidgetS|s CentimeterGeneralConfigWidgetrColors:GeneralConfigWidget,Comm10E (105 x 241 mm)Comm10E (105 x 241 mm)GeneralConfigWidget$DLE (110 x 220 mm)DLE (110 x 220 mm)GeneralConfigWidget0Executive (191 x 254 mm)Executive (191 x 254 mm)GeneralConfigWidget(Folio (210 x 330 mm)Folio (210 x 330 mm)GeneralConfigWidget[WOSFont:GeneralConfigWidgetFormFormGeneralConfigWidget^8GeneralGeneralConfigWidget[InchesGeneralConfigWidgetj*T LandscapeGeneralConfigWidget*Ledger (432 x 279 mm)Ledger (432 x 279 mm)GeneralConfigWidget]揹 Left marginGeneralConfigWidget]Left:GeneralConfigWidget(Legal (216 x 356 mm)Legal (216 x 356 mm)GeneralConfigWidget*Letter (216 x 279 mm)Letter (216 x 279 mm)GeneralConfigWidgetk|s MilimetersGeneralConfigWidgetW(eN{tVhN-bS_Open in file managerGeneralConfigWidget dO\_UOperation history:GeneralConfigWidget yOptions:GeneralConfigWidgeteT Orientation:GeneralConfigWidget~WPaper:GeneralConfigWidgetP} PixelsGeneralConfigWidget~TPortraitGeneralConfigWidgetbSSpQh< Print gridGeneralConfigWidgetbSSpuxPrint page numbersGeneralConfigWidgetS󏹍 Right marginGeneralConfigWidgetSRight:GeneralConfigWidget,Tabloid (279 x 432 mm)Tabloid (279 x 432 mm)GeneralConfigWidgetN  Top marginGeneralConfigWidgetN Top:GeneralConfigWidgetFormFormHintTextWidget\^`' Attributes IndexWidget^vS Concurrent IndexWidgetQC} Elements IndexWidget_fe Fast update IndexWidget XkQEV[P Fill Factor: IndexWidget yOptions: IndexWidgetYtQepv{~T RR+N:<br/><br/> <strong>YtQep</strong> <em>language_handler function()</em><br/> <strong>Qep</strong> <em>void function(oid)</em><br/> <strong>QTQep</strong> <em>void function(internal)</em>DThe functions to be assigned to the language should have, respectively, the following signatures:

Handler Function: language_handler function()
Validator Function: void function(oid)
Inline Function: void function(internal)LanguageWidgetSOTrusted:LanguageWidget Qs(&C)&Close MainWindow (&E)&Edit MainWindow [Q(&E)&Export MainWindow eN(&F)&File MainWindow V(&S)&Show MainWindow[P[aR0Qh<Align objects position to grid MainWindowSmCancel MainWindow|j!Wv~W/u]e9S S[[abSSpQ0Ou(evn~~bSSpTOu(؋n SUQ T& b Sm N-kbbSSp0Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. MainWindowxn Confirmation MainWindow Ctrl+-Ctrl+- MainWindow Ctrl+0Ctrl+0 MainWindow Ctrl+=Ctrl+= MainWindow Ctrl+GCtrl+G MainWindow Ctrl+LCtrl+L MainWindow Ctrl+NCtrl+N MainWindow Ctrl+OCtrl+O MainWindow Ctrl+PCtrl+P MainWindow Ctrl+SCtrl+S MainWindow Ctrl+YCtrl+Y MainWindow Ctrl+ZCtrl+Z MainWindow4epcn^j!W (*.dbm);; b@g eN (*.*)'Database model (*.dbm);;All files (*.*) MainWindowkcW(bSSpepcn^j!WDatabase model printing MainWindowF1F1 MainWindowF10F10 MainWindowF12F12 MainWindowF4F4 MainWindow^8General MainWindowbS_j!W Load model MainWindowe^New MainWindowe^[a New object MainWindowcNPlugins MainWindowO[X '%1' N:...Save '%1' as... MainWindowO[XQhSave all MainWindowO[Xj!W Save model MainWindowf>y:Qh< Show grid MainWindow f>y:j!WiShow the model overview MainWindow f>y:Ru{&Show the page delimiters MainWindow)\Zoom - MainWindowe>Y'Zoom in MainWindow)\Zoom out MainWindow<pgModeler - PostgreSQL epcn^^j!]Qw'pgModeler - PostgreSQL Database Modeler MainWindow Sm(&C)&Cancel Messagebox T&(&N)&No Messagebox xn[(&O)&Ok Messagebox f/(&Y)&Yes MessageboxfTJAlert MessageboxSmCancel Messageboxxn Confirmation Messagebox DialogDialog MessageboxError Messagebox_^8 Exceptions MessageboxO`o Information Messageboxf>y:/_^8Xh0Show/hide exceptions stack. MessageboxO`omsg Messagebox ^u((&A)&ApplyMetadataHandlingForm Sm(&C)&CancelMetadataHandlingFormYth{~...Progress label...MetadataHandlingForm Qs(&C)&CloseModelDatabaseDiffForm00ModelDatabaseDiffFormSmCancelModelDatabaseDiffFormxn ConfirmationModelDatabaseDiffFormc Connection:ModelDatabaseDiffForm[QExportModelDatabaseDiffFormeNFile:ModelDatabaseDiffFormYth{~...Progress label...ModelDatabaseDiffForm4SQL Nx (*.sql);;b@g eN (*.*)!SQL code (*.sql);;All files (*.*)ModelDatabaseDiffForm Qs(&C)&CloseModelExportForm [Q(&E)&ExportModelExportForm......ModelExportFormSmCancelModelExportFormc Connection:ModelExportForm[Qj!WN:...Export model as...ModelExportForm bR[Q#Exporting process sucessfuly ended!ModelExportFormeNFile:ModelExportForm _ueY [aIgnore object duplicityModelExportFormkcW(RYSj!W[Q...Initializing model export...ModelExportForm2ub SQL Nxv PostgreSQL rHg, y:Ru{&Show delimitersModelExportFormf>y:Qh< Show gridModelExportForm|{WType:ModelExportForm Qs(&C)&Close ModelFixFormQsj!W Close modelModelNavigationWidgetFormFormModelNavigationWidget11ModelObjectsWidgetSmCancelModelObjectsWidgetSmQh Clear AllModelObjectsWidgetRhV List viewModelObjectsWidgete^NewModelObjectsWidget[aObjectModelObjectsWidget [aVMnObjects view configurationModelObjectsWidgetr6[a Parent ObjectModelObjectsWidgetr6|{W Parent TypeModelObjectsWidget bSelectModelObjectsWidget bQh Select AllModelObjectsWidgethV Tree viewModelObjectsWidget|{WTypeModelObjectsWidgetj!WiModel overviewModelOverviewWidget Sm(&C)&CancelModelRestorationForm `bY (&R)&RestoreModelRestorationFormepcn^DatabaseModelRestorationFormeNFileModelRestorationFormj!W`bY Model restorationModelRestorationForm00ModelValidationWidgetSmCancelModelValidationWidget Ctrl+SCtrl+SModelValidationWidgetFormFormModelValidationWidgetmRe[aR0j!WN-Add a new object in the model ModelWidget`T eY R6 N-[avOV[aTOgY'P^Q\]Y R6[a|4R0QvNj!We Su_u(Y1eHvg:O0Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. ModelWidget Sfb@g  Change owner ModelWidget~g_ Constraints ModelWidgetY R6Copy ModelWidgetRjRCut ModelWidgetDelDel ModelWidgetR dDelete ModelWidgetxn[R d N-v[aT1Do you really want to delete the selected object? ModelWidgetgCPEdit permissions ModelWidget Oe9[a\^`'Edit the object properties ModelWidgetF2F2 ModelWidgetkcW(}Qeepcn^j!WLoading database model ModelWidget yRR0j!_Move to schema ModelWidgete^New ModelWidgetBYtz N-Su R[alg |4R0j!WN-0`ŋXhzNot all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! ModelWidget|4Paste ModelWidgetkcW(|4[a...Pasting objects... ModelWidget\^`' Properties ModelWidgetObProtect ModelWidget_T}T kd[aQuick rename the object ModelWidgetT}T Rename ModelWidgetkcW(O[Xepcn^j!WSaving database model ModelWidget bSelect ModelWidget bQh Select all ModelWidget b[P[aSelect children ModelWidget bj!WN-vQhV_b[a.Selects all the graphical objects in the model ModelWidgetShift+Del Shift+Del ModelWidgetf>y:Show ModelWidgetf>y:[anNxShow object source code ModelWidgetnNx Source code ModelWidget SpaceSpace ModelWidgethTables ModelWidgetSmOb Unprotect ModelWidget00NewObjectOverlayWidget11NewObjectOverlayWidget22NewObjectOverlayWidget33NewObjectOverlayWidget44NewObjectOverlayWidget55NewObjectOverlayWidget88NewObjectOverlayWidget99NewObjectOverlayWidgetZT AggregateNewObjectOverlayWidget|{WlcbCastNewObjectOverlayWidgetRColumnNewObjectOverlayWidget~g_ ConstraintNewObjectOverlayWidgetxlcb ConversionNewObjectOverlayWidgetY R6CopyNewObjectOverlayWidgetWDomainNewObjectOverlayWidgetFormFormNewObjectOverlayWidgetQepFunctionNewObjectOverlayWidget}"_IndexNewObjectOverlayWidgetLanguageNewObjectOverlayWidgetMMNewObjectOverlayWidgetdO\{&OperatorNewObjectOverlayWidgetgCP PermissionsNewObjectOverlayWidget҂rRoleNewObjectOverlayWidgetRRuleNewObjectOverlayWidgetj!_SchemaNewObjectOverlayWidget^RSequenceNewObjectOverlayWidgethTableNewObjectOverlayWidgethzz TablespaceNewObjectOverlayWidgeteg,hFTextboxNewObjectOverlayWidgetSVhTriggerNewObjectOverlayWidget|{WTypeNewObjectOverlayWidgetVViewNewObjectOverlayWidgetZZNewObjectOverlayWidgetEditNumberedTextEditorbS_LoadNumberedTextEditorOV DependenciesObjectDepsRefsWidget[aObjectObjectDepsRefsWidgetr6[a Parent ObjectObjectDepsRefsWidgetr6|{W Parent TypeObjectDepsRefsWidget_u( ReferencesObjectDepsRefsWidget|{WTypeObjectDepsRefsWidgetSmQh Clear AllObjectFinderWidgetFormFormObjectFinderWidget[aObjectObjectFinderWidgetr6[a Parent ObjectObjectFinderWidgetr6|{W Parent TypeObjectFinderWidget bSelectObjectFinderWidget bQh Select AllObjectFinderWidget|{WTypeObjectFinderWidgetSmCancelObjectRenameWidgetFormFormObjectRenameWidgetT}T RenameObjectRenameWidgetnzz[Wk Clear fieldObjectSelectorWidgetFormFormObjectSelectorWidget b[a Select ObjectObjectSelectorWidgetmRyvAdd ItemObjectsTableWidget Alt+RAlt+RObjectsTableWidgetxn ConfirmationObjectsTableWidgetCtrl+Down Ctrl+DownObjectsTableWidget Ctrl+End, Ctrl+SCtrl+End, Ctrl+SObjectsTableWidgetCtrl+Home Ctrl+HomeObjectsTableWidgetCtrl+UpCtrl+UpObjectsTableWidgetDelDelObjectsTableWidgetyd N-vyvT/Do you really want to remove the selected item?ObjectsTableWidgetyv Edit ItemObjectsTableWidgetFormFormObjectsTableWidgetInsInsObjectsTableWidgetN y Move DownObjectsTableWidgetN yMove UpObjectsTableWidgetyg+\> Move to endObjectsTableWidgety_Y4 Move to startObjectsTableWidgetR dQh Remove AllObjectsTableWidgetydyv Remove ItemObjectsTableWidgetShift+Del Shift+DelObjectsTableWidget SpaceSpaceObjectsTableWidgetfeyv Update ItemObjectsTableWidget00OperationListWidget11OperationListWidget R ddO\_UDelete operation historyOperationListWidget$R ddO\_Uf/N SdO\ ~~TZDelete the executed operations history is an irreversible action, do you want to continue?OperationListWidget bgLvdO\Executed OperationsOperationListWidget T y%1Name: %1OperationListWidget [a%1 Object: %1OperationListWidgetN f>y:dO\_UOperation history exclusionOperationListWidget dO\%1 Operation: %1OperationListWidgetdO\ Operations:OperationListWidgetOMn Position:OperationListWidgetPZRedoOperationListWidgetdUndoOperationListWidgetR^bRcreatedOperationListWidgetOe9bRmodifiedOperationListWidgetyRbRmovedOperationListWidgetR dbRremovedOperationListWidget؋|{Default Class:OperatorClassWidgetQC} ElementsOperatorClassWidgetQepFunctionOperatorClassWidgetQep Function:OperatorClassWidget }"_|{W Indexing:OperatorClassWidget[aObjectOperatorClassWidgetdO\{&OperatorOperatorClassWidgetdO\{&eOperator FamilyOperatorClassWidgetdO\{& Operator:OperatorClassWidget[XPStorageOperatorClassWidget[XP|{W Storage TypeOperatorClassWidget e/c/{VueSupport/StrategyOperatorClassWidget e/c/{VueSupport/Strategy:OperatorClassWidget|{WTypeOperatorClassWidgetkcW(^z}"_ Indexing:OperatorFamilyWidgetSep ArgumentsOperatorWidgetT^ c (HASHES)HASHESOperatorWidgetcJoin:OperatorWidget ]Sep|{WLeft Argument TypeOperatorWidgetTc (MERGES)MERGESOperatorWidget yOptions:OperatorWidget SSep|{WRight Argument TypeOperatorWidgetW(R^SUvdO\{&e_Ř{c[[NSepN-v<strong><em>NOU</em></strong>NN*0SY O\N:dO\{&vQep_Ř{g NSg NN*Sep NN*Sepv|{W_Ř{NSUvdO\{&Sepv|{WvT 0To create a unary operator it is necessary to specify as 'any' one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator.OperatorWidget؋P<Default Value:ParameterWidgetININParameterWidgetj!_Mode:ParameterWidgetOUTOUTParameterWidgetmRgCPAdd PermissionPermissionWidgetSmdO\Cancel OperationPermissionWidgetNx Code PreviewPermissionWidgetgCPEdit permissionsPermissionWidgetCRANT OPTION GRANT OPTIONPermissionWidgetIDID:PermissionWidgetIdIdPermissionWidgetT yNamePermissionWidgetgCP PermissionsPermissionWidgetgCP PrivilegePermissionWidgetgCP PrivilegesPermissionWidget҂rRolesPermissionWidgetfegCPUpdate PermissionPermissionWidgetepcn|{W Data TypePgSQLTypeWidget~^ DimensionPgSQLTypeWidgetFormFormPgSQLTypeWidgeth<_Format:PgSQLTypeWidgetS: Interval:PgSQLTypeWidgetLL:PgSQLTypeWidget^LengthPgSQLTypeWidgetMMPgSQLTypeWidgetPP:PgSQLTypeWidget|^ PrecisionPgSQLTypeWidgetzzSpatial:PgSQLTypeWidgeteS: Timezone:PgSQLTypeWidget|{WType:PgSQLTypeWidgetS_ Variation:PgSQLTypeWidgetZZPgSQLTypeWidget[ ][ ]:PgSQLTypeWidgetFormFormPluginsConfigWidget R`c^LibraryPluginsConfigWidget ]R}vcNLoaded plug-insPluginsConfigWidgetW(eN{tVhN-bS_Open in file managerPluginsConfigWidget cNh9v_UPlug-ins root directory:PluginsConfigWidgetcNPluginPluginsConfigWidgetrHg,VersionPluginsConfigWidgetT yName PolicyWidget҂rRoles PolicyWidget%1 (L%2) %1 (line: %2)QObjectnew_database new_databaseQObjectY R6CopyRelationshipConfigWidget؋DefaultRelationshipConfigWidget^ Deferral:RelationshipConfigWidgetFormFormRelationshipConfigWidgetlSGeneralizationRelationshipConfigWidgetON DELETE ON DELETE:RelationshipConfigWidgetON UPDATE ON UPDATE:RelationshipConfigWidget1-N1-nRelationshipWidget\^`' AttributeRelationshipWidget\^`' AttributesRelationshipWidgetWep Cardinality:RelationshipWidget~g_ ConstraintRelationshipWidget~g_ ConstraintsRelationshipWidget؋DefaultRelationshipWidgetS^ Deferrable:RelationshipWidget^ Deferral:RelationshipWidget^8GeneralRelationshipWidgetlSQs| (~b))Generalization relationship (inheritance)RelationshipWidgeth{& IdentifierRelationshipWidget Y[YQs|Many to many relationshipRelationshipWidgetT yNameRelationshipWidgetY[YQs|ubhvT y:Name of the table generated from many to many relationshipRelationshipWidgetON DELETE ON DELETE:RelationshipWidgetON UPDATE ON UPDATE:RelationshipWidget N[YQs|One to many relationshipRelationshipWidget N[NQs|One to one relationshipRelationshipWidgetN;. Primary keyRelationshipWidget_u(hReferenced Table:RelationshipWidget|{WTypeRelationshipWidgetdepdepRelationshipWidgetN-Nn-nRelationshipWidget\^`' Attributes RoleWidgetc Connections: RoleWidgetbTX Member of RoleWidgetbTXMembers RoleWidgetbTX({tTX)Members (Admin.) RoleWidget[x Password: RoleWidget҂rRole RoleWidget~u(b7 Superuser RoleWidgetTl`'Validity RoleWidget gaNh_Conditional Expr.: RuleWidgetNNEvent: RuleWidget bgL|{WExecution Type: RuleWidgetSQL T}N SQL Command: RuleWidget SQL T}N SQL command RuleWidgetR^NN*N bgLNOUdO\vR<STRONG>DO NOTHING</STRONG> {SUp \1f/ SQL T}NhN-lg vT}N0To create a rule that does not perform any action (DO NOTHING) simply do not specify commands in the SQL commands table. RuleWidgetSmQh Clear AllSQLExecutionWidgetF6F6SQLExecutionWidgetFormFormSQLExecutionWidgetbS_LoadSQLExecutionWidgetO[XSaveSQLExecutionWidgetS[XN:Save asSQLExecutionWidget Alt+RAlt+R SQLToolWidget\^`' Attributes SQLToolWidgetFormForm SQLToolWidgetnNx Source code SQLToolWidgetFormFormSceneInfoWidget[XCache:SequenceWidget_sCyclic:SequenceWidgetX Increment:SequenceWidgetgY'P<Maximum:SequenceWidgetg\P<Minimum:SequenceWidgetwYP<Start:SequenceWidgete^AddSnippetsConfigWidgetSmCancel editionSnippetsConfigWidget ^zecCreate new connectionSnippetsConfigWidgetR d N-vcDelete selected connectionSnippetsConfigWidget N-vcEdit selected connectionSnippetsConfigWidgetFormFormSnippetsConfigWidget^8GeneralSnippetsConfigWidgetIDID:SnippetsConfigWidgetR dQh Remove AllSnippetsConfigWidgetShift+Del Shift+DelSnippetsConfigWidgetfeUpdateSnippetsConfigWidget.-- elubkd[a|{Wv SQL Nx --2-- SQL code unavailable for this type of object --SourceCodeWidgetkcW(ubnNx......Generating source code...SourceCodeWidgetPostgreSQL PostgreSQLSourceCodeWidgetSQLSQLSourceCodeWidget4SQL Nx (*.sql);;b@g eN (*.*)!SQL code (*.sql);;All files (*.*)SourceCodeWidget gw nNxSource code visualizationSourceCodeWidgetrHg,Version:SourceCodeWidgetXMLXMLSourceCodeWidgeticonecodigo iconecodigoSourceCodeWidgetIDID:SwapObjectsIdsWidget[aObjectSwapObjectsIdsWidgetr6[a Parent ObjectSwapObjectsIdsWidgetr6|{W Parent TypeSwapObjectsIdsWidget|{WTypeSwapObjectsIdsWidgetY R6CopyTableDataWidgetDelDelTableDataWidgetInsInsTableDataWidget|4PasteTableDataWidgetShift+Del Shift+DelTableDataWidgetY R6Copy TableWidget؋P< Default Value TableWidgetNNEvent TableWidgetNNEvents TableWidgetbgL Execution TableWidgetSFiring TableWidget}"_Indexing TableWidgetT yName TableWidgetT&No TableWidgetON DELETE ON DELETE TableWidgetON UPDATE ON UPDATE TableWidget_u(h Refer. Table TableWidget҂rRoles TableWidgetj!_Schema TableWidget|{WType TableWidgetf/Yes TableWidget[WQx Directory:TablespaceWidgetFormFormTablespaceWidgetkcW(bgLvNRExecuting tasksTaskProgressWidget|OSBold TextboxWidget[WOSFont: TextboxWidgeteOSItalic TextboxWidget beg,rSelect text color TextboxWidgetN R~ Underline TextboxWidgetSep Argument: TriggerWidgetSep Arguments TriggerWidgetRColumn TriggerWidgetRColumn: TriggerWidgetRColumns TriggerWidget~g_ Constraint TriggerWidget DELETEDELETE TriggerWidgetS^ Deferrable: TriggerWidgetNNEvent: TriggerWidgetQep Function: TriggerWidget INSERTINSERT TriggerWidget yOptions: TriggerWidgetTRUNCATETRUNCATE TriggerWidget|{WType TriggerWidget UPDATEUPDATE TriggerWidgetANALYZEANALYZE: TypeWidget[P Alignment: TypeWidget\^`' Attributes TypeWidgetWg,|{W Base Type TypeWidget|{R+ Category: TypeWidgetMnConfiguration: TypeWidget؋P<Default Value: TypeWidgetR{& Delimiter: TypeWidgetQC} |{W Element Type TypeWidgetgN> Enumeration TypeWidgetgN> Enumeration: TypeWidgetgN> Enumerations TypeWidgetQep Functions TypeWidget INPUTINPUT: TypeWidget Q^Internal Length: TypeWidgetT yName TypeWidgetT yName: TypeWidgetOUTPUTOUTPUT: TypeWidget dO\{&|{Operator Class: TypeWidget yOptions: TypeWidget RECVRECV: TypeWidget SENDSEND: TypeWidget[XPStorage: TypeWidgetTPMOD_IN TPMOD_IN: TypeWidgetTPMOD_OUT TPMOD_OUT: TypeWidgetu(N|{W[NIvQepu( C Q ^vN{&TN RvQep{~T <br/> <table> <tr> <td><strong>INPUT</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND</strong> <em>byta function(any)</em></td> <td><strong>RECV</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE</strong> <em>boolean function(internal)</em></td> <tr> </table>The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:
INPUT: any function(cstring, oid, integer) OUTPUT: cstring function(any)
SEND: byta function(any) RECV: any function(internal, oid, integer)
TPMOD_IN: integer function(cstring[]) TPMOD_OUT: cstring function(integer)
ANALYZE: boolean function(internal)
 TypeWidget|{WType TypeWidgetcharchar TypeWidget double precisiondouble precision TypeWidgetintegerinteger TypeWidgetsmallintsmallint TypeWidget 0.0.00.0.0UpdateNotifierWidgetR+T Alias ViewWidgetRR+T  Alias Col. ViewWidgetNx Code Preview ViewWidget R/h_ Col./Expr. ViewWidgetRColumn ViewWidgetRR+T  Column Alias: ViewWidgetRColumn: ViewWidgetNNEvent ViewWidgetNNEvents ViewWidgetbgL Execution ViewWidgeth_ Expression ViewWidget h_R+T Expression Alias: ViewWidgeth_ Expression: ViewWidgetSFiring ViewWidget}"_Indexes ViewWidget}"_Indexing ViewWidgetj!_Mode: ViewWidgetT yName ViewWidget_u(h Refer. Table ViewWidget_u( References ViewWidgetRRules ViewWidgethR+T  Table Alias: ViewWidgethTable: ViewWidgetSVhTriggers ViewWidgetu(W(Used in: ViewWidgetFormForm WelcomeWidgetpgmodeler-0.9.2/lang/zh_CN.ts000066400000000000000000014432131360462764600160200ustar00rootroot00000000000000 AboutWidget About pgModeler 关于 pgModeler PostgreSQL Database Modeler PostgreSQL 数据库建模工具 Open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand, let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards. pgModeler is proudly a brazilian software! Hide this widget ... (BUILD_NUM) License 0.0.0 0.0.0 build: <html><head/><body><p><a href="http://pgmodeler.com.br"><span style=" text-decoration: underline; color:#2980b9;">https://pgmodeler.io</span></a></p></body></html> <html><head/><body><p>Copyright 2006-2018 - Raphael Araújo e Silva &lt;<a href="mailto:raphael@pgmodeler.com.br"><span style=" text-decoration: underline; color:#0057ae;">raphael@pgmodeler.io</span></a>&gt;</p></body></html> AggregateWidget Final Function: 最终处理函数: Sort Operator: 排序操作符: Funtion Inputs 函数输入 Function State 函数状态 Input Data Type 输入数据类型 State Data Type 状态数据类型 An aggregate function that accepts the types <em><strong>typeA</strong></em> and <em><strong>typeB</strong></em> as input types and which type of state is <em><strong>state_type</strong></em>, must obey the following rules: <br/><br/> <strong> &nbsp;&nbsp;&nbsp;• Final Function:</strong> <em>void final_function(<strong>state_type</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp;• Transition Function:</strong> <em><strong>state_type</strong> transition_function(<strong>state_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em> 聚合函数接受类型 <em><strong>typeA</strong></em> 和 <em><strong>typeB</strong></em> 作为输入类型,并且类型状态为 <em><strong>state_type</strong></em>, 函数必须遵循如下规则:<br/><br/> <strong> &nbsp;&nbsp;&nbsp;•最终处理函数:</strong> <em>void final_function(<strong>state_type</strong>)</em><br/> <strong> &nbsp;&nbsp;&nbsp;• 过渡处理函数:</strong> <em><strong>state_type</strong> transition_function(<strong>state_type</strong>, <strong>typeA</strong>, <strong>typeB</strong>)</em> Initial Condition: Transition Func.: AppearanceConfigWidget Element: 元素: Global: Font style 全局:字体样式 Global: Constraints descriptor 全局:约束描述符 Global: Object selection 全局:对象选择 Global: Position hint text 全局:位置提示内容 Global: Position hint box 全局:位置提示框 Global: Objects type 全局:对象类型 Global: Lock arc 全局:锁环 Global: Lock body 全局:锁体 Table: Schema name 表:模式名称 Table: Table name 表:表名称 Table: Columns box 表:列框 Table: Extended attributes box 表:扩展属性框 Table: Title box 表:标题框 Index: Descriptor 索引:描述符 Trigger: Descriptor 触发器:描述符 View: Schema name 视图:模式名称 View: View name 视图:视图名称 View: References box 视图:引用框 View: Title box 视图:标题框 View: Table / columns alias 视图:表/列别名 View: Referenced column 视图:引用列 View: Referenced table 视图:引用表 View: Reference descriptor 视图:引用描述符 Textbox: Body 文本框:框体 Column: Column name 列:列名称 Column: Descriptor 列:描述符 Column: Included / Inherited by relationship 列:包含在/继承自关系 Column: Protected 列:写保护 Column (pk): Column name 列(PK):列名称 Column (pk): Descriptor 列(PK):描述符 Column (fk): Column name 列(FK):列名称 Column (fk): Descriptor 列(FK):描述符 Column (uq): Column name 列(UQ):列名称 Column (uq): Descriptor 列(UQ):描述符 Column (nn): Column name 列(NN):列名称 Column (nn): Descriptor 列(NN):描述符 Relationship: Descriptor 关系:描述符 Relationship: Label text 关系:标签内容 Relationship: Label box 关系:标签框 Relationship: Attribute text 关系:属性内容 Relationship: Attribute descriptor 关系:属性描述符 Bold 粗体 Italic 斜体 Colors: 颜色: Underline 下划线 Form Form Rule: Name 规则:名称 Rule: Descriptor 规则:描述符 Index: Name 索引:名称 Trigger: Name 触发器:名称 Font: 字体: pt pt View: Extended attributes box Tag: Name Tag: Body Placeholder: Body Constraint: Name Constraint: Descriptor Application Unknown exception caught! 捕捉到未知异常! Failed to create initial configuration in `%1'! Check if the current user has write permission over that path and at least read permission over `%2'. BaseConfigWidget A backup of the previous settings was saved into <strong>%1</strong>! BaseForm &Apply 应用(&A) &Cancel 取消(&C) Dialog Dialog &Ok 确定(&O) %1 properties BaseObject Column Constraint 约束 Function 函数 Trigger 触发器 Index 索引 Rule 规则 Table View 视图 Domain Schema 模式 Aggregate 聚合 Operator 操作符 Sequence 序列 Role 角色 Conversion 编码转换 Cast 类型转换 Language 语言 Type 类型 Tablespace 表空间 Operator Family 操作符族 Operator Class 操作符类 Database 数据库 Textbox 文本框 Permission 权限 Parameter 参数 Collation Relationship Type Attribute new_object Extension Event Trigger Tag Basic Relationship Policy Generic SQL BaseObjectView SQL off BaseObjectWidget Name: 名称: Comment: 备注: Tablespace: 表空间: Owner: 所有者: Schema: 模式: This object is protected thus no change in form will be applied to it. 此对象处于受保护状态,无法对它应用任何修改。 Value(s) Version 版本 icone icone Edit permissions 编辑权限 Disable SQL code Collation: Required field. Leaving this empty will raise errors! Edit object's permissions 编辑对象的权限 Disables the generated SQL code using comment tokens (--). This will disable the code of all child and referrer objects. Append or prepend a set of SQL commands to the object's definition. Custom SQL ID: ID: The <em style='color: %1'><strong>highlighted</strong></em> fields in the form or one of their values are available only on specific PostgreSQL versions. Generating SQL code for versions other than those specified in the fields' tooltips may create incompatible code. BaseRelationship rel_%1_%2 BaseTableView Toggles the extended attributes display Connected rels: %1 BugReportForm Bug Report Bug report &Cancel 取消(&C) Create 创建 Use the form below to generate a complete bug report. Please, try to be as clear as possible when describing the actions that can reproduce the bug. Additionally, it's important to attach a sample database model so that the bug can be quickly discovered and fixed! Report 报告 Issue details Output: Select the report's output folder ... <html><head/><body><p>If you prefer it's possible to report this issue anytime on pgModeler's project repository at <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html> Database Model Attach the below database model file to be debugged. Attach a different database model Bug report successfuly generated! Please, send the file <strong>%1</strong> to <em>%2</em> in order be analyzed. Thank you for the collaboration! Load model 打开模型 Database model (*.dbm);;All files (*.*) 数据库模型 (*.dbm);; 所有文件 (*.*) Select report output folder BulkDataEditWidget Bulk data edit CastWidget Assignment 强制转换 Input / Output 输入 / 输出 The function to be assigned to a cast from <em><strong>typeA</strong></em> to <em><strong>typeB</strong></em> must have the following signature: <em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>. 将<em><strong>类型 A</strong></em>转换成 <em><strong>类型 B</strong></em>的函数签名:<em><strong>typeB</strong> function(<strong>typeA</strong>, integer, boolean)</em>. Source data type 原始数据类型 Target data type 目标数据类型 Cast Type: I&mplicit Conversion Func.: E&xplicit CodeCompletionWidget Makes the widget closable only by ESC key or mouse click on other controls. SQL Keyword (no items found.) Make &persistent CollationWidget Locale: Encoding: 编码: LC_COLLATE: LC_COLLATE: LC_CTYPE: LC_CTYPE: The fields <strong><em>Collation</em></strong>, <strong><em>Locale</em></strong>, <strong><em>LC_COLLATE & LC_CTYPE</em></strong> are mutually exclusive, so you have to set only one of them in order to properly handle a collation. Not defined ColorPickerWidget Form Form Generate random color(s) Alt+R Alt+R Select color ColumnWidget Default Value: 默认值: E&xpression: &NOT NULL Se&quence: Edit the underlying sequence's attributes Edit sequence Identity: ConfigurationForm pgModeler Configuration pgModeler 配置 &Apply 应用(&A) &Cancel 取消(&C) Defaults 默认 General 常规 Plug-ins 插件 Any modification made until now in the current section will be lost! Do you really want to restore default settings? 当前部分所做的修改将会丢失!要恢复到默认设置吗? Relationships Appearance Connections Snippets In some cases restore the default settings related to it may solve the problem. Would like to do that? Restore ConnectionsConfigWidget Connections: 连接: Create new connection 建立新连接 Cancel edition 取消编辑 Edit selected connection 编辑选中的连接 Connection Alias: 连接别名: Connection DB: 连接数据库: Host/Port: 主机/端口: User: 用户: Password: 密码: Timeout: 超时: second(s) 秒(s) SSL Mode: SSL 模式: Disable 禁用 Allow 允许 Require 必需 AC verification CA认证 Full verification 双向认证 Client Key: 客户端密钥: Revoked Certs.: 已吊销证书: Force GSSAPI 强制 GSSAPI Add 新建 Update 更新 Test 测试 Delete selected connection 删除选中的连接 Client Certificate: 客户端证书: ~/.postgresql/postgresql.crt ~/.postgresql/postgresql.crt ~/.postgresql/postgresql.key ~/.postgresql/postgresql.key Root Certificate: 根证书: ~/.postgresql/root.crt ~/.postgresql/root.crt ~/.postgresql/root.crl ~/.postgresql/root.crl Success 成功 Edit database connections Duplicate the selected connection General 常规 Other params: Specify additional connection parameters in the form [param]=[value]. These parameters are described in the <strong>libpq</strong> chapter at PostgreSQL docs. Default for: Automatically browses the named database when using this connection to manage databases on <strong>Manage</strong> view. Auto browse Diff Export 导出 Import Validation Security Kerberos Server: Indicates in which operations (diff, export, import or validation) the connection is used if none is explicitly specified by the user. There is a connection being created or edited! Do you want to save it? Found %1 connection(s) No connections found Edit connections Connection successfully established! Server details: PID: `%1' Protocol: `%2' Version: `%3' ConstraintWidget Constraint Type: 约束类型: Fill Factor: 填充因子: Deferrable: 可延迟: Deferral: 延迟: Columns Column: 列: Referenced Columns 引用列 Table: 表: Column Type 类型 ON DELETE: ON DELETE: ON UPDATE: ON UPDATE: Match: No inherit: Exclude Elements Columns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form. This attribute cannot be changed once the object is created. Expression: Indexing: ConversionWidget Source Encoding: 原始编码: Target Encoding: 目标编码: Default Conversion: 默认转换: The function to be assigned to an encoding conversion must have the following signature: <em>void function(integer, integer, cstring, internal, integer)</em>. 编码转换的函数签名:<em>void function(integer, integer, cstring, internal, integer)</em>。 Conversion Func.: CrashHandlerForm Crash Handler Stack trace 堆栈跟踪信息 Input: Load report file for analysis Save the attached model file on the filesystem pgModeler bug report (*.bug);;All files (*.*) Load report Save model 保存模型 Database model (*.dbm);;All files (*.*) 数据库模型 (*.dbm);; 所有文件 (*.*) Crash handler Bug report analysis mode activated. Oops! pgModeler just crashed! 糟糕!pgModeler 崩溃了! We apologize for what happened! It is clear that a nasty bug caused that. Please fill out the form below describing your actions before pgModeler quit unexpectedly. This will help on bug extermination and improve the software. CsvLoadWidget Form Form Load CSV CSV File: Select output file ... Separator: Use the first row as column names in the CSV file. By unchecking this option the first row is used as data. Columns in the first row Load 打开 Semicolon (;) Comma (,) Space Space Tabulation Other ; Text delimiter: " Load CSV file Comma-separted values (*.csv);;All files (*.*) CustomSQLWidget Add custom SQL code SQL code Puts an SELECT command template at current cursor position. &SELECT Puts an INSERT command template at current cursor position. &INSERT Puts an UPDATE command template at current cursor position. &UPDATE Puts an DELETE command template at current cursor position. &DELETE &Clear Append SQL Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command. Append at end of model definition. Prepend SQL Prepend at beginning of model definition. <html><head/><body><p>Use custom commands with extreme caution because you can change the semantics of the entire model when running SQL validation or export processes. Additionally, depending on the amount of commands, those processes can have their performance sensibly degradated.</p></body></html> Generic INSERT Include serial columns Exclude serial columns Generic SELECT Table SELECT Generic UPDATE Table UPDATE Generic DELETE Table DELETE DataManipulationForm Data Manipulation &Close 关闭(&C) Refresh listing F5 F5 Save changes Ctrl+S Ctrl+S Export results to CSV file Ctrl+X Undo modifications Ctrl+Z Ctrl+Z Add empty rows Ins Ins Mark the selected rows to be deleted Del Del Duplicate the selected rows Ctrl+D Filter the result set Table: 表: Schema: 模式: in Hide views Filter expression Order && Limit results (Use <strong>0</strong> for no limit) Limit in: Add Item 添加项目 Remove Item 移除项目 Clear the order by columns list Move selected item up Move selected item down ASC DESC Column: 列: <strong>WARNING: </strong> There are some changed rows waiting the commit! Do you really want to discard them and retrieve the data now? Rows returned: <strong>%1</strong>&nbsp;&nbsp;&nbsp; <em>(Limit: <strong>%1</strong>)</em> none No objects found Found %1 object(s) Views can't have their data handled through this grid, this way, all operations are disabled. The selected table doesn't owns a primary key! Updates and deletes will be performed by considering all columns as primary key. <strong>WARNING:</strong> those operations can affect more than one row. This row is marked to be %1 deleted updated inserted [binary data] <strong>WARNING:</strong> Once commited its not possible to undo the changes! Proceed with saving? delete update insert <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> Copy items on the grid Paste items on the grid Ctrl+V Browse referenced tables Change the values of all selected cells at once Ctrl+E Add new rows from a CSV file Copy as CSV Copy as text Copy items Pase items Browse tables Duplicate row(s) Delete row(s) Edit cell(s) Column Referenced tables (none) Referrer tables DatabaseExplorerWidget Form Form Open the grid to visualize or edit data Data &Grid Alt+G Open a new SQL execution pane ... Ctrl+F6 Update the objects tree Drop this database Expands all items Collapses all items Filters the currently loaded items in the tree by using a pattern and matching their names. If <strong>By OID</strong> is checked the pattern is interpreted as an integer value that represents the object id (OID). <br><br/><strong>HINT:</strong> if you need to search the entire database use the full refresh (<strong>Ctrl+F5</strong>) prior the filtering. Filter: By OID Attribute 属性 Value Show raw attributes (not found, OID: %1) -- Source code not generated! Hit F7 or middle-click the item to load it. -- Admin. roles Alignment Analyze func. Arg. count Arg. default count Arg. defaults Arg. modes Arg. names Arg. types Behavior type By value Cast type Category Collatable Collation Comment Commutator Op. Configuration Conn. limit Constraint 约束 Create DB Create role Curr. version Default 默认 Default value Definition 定义 Delimiter Dest. type Dimension 维度 Directory Dest. encoding Element 元素 Encoding Encrypted Enumerations 枚举 Exec. cost Expression 表达式 Op. family Final func. Function 函数 Func. type Handler func. Handles type Hashes Index type Inherit Ini. condition Inline func. Input func. Internal length Interval type I/O cast Join func. Language 语言 LC COLLATE LC CTYPE Leak proof Left type Length 长度 Library 动态链接库 Can login Materialized Member roles Merges Name 名称 Negator op. Not null Object type OID With OIDs Old version Operator 操作符 Operator func. Output func. Owner Owner column Parents Password Permissions 权限 Precision 精度 Preferred Range attributes Receive func. Ref. roles Replication Restriction func. Return type Returns SETOF Right type Rows amount Schema 模式 Security type Send func. Sort op. Source type Src. encoding State type Storage 存储 Superuser 超级用户 Tablespace 表空间 Type mod. in func. Type mod. out func. Transition func. Trusted Type 类型 Type attribute Types Unlogged Validator func. Validity 合法性 Windows func. false true Cache value Cycle Increment Max. value Min. value Start value Last value Subtype Op. class Canonical func. Subtype diff func. Deferrable For each row Firing 触发 On insert On delete On update On truncate Arguments 参数 Table Trigger func. Columns Condition Deferment Event 事件 Execution mode Commands Position Comparison type Ref. columns Expressions Fill factor No inherit Op. classes Operators 操作符 Ref. table Unique Predicate Collations Inherited Snippets Drop object Drop cascade Truncate Trunc. cascade Show data Reload properties Update 更新 Rename 重命名 Source code 源代码 Quick refresh Full refresh Do you really want to drop the object <strong>%1</strong> <em>(%2)</em>? Do you really want to <strong>cascade</strong> drop the object <strong>%1</strong> <em>(%2)</em>? This action will drop all the other objects that depends on it. Do you really want to truncate the table <strong>%1</strong>? Do you really want to <strong>cascade</strong> truncate the table <strong>%1</strong>? This action will truncate all the tables that depends on it? Src. table: %1 Src. column(s): %2 Ref. table: %1 Ref. column(s): %2 -- Source code genaration for buil-in and base types currently unavailable -- -- Source code unavailable for the object %1 (%2). -- Toggle the display of filter widget as well the system/extension objects. Sort items alphabetically. When unchecked, items are sorted by OID. Sort alphabetically Client encoding Configuration file Data directory Dynamic library path Dynamic shared memory Hba file Listen addresses Max. connections Listen port Server encoding SSL SSL ca file SSL cert file SSL crl file SSL key file Server version Ident file Password encryption Connection ID Server PID Server protocol Referrers Identity Command USING expr. CHECK expr. Roles 角色 RLS enabled RLS forced Show objects filter Show system objects Show extension objects -- Source code unavailable for this kind of object -- Also restart sequences Warning You're running a demonstration version! The data manipulation feature is available only in the full version! <strong>CAUTION:</strong> You are about to drop the entire database <strong>%1</strong>! All data will be completely wiped out. Do you really want to proceed? DatabaseImportForm Settings Options Connection: 连接: Resolve some of the object's dependencies by querying the catalog when a needed object does not exists on the loaded set. In some cases it's necessary to combine this option with others below. This option does not applies to database level objects like role, tablespace and language as well for data types, extensions. Automatically resolve dependencies Random colors will be assigned to imported relationships facilitating the identification of links between tables mainly in large models. Random colors for relationships Enables the import of system built-in objects. It's recommend to select only those objects that are directly referenced by the ones to be imported. WARNING: Try to import a huge set of system objects can bloat the resultant model or even crash pgModeler due to memory/cpu overuse. Import system objects Enables the import of objects created by extensions. Generally there is no need to check this option but if there are objects in the database that directly references this category of objects this mode must be enabled. Import extension objects pgModeler ignores import errors and will try to create as many as possible objects. By checking this option the import operation will be not aborted but an incomplete model will be constructed. This option generates a log file on pgModeler's temp directory. Ignore import errors All catalog queries as well the created objects' source code are printed to standard output (stdout). Debug mode Create all imported objects in the current working model instead of create a new one. Import objects to the working model Database 数据库 Filter: Filter object by it's OID By OID Select all objects ... Clear object selection Expands all items Collapses all items Output Progress label... 处理标签... Cancel 取消 &Import &Close 关闭(&C) <strong>ATTENTION:</strong> You are about to import objects to the current working model! This action will cause irreversible changes to it even in case of critical errors during the process. Do you want to proceed? Importing process aborted! Importing process canceled by user! Importing process sucessfuly ended! No databases found Found %1 database(s) Retrieving objects from database... Retrieving cluster level objects... Retrieving objects of schema `%1'... This is a PostgreSQL built-in data type and cannot be imported. This is a pgModeler's built-in object. It will be ignored if checked by user. Import database Retrieving objects of `%1' (%2)... DatabaseImportHelper Retrieving system objects... `%1' Retrieving objects... `%1' Creating object `%1' (%2)... Import failed to recreate some objects in `%1' tries. Creating permissions for object `%1' (%2)... Creating columns permissions... Updating relationships of `%1' (%2)... Validating relationships... The database import ended but some errors were generated and saved into the log file `%1'. This file will last until pgModeler quit. Creating table inheritances... Destroying unused detached columns... Assigning sequences to columns... Creating object `%1' (%2), oid `%3'... Trying to recreate object `%1' (%2), oid `%3'... DatabaseModel The demonstration version can create only `%1' instances of each object type! You've reach this limit for the type: `%2' Loading: `%1' (%2) Validating relationships... Saving object `%1' (%2) Saving metadata of the object `%1' (%2) Metadata file successfully saved! Process successfully ended but no metadata was saved! Creating object `%1' (%2) Object `%1' (%2) already exists. Ignoring. Loading metadata for object `%1' (%2) Object `%1' (%2) not found. Ignoring metadata. Metadata file successfully loaded! Generating %1 code: `%2' (%3) DatabaseWidget Model Author: 模型作者: Encoding: 编码: Connections: 连接: Default 默认 Template DB: 数据库模板: LC_COLLATE: LC_COLLATE: LC_CTYPE: LC_CTYPE: Attributes 属性 Default Objects Tablespace: 表空间: Schema: 模式: Collation: Owner: 所有者: The fields <strong>LC_COLLATE</strong> and <strong>LC_CTYPE</strong> have pre-configured values based upon the running system. You can freely modify those values if you intend to export the model to another host. Use the above fields to specify the default attributes assigned to new objects created on the database model. Leaving a field empty will cause PostgreSQL to use the default values when exporting the model. Options: 选项: Allow connections Is template DomainWidget Default Value: 默认值: Name: 名称: Attributes 属性 Not null Check constraints Expression: Name 名称 Expression 表达式 DonateWidget Form Form Donate to pgModeler Hide this widget ... <html><head/><body><p>pgModeler is brought to you thanks to a <span style=" font-style:italic;">great effort to create and distribute a quality product</span>. This project is reaching out levels of maturity never imagined. All this is the result of a joint work between its author and the <span style=" font-weight:600;">Open Source community</span>. <br/><br/>This software has a long way to go yet and with your help we'll keep maintaining the good job and bringing new improvements on each release. If you did like pgModeler and thinks it deserves a contribution please make a donation!</p></body></html> I want to help! ElementsWidget Form Form Column: 列: Expression: Collation: Operator Class: 操作符类: Operator: 操作符: Sorting: 正在排序: Ascending 升序 Descending 降序 Nulls first Null 值优先 Element 元素 Type 类型 Operator Class 操作符类 Sorting 排序 Nulls First Null 值优先 Collation Operator 操作符 Expression 表达式 Yes No EventTriggerWidget Event: 事件: Function: 函数: Filter Tag: Tag command Exception Assignment of a pseudo-type to the type of the column! 列类型不能为伪类型! Assignment of a precision greater than the length of the type! 精度不能大于类型长度! Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6! 类型 time,timestamp 或 interval 的精度设置无效。精度必须小于等于 6! Reference to a column which index is out of the capacity of the column list! 不能引用不在列列表中的列! Assignment of not allocated object! 必须设置对象! Removing an object of an invalid type! 不能移除无效类型的对象! Obtaining an object of an invalid type! 不能获取无效类型的对象! Assignment of empty name to table return type! 表的返回值类型的名称不能为空! Reference to an event which does not belongs to trigger! 不能引用不属于触发器的事件! Assignment of a function which language is invalid! 语言转换函数无效! Assignment of empty name to an object! 对象名称不能为空! Assignment of schema object which type is invalid! 模式对象类型无效! Assignment of tablespace object with invalid type! 表空间对象包含无效类型! Assignment of tablespace to an invalid object! 表空间对象无效! Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique! 无效的表空间约束!表空间约束必须是主键约束或唯一约束! Assignment of owner object which type is invalid! 所有者对象的类型无效! Assignment of owner to an invalid object! 所有者对象无效! Reference to a function with invalid type! 引用了无效的函数类型! Reference to an argument of the operator with invalid type! 引用了无效的操作符参数类型! Reference to an operator with invalid type! 引用了无效的操作符类型! Reference to an invalid role type! 引用了无效的角色类型! Assignment of an object that already belongs to another table! 对象已属于另一个表! Assignment of a schema to the sequence which differs from the schema of the owner table! 序列模式与表模式不一致! Assignment of an invalid value to one of the sequence attributes! 序列属性的其中一个值无效! Assignment of a minimum value to the sequence which is greater than the maximum value! 序列的最小值大于其最大值! Assignment of a null increment value to the sequence! 不能给序列设置空的自增值! Assignment of null cache value to the sequence! 序列缓冲值不能为空! Allocation of object with invalid type! 不能创建类型无效的对象! Assignment of not allocated language! 没有指定语言! Assignment of language object which type is invalid! 语言对象的类型无效! Reference to data type with an index outside the capacity of data types list! 引用的数据类型不在数据类型列表的范围内! Assignment of invalid type to the object! 对象的类型无效! Obtaining types with invalid quantity! 正确获取的类型的数量无效! Insertion of item which already exists in the attributes list of the type! 插入的项目已存在于类型属性列表! Insertion of invalid item in the attributes list of the type! 插入类型属性列表的项目无效! Insertion of item which already exists in the enumarations list of the type! 插入的项目已存在于类型枚举列表! Insertion of invalid item in the enumerations list of the type! 插入类型枚举列表的项目无效! Assignment of invalid configuration to the type! 类型的配置无效! Assignment of an invalid strategy/support number to an operator class element! 操作符类元素的策略/支持值无效! Insertion of element which already exists in the element list! 插入的元素已存在于元素列表! Removal of an object not allocated! 不能移除未分配的对象! Operation with object(s) which type(s) is invalid! 操作对象的类型无效! Reference to object with invalid type! 引用对象的类型无效! Operation with object not allocated! 无法操作未分配的对象! The relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user! 强制执行两表 1-1 关系的功能尚未实现,因为它结合模型中由用户定义的两人互相分离的表! Assignment of an invalid expression to the object! 对象的表达式无效! Assignment of a primary key to a table which already has one! 表的主键已存在! A foreign key can not be added to a relationship because is created automatically when this is connected! 无法给关系添加外键,因为在连接时已经自动添加了! Reference to an user-defined data type that not exists in the model! 引用的用户自定义类型不存在于模型! Assignment of invalid maximum size to operation list! 操作列表的最大值无效! One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns! 一个或者多个对象无效,并自动删除了。因为他们引用的表列所在的关系已经不存在了,由于连接中断或者排除生成的列! Reference to an invalid privilege type! 引用了无效的权限类型! Assignment of privilege incompatible with the type of object referenced by permission! 权限与被允许引用的对象的类型不一致! It is not possible to create arrays of domains or sequences (dimension >= 1)! PostgreSQL does not yet implement this feature! 无法创建维数 > = 1域或序列数组!PostgreSQL 尚未实现此功能! Assignment of invalid name to the table generated from N-N relationship! 分配无效名称给由 N-N 关系生成的表! Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns! 主键,外键,唯一键等约束必须有至少一列来关联他们!对于外键约束引用列必须被选中! The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack! ** Executed SQL command: ** %1 导出失败,PostgreSQL 服务器执行 SQL 命令时发生错误!详情请查看返回的异常信息! ××执行的 SQL 语句:×× %1 One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details. 插件加载发生错误,一个或多个插件没有激活!详情请查看异常信息。 Assignment of empty XML buffer to parser! 分配空白 XML 缓存给解析器! Assignment of empty DTD file name! 分配一个空 DTD 文件名! Assignment of empty name to the DTD declaration! 分配空白名称给 DTD 声明! Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated! 操作在未分配的元素树上!必须要先载入 XML 解析器缓存并执行解析,这样树才能生成! Operation with unallocated tree element! 操作在未分配的树元素上! Operation with element which does not exists in the element tree currently loaded! 操作的元素,在当前载入的元素树中不存在! Assignment of a value to an invalid connection parameter! 给一个无效的连接参数分配一个值! Operation on connection not established! 未能成功连接! Attempt to connect without define configuration parameters! 尝试没有定义配置参数的连接! Assignment of not allocated SQL command result! 指定的 SQL 命令结果不存在! Unable to allocate the result of the SQL command because the response from the DBMS was not understood by the client! 无法获得 SQL 命令结果,因为服务器端的反馈客户端无法识别! Reference to a column of tuple with invalid index! 引用的一列元组索引无效! Reference to a column of tuple with invalid name! 引用的一列元组名字无效! Assignment of a not allocated column to object `%1' (%2)! Assignment of a not allocated schema to object `%1' (%2)! The object `%1' (%2) has inconsistent SQL or XML definition! The object `%1' (%2) already exists on `%3' (%4)! The object `%1' (%2) cannot be assigned because there is already exists in the container object `%3'! Assigning object of an invalid type! The insertion of the parameter `%1' will not be possible because there is another parameter with same name in the function `%2'! The insertion of the table return type `%1' will not be possible because there is another return type with the same name in the `%2'! Reference to a parameter which index is out of the parameter list bounds! The column `%1' cannot be assigned to the trigger `%2' because they belongs to different parent tables! Assignment of a not allocated function to object `%1' (%2)! Assignment of a function which return type is different from `%1'! Assignment of a function which parameter count is invalid to the object `%1' (%2)! Event trigger function must be coded in any language other than SQL! Assignment of not allocated table to object `%1' (%2)! Reference to an argument which index is out of argument list bounds! Assignment of a name which contains invalid characters! Assignment of a name which length exceeds the maximum of 63 characters! Assignment of appended or prepended SQL to an invalid object! Assignment of value to an invalid option type on role! The insertion of the role `%1' is not possible because this is already being referenced by role `%2'! Reference redundancy detected by having the role `%1' referencing the role `%2'! The role `%1' can not be listed as a member of itself! Reference to a role which index is out of role list bounds! Insertion of empty command to the rule! Reference to a command which index is out of the command list bounds! Is not possible to create a self generalization/copy relationship! The table can not inherit or copy their own attributes! Assignment of a start value to the sequence which is extrapolating the range defined by minimum and maximum values! Assignment of owner table which is not in the same schema as the sequence `%1'! Assignment of owner table which does not belong to the same owner of the sequence `%1'! Assignment of a nonexistent owner column to the sequence `%1'! Assignment of an owner column to the sequence `%1' that is not related to any table! Reference to a label which index is out of labels list bounds! Assignment of a function with invalid return type to object `%1' (%2)! Assignment of a function with invalid parameter(s) type(s) to object `%1' (%2)! Assignment of a null type to object `%1' (%2)! Assignment of an empty directory to object `%1' (%2)! Reference to an attribute which index is out of the attributes list bounds! Reference to an enumeration which index is out of the enumerations list bounds! Assignment of an operator which input type count is invalid to aggregate function! Assignment of an operator which types of arguments is invalid! Assignment of system reserved name to the object `%1' (%2)! One function with invalid configuration is been used by the object `%1' (%2)! Reference to an element which index is out of element list bounds! Reference to an object which index is out of object list bounds! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4)! The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4) that belongs to `%5' (%6)! The creation of the relationship `%1' between the table `%2' and `%3' can not be done because one does not have a primary key. If the relationship is of the type n-n both tables must have primary keys! Identifier relationship can not be created for a self relationship, relationships of the type n-n, copy or generalization! Unable to create a copy relationship because the column `%1' in table `%2' already exists in table `%3'! Unable to create the generalization relationship because the column `%1' in table `%2' can not be merged with the column `%3' of table `%4' because they have incompatible types! Unable to create the generalization relationship because the constraint `%1' in table `%2' can not be merged with the constraint `%3' of table `%4' due to their incompatible composition! An attribute can not be added to a copy or generalization relationship! The object `%1' (%2) is referencing the object `%3' (%4) which was not found in the model! Unable to write the file or directory `%1'! Make sure the output directory exists, or if the user has write permissions over it! Unable to write the file `%1' due to one or more errors in the definition generation process! The configuration of the relationship `%1' generates a redundancy between the relationships `%2'. Redundancy on identifier or generalization/copy relationships are not accepted since they result in incorrect column spreading making the model inconsistent! The primary key `%1' can only be allocated if declared within a block of code that defines a table or relationship! Insertion of a role which already exists in the role list of the permission! There is already a permission on object `%1' (%2) which has one or more equal roles from those present on permission to be assigned to the object! A permission is referencing the object `%1' (%2) which was not found in the model! The object `%1' (%2) can not be created because its not being assigned to any schema! The tablespace `%1' can not be inserted into the model because it points to the same directory as the tablespace `%2'! The function `%1' can not get a source code as a definition because its language is set to C. Use the attributes symbol and dynamic library instead! The function `%1' can have the attributes symbol and dynamic library configured only if the language is set to C. For all other cases you must specify a source code that defines it in the DBMS! The operator `%1' can not be assigned as a comutator of operator `%2' because it has incompatible settings! The operator `%1' can not be assigned as negator of operator `%2' because it has incompatible settings! The type `%1' can not self refer in the attributes `element' or `copy type' or be used as a data type of an attribute in the configuration of a composite type! Assignment of invalid element to type `%1'! Assignment of invalid alignment to type `%1'! The relationship `%1' can not make use of the special primary key because it is marked as identifier or it is a self relationship! The object `%1' (%2) can not be edited or deleted because it was automatically included through a relationship! If the object is an attribute or constraint the modifications must be done on the relationship editing form. The object `%1' (%2) can not be deleted because it is protected! The group `%1' has already been declared earlier! The group `%1' can not be built in the groups declaration block (%2)! The group `%1' was built but not declared in the groups declaration block (%2)! The group `%1' can not be built without possessing child elements! The group `%1' can not be built once more because this was done in previous blocks! The group `%1' has been declared but not built! Reference to a column of the objects table with invalid index! Reference to a row of the objects table with invalid index! The object `%1' (%2) can not be manipulated because it is reserved to PostgreSQL! This object is present in the database model only as a reference! The new configuration of the function invalidates the object `%1' (%2)! In this case it is needed to undo the relationship between the affected object and function in order to the new configuration to take effect! A view reference must be used in at least one these SQL scopes: View Definition, SELECT-FROM, FROM-WHERE or After WHERE! Could not find the default settings file `%1'! To restore default settings check the existence of the file and try again! Could not load the plugin `%1' from the library `%2'! Message returned by plugin manager: `%3' Error while interpreting XML buffer at line %1 column %2. Message generated by the parser: %3. %4 Attempt to start a connection already stablished! Could not connect to the database. Message returned: `%1' Unable to allocate command result for the SQL because the server has generated a fatal error! Message returned by the DBMS: `%1' Reference to a tuple with an invalid index or the result is empty (no tuples)! Reference to a column of a tuple which was not yet initialized (tuple navigation not started)! Could not execute the SQL command. Message returned: `%1' Invalid use of a view reference as whole SQL definition! The assigned reference must be an expression! Assignment of a second definition expression to the view! It is not possible mix ordinary references (SELECT-FROM, FROM-WHERE, After WHERE) with references used as view SQL definition! Assignment of collation object which type is invalid! At the moment pgModeler does not support the creation of primary keys which some columns were generated by relationship connection. To create primary keys with this feature you can use the field `Identifier' or the tab `Primary key' on relationship editing form! Collations must be created at least with attributes LC_COLLATE and LC_CTYPE defined! The object `%1' (%2) cannot reference itself! This operation is not permitted for this kind of object! Only operator families which uses `btree' as indexing method are accepted by operator class elements! Reference to an invalid copy table option! Copy relationship between tables `%1' and `%2' cannot be done because the first one already copies attributes from `%3'! Tables can have only one copy table! The INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers! The TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table! The INSTEAD OF mode cannot be used on view triggers that executes for each statement! Constraint triggers can only be executed on AFTER events and for each row! A view trigger cannot be AFTER/BEFORE when it executes for each row! A trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event! Assignment of a column which has no parent table to the object `%1' (%2)! Only constraint triggers can be deferrable or reference another table! Reference to a function id which is incompatible with the user define type configuration! The operator class assigned to the object `%1' (%2) must use `btree' as indexing method! The validation process failed due to an error triggered by the validation helper. For more details about the error check the exception stack! The extension `%1' is registered as a data type and cannot have the attribute `handles datatype' modified! The fk relationship `%1' cannot be created because the foreign-key that represents it was not created on table `%2'! Assignement of an invalid object name pattern to the relationship `%1'! Reference to an invalid object name pattern id on the relationship `%1'! Invalid use of variadic parameter mode! This mode can be used only with an array or "any" data type! Mixing incompatibles DBMS export modes: `ignore object duplications', `drop database' or `drop objects' cannot be used with `simulate export'! Mixing incompatibles DROP options: `drop database' and `drop objects' cannot be used at the same time! Invalid object id swapping operation! The objects involved are the same! Invalid object id swapping operation! The database itself, tablespaces or roles cannot have the ids swapped! The widget already has a parent and cannot be assigned to a different object! Could not load the database model file `%1'. Check the error stack to see details. Try to run `pgmodeler-cli --fix-model' in order to correct the structure of the file if that is the case. The column `%1' cannot reference it's parent table `%2' as data type! Operation with an invalid element id `%1'! Reference to an invalid color id `%1' for element `%2'! Assignment of an invalid object to `%1' (%2)! The assigned object must be of type `%3'. The sequence `%1' can't be assigned to the column `%2' because the data type of the latter is incompatible. The type used must be an integer one! The option to generate temporary object names can only be used in simulation mode! It's not possible convert the type of the column `%1' to serial! It must have an `integer' based type and its default value must be a call to `nextval(seq_name::regclass)' function or a sequence object must be directly assigned to the column! Could not assign the variable `%1' to event trigger's filter. Currently, PostgreSQL supports only the `TAG' variable! Could not perform the `%1' operation on `%2' using the data on row `%3'! All changes were rolled back. ** Returned error ** %4 Malformed unescaped value on row `%1' column `%2'! Trying to undo/redo an invalid operation over an object that does not exists anymore or can't be handled! The operation history will be cleaned up. The object `%1' (%2) can't be handled because some needed fields are not set! Please, make sure to fill at least the requires fields in order to properly create or update the object. A relationship can only be swapped by other object of the same kind! A parent table of `%1' which OID is `%2' was not found in the set of imported objects! The enumeration `%1' can't be assigned to the type `%2' because contains invalid characters! The enumeration `%1' can't be assigned to the type `%2' because is too long! The connection was idle for too long and was automatically closed! The connection was unexpectedly closed by the database server `%1' at port `%2'! There is already a relationship between `%1' (%2) and `%3' (%4) in the model! When using relationships of the type generalization, copy and one-to-one there can't be other relationships linked to the pair of tables. Unable to load the configuration file `%1'! Please check if file exists in its folder and/or if it is not corrupted! Invalid syntax in file `%1', line %2, column %3! Invalid instruction `%1' on file `%2', line %3, column %4! Unknown attribute `%1' in file `%2', line %3, column %4! Invalid metacharacter `%1' in file `%2', line %3, column %4! Invalid operator `%1' in comparison expression, file `%2', line %3, column %4! Attribute `%1' with an undefined value in file `%2', line %3, column %4! Attribute `%1' with an invalid name in file `%2', line %3, column %4! Could not access the file or directory `%1'! Make sure that it exists or if the user has access permissions on it! Could not load file `%1'. The same appears to be inconsistent or one of its dependencies (DTD files) has errors or is missing! Unsupported PostgreSQL version (%1) detected! Valid versions are between %2 and %3. The object `%1' (%2), oid `%3', could not be imported due to one or more errors! Check the exception stack for more details. `HINT:' if the object somehow references objects in `pg_catalog' or `information_schema' consider enable the importing of system objects. Failed to drop the database `%1' because it is defined as the default database for the connection `%2'! The column `%1' must be `NOT NULL' because it composes the primary key of the table `%2'. You need to remove the column from the mentioned contraint in order to disable the `NOT NULL' on it! The identity column `%1' has an invalid data type! The data type must be `smallint', `integer' or `bigint'. Reference to an invalid affected command in policy `%1'! Reference to an invalid special role in policy `%1'! ExtensionWidget Version: 版本: Old Version: This attribute cannot be changed once the object is created. Handles data type FindReplaceWidget Form Form Replace one occurrence Replace Replace all occurrences Replace All Replace the selection and find the next one Replace && Find Replace: Find: Find previous Shift+F3 Find next F3 F3 Case sensitive Regular expression Whole words Hide this widget ... FunctionWidget Attributes 属性 Function Type: 函数类型: Execution Cost: 执行开销: Rows Returned: 返回行数: Behavior: 行为: Security: 安全: Return Method: 返回方法: Set Parameters 参数 Definition 定义 Dynamic Library: 动态库: Symbol: 符号: Library: 库: Source code: 源代码: Column Type 类型 Name 名称 Default Value 默认值 Return Table 返回表 Si&mple Tab&le Windown Func. Leakproof Mode Language: GeneralConfigWidget Operation history: 操作记录: Print grid 打印网格 Print page numbers 打印页码 Paper: 纸型: Orientation: 方向: Portrait 纵向 Landscape 横向 Milimeters 毫米 Inches 英寸 Centimeter 厘米 Left: 左: Left margin 左边距 Top: 上: Top margin 上边距 Right: 右: Right margin 右边距 Form Form A0 (841 x 1189 mm) A0 (841 x 1189 mm) A1 (594 x 841 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A3 (297 x 420 mm) A4 (210 x 297 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) A9 (37 x 52 mm) B0 (1030 x 1456 mm) B0 (1030 x 1456 mm) B1 (728 x 1030 mm) B1 (728 x 1030 mm) B10 (32 x 45 mm) B10 (32 x 45 mm) B2 (515 x 728 mm) B2 (515 x 728 mm) B3 (364 x 515 mm) B3 (364 x 515 mm) B4 (257 x 364 mm) B4 (257 x 364 mm) B5 (182 x 257 mm) B5 (182 x 257 mm) B6 (128 x 182 mm) B6 (128 x 182 mm) B7 (91 x 128 mm) B7 (91 x 128 mm) B8 (64 x 91 mm) B8 (64 x 91 mm) B9 (45 x 64 mm) B9 (45 x 64 mm) C5E (163 x 229 mm) C5E (163 x 229 mm) Comm10E (105 x 241 mm) Comm10E (105 x 241 mm) DLE (110 x 220 mm) DLE (110 x 220 mm) Executive (191 x 254 mm) Executive (191 x 254 mm) Folio (210 x 330 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Ledger (432 x 279 mm) Legal (216 x 356 mm) Legal (216 x 356 mm) Letter (216 x 279 mm) Letter (216 x 279 mm) Tabloid (279 x 432 mm) Tabloid (279 x 432 mm) Pixels 像素 Bottom: 下: Bottom margin 下边距 General && Design General 常规 Check if there is a new version on server Design Disable antialiasing for lines and texts improving performance when handling huge models. Disable render smoothness Triggers a dialog asking the user to validate the model before a save, export or diff operation. Validate before save, export or diff Start move the canvas when the cursor is on the canvas edges Move canvas by keep mouse on corners Graphical objects (table, views and textboxes) will be created in a single step without the need to click on canvas Simplify creation of graphical objects After loading the model the last zoom and position on canvas will be restored Save and restore last position and zoom When enabled this option creates a placeholder object at the previous table's position when starting to move it. This will cause graphical updates on relationship lines to be performed only when the drag & drop action is done improving the performance. Disabling placeholders will cause those updates to be executed every time the table's position changes a single pixel (classical behavior). Use placeholders when moving tables Hide the portion of table which represent triggers, indexes and rules Hide table extended attributes Hide the object which represents the tag assigned to the table Hide table tags Hide the object that represents the relationship name Hide relationship name Toggles the code completion in all fields that accepts the input of SQL commands. Enable SQL code completion Printing && Code Code style Size: Font: 字体: Colors: 颜色: Options: 选项: Display line numbers Highlight lines at cursor's position pt pt Custom tab width: Printing Custom Unity: Custom Size: Width: Height: Page Margins: Line numbers' font color Line numbers' background color Highlighted line color The little brown fox jumps over the lazy dog Minimum object opacity (%): Defines the minimum opacity percentage applied to the objects when using the fade out feature. A zero opacity causes the object to be completely hidden not being possible to interact with it in the canvas area. Canvas grid size: Defines the vertical and horizontal grid size. This value affects the spacing of objects when using object grid alignment feature. By default the range selection is triggered with Shift + left click. By checking this option range selection will be activated only with a single click and move. Trigger range selection with a single click Defines the maximum amount of elements held in the operation history. Once reached the maximum number the history is automatically cleaned. Defines the period when the opened models will be saved automatically. Autosave interval (minutes): Replaces any straight line in relationship by curved ones in order to improve the model's visualization. Use curved lines for relationships Souce code editor args: lines Clear the entire SQL comand history. Clear history Open in file manager 在文件管理器中打开 Overrides the default user interface language defined by the system. Requires restarting the program. <strong>NOTE:</strong> UI translations are third party collaborations thus any typo or mistake should be reported directly to their respective maintainers. SQL history max. length: Check updates at startup User interface language: Browse the source code editor application Souce code editor: Configurations directory: System default All files (*.*) Load file GenericSQLWidget SQL code HintTextWidget Form Form IndexWidget Fill Factor: 填充因子: Options: 选项: Concurrent 并发 Fast update 快速更新 Elements 元素 Attributes 属性 Indexing: Unique Buffering Predicate: LanguageWidget Trusted: 可信: The functions to be assigned to the language should have, respectively, the following signatures:<br/><br/> <strong>Handler Function:</strong> <em>language_handler function()</em><br/> <strong>Validator Function:</strong> <em>void function(oid)</em><br/> <strong>Inline Function:</strong> <em>void function(internal)</em> 语言处理函数的签名分别为:<br/><br/> <strong>处理函数:</strong> <em>language_handler function()</em><br/> <strong>验证函数:</strong> <em>void function(oid)</em><br/> <strong>内联函数:</strong> <em>void function(internal)</em> Validator Func.: Handler Func.: Inline Func.: MainWindow &File 文件(&F) &Edit 编辑(&E) &Show 视图(&S) New 新建 Zoom - 缩小 Show grid 显示网格 Show the page delimiters 显示分页符 Save '%1' as... 保存 '%1' 为... Confirmation 确认 Load model 打开模型 Show the model overview 显示模型概览 pgModeler - PostgreSQL Database Modeler pgModeler - PostgreSQL 数据库建模工具 Plugins 插件 Ctrl+N Ctrl+N Ctrl+S Ctrl+S Zoom in 放大 Ctrl+= Ctrl+= Zoom out 缩小 Ctrl+- Ctrl+- Ctrl+O Ctrl+O Ctrl+P Ctrl+P Ctrl+Z Ctrl+Z Ctrl+Y Ctrl+Y Ctrl+G Ctrl+G Ctrl+0 Ctrl+0 Align objects position to grid 对齐对象到网格 Ctrl+L Ctrl+L Save all 保存全部 Database model printing 正在打印数据库模型 Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing. 模型的纸型/页边距已改变,这可能导致对象打印出错。要使用新的设置继续打印吗?要使用默认设置,请单击“否”或“取消”中止打印。 Database model (*.dbm);;All files (*.*) 数据库模型 (*.dbm);; 所有文件 (*.*) Save model 保存模型 Ctrl+Q Ctrl+Shift+S Ctrl+W Ctrl+H F10 F10 F1 F1 This action will open a web browser window! Want to proceed? Saving temp. models Toogle the model validation widgets &Validation Alt+V Toggle the object finder Find Object Ctrl+F Toggle the operation history widget &Operations Alt+O Toggle the model objects widget O&bjects Alt+B He&lp Pl&ugins General 常规 Controls &New New model &Save &Zoom in Zoo&m out &Load Sa&ve as E&xit Exit pgModeler &About pgModeler F4 F4 &Print Print model &Undo Undo operation &Redo Redo operation &Export 导出(&E) Export the current opened model in different modes Ctrl+Shift+E &Show grid &Close 关闭(&C) Close current model &Normal zoom &Align to grid Show &delimiters &Settings Edit pgModeler settings F12 F12 &Overview &Support Access the support page New object 新建对象 Access the list of loaded plugins &Recent Models Load recently opened model &Import Import existing database to new model (reverse engineering) Ctrl+Shift+I Rest&ore Session &Fix a model New version found! Update for the current version is available on project's site &Check for update action_main_menu Main menu Show expanded Expands the main menu bar in classical mode Hide main menu Hides the main menu bar and put the action on a separated action Ctrl+Shift+H &Diff Ctrl+Shift+D Welcome Welcome screen Shift+W Design Design database models Shift+D Manage Manage existent databases Shift+M &Bug report Report a bug Donate Help pgModeler by donating! Objects me&tadata Objects metadata (Demo) Save modified model(s) The following models were modified but not saved: %1. Do you really want to quit pgModeler? Clear Menu The demonstration version can create only `one' instance of database model! The model <strong>%1</strong> was modified! Do you really want to close without save it? Warning You're running a demonstration version! The model saving feature is available only in the full version! <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! It's recommended to validate it before save in order to create a consistent model otherwise the generated file will be broken demanding manual fixes to be loadable again! Save anyway Validate <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the export process it's recommended to validate in order to correctly create the objects on database server! Export anyway <strong>WARNING:</strong> The model <strong>%1</strong> is invalidated! Before run the diff process it's recommended to validate in order to correctly analyze and generate the difference between the model and a database! Diff anyway Could not load the database model file `%1'. Check the error stack to see details. You can try to fix it in order to make it loadable again. Fix model Cancel 取消 Access support page (no samples found) You're running a demonstration version! Note that you'll be able to create only <strong>%1</strong> instances of each type of object and some key features will be disabled or limited!<br/><br/>You can purchase a full binary copy or get the source code at <a href='http://pgmodeler.com.br'>pgmodeler.com.br</a>. <strong>NOTE:</strong> pgModeler is an open source software, but purchasing binary copies or providing some donations will support the project and cover all development costs.<br/><br/> <strong>HINT:</strong> in order to test all features it's recommended to use the <strong>demo.dbm</strong> model located in </strong>Sample models</strong> at <strong>Welcome</strong> view.<br/><br/><br/><br/> save export diff Executing pending <strong>%1</strong> operation... Determine the changes between model/database and another database Arrange objects Rearrange objects over the canvas Grid Hierarchical Scattered Rearrange objects over the canvas is an irreversible operation! Would like to proceed? Messagebox Dialog Dialog msg 信息 Exceptions 异常 Show raw text errors or information. Show/hide exceptions stack. 显示/隐藏异常堆栈。 ... &Yes 是(&Y) &No 否(&N) Cancel 取消 &Ok 确定(&O) &Cancel 取消(&C) Error 错误 Alert 警告 Information 信息 Confirmation 确认 MetadataHandlingForm Handle metadata &Apply 应用(&A) &Cancel 取消(&C) Handle objects metadata Settings Extract from: Loading a metadata file to the current model is an irreversible operation so be sure to specify a backup file before proceed. Options Handles the following database model attributes in the metadata file: author, zoom factor, last position and default objects. Database model metadata Handles the objects' positioning in the metadata file. Objects' positioning Handles the objects' custom colors in the metadata file. Currently available only for relationships and schemas. Custom object's colors Handles the objects' protection status in the metadata file. Objects' protection status Handles the objects' SQL disabled status in the metadata file. Objects' SQL disabled status Handles the objects' custom SQL commands in the metadata file. Custom SQL commands Textbox objects Tag objects Backup file: Select file ... Apply to: Operation: Output Progress label... 处理标签... model not saved yet The backup file cannot be the same as the input model! Extracting metadata to file `%1' Saving backup metadata to file `%1' Applying metadata from file `%1' Metadata processing aborted! Objects metadata file (*.omf);;All files (*.*) Handles the objects' fade out status in the metadata file. Objects' fade out status Save tags to the output file when extracting metadata. When loading the file, the tags are recreated and duplicated ones are ignored. Save textboxes to the output file when extracting metadata. When loading the file, the textboxes are recreated and duplicated ones are ignored. Handles the tables' and views' extended attributes display status in the metadata file. Tables' extended attributes display Save generic SQL objects to the output file when extracting metadata. When loading the file, the objects are recreated and duplicated ones are ignored. Generic SQL objects Extracts the objects' metadata from the loaded models and apply to the current focused model. A backup file can be specified to where the focused model's current metadata will be saved. &Extract and restore Extracts the objects metadata from one of the loaded models saving the info to a backup file. Extract &only Reads the objects' metadata from a previously saved backup file and apply to the current model. &Restore a backup file ModelDatabaseDiffForm Settings Connection: 连接: Database: Ignores as many as possible errors on import step. This option generates an incomplete diff. Ignore import errors Clears the data of all tables which will have columns modified. This is useful to avoid errors related to type casting. <strong>WARNING:</strong> DO NOT use this option on production servers and always make a backup before use it. Import system (built-in) objects. Use this if the import step is returning errors related to missing objects. Import system objects Import objects created by extensions. Use this if the import step is returning errors even importing built in ones. Import extension objects For DROP command, the objects that depends on an object to be dropped will be deleted as well. For TRUNCATE command, tables that are linked to a table to be truncated will be truncate too. <strong>NOTE:</strong> this option can affect more objects than listed in the output or diff preview. Drop or truncate in cascade mode Permissions already set on database objects will be kept.The ones configured on the model will be applied to the database. Keep object's permissions Database cluster level objects like roles and tablespaces will not be dropped. Keep cluster objects Recreate only unmodifiable objects Instead of use an ALTER command to modify certain kind of objects a DROP and CREATE will be used in order to do a full modification. This option does not affects the database object. Force recreation of objects Ignores errors generated by duplicated objects when exporting the diff to database. Ignore duplicity errors Serial columns are converted to integer and having the default value changed to <strong>nextval(sequence)</strong> function call. By default, a new sequence is created for each serial column but checking this option sequences matching the name on column's default value will be reused and will not be dropped. Reuse sequences on serial columns No command to rename the destination database will be generated even the model's name differ from database name. Preserve database name Avoid the generation of DROP commands for objects that exists in database but not in the model. This is useful when diff a partial model against the complete database. Do not drop missing objects Diff mode Override the PostgreSQL version when generating the diff. The default is to use the same version as the input database. Use PostgreSQL: Compares the model and the input database storing the diff in a SQL file for later usage. Store in S&QL file File: 文件: Select output file ... Compares the model and the input database generating a diff and applying it directly to the latter. <strong>WARNING:</strong> this mode causes irreversible changes on the database and in case of failure the original structure is not restored, so make sure to have a backup before proceed. Appl&y on server Output Changes: Cancel 取消 Progress label... 处理标签... Step label... <html><head/><body><p>Objects marked with an <span style=" font-weight:600;">ALTER</span> may not be effectively changed unless that the differences detected are in attributes that can be modified through ALTER commands otherwise no operationwill be performed or, if the force recreation is checked, the object will be dropped and created again.</p></body></html> Objects to be created 0 0 Objects to be dropped Possible objects to be changed Ignored objects (system ones or with sql disabled) Diff Preview &Apply diff &Generate &Close 关闭(&C) Waiting process to start... Confirmation 确认 <strong>WARNING:</strong> The generated diff is ready to be exported! Once started this process will cause irreversible changes on the database. Do you really want to proceed? Apply diff Preview diff Diff process paused. Waiting user action... Saving diff to file <strong>%1</strong> Diff process sucessfully ended! No operations left. Operation cancelled by the user. Process aborted due to errors! -- SQL code purposely truncated at this point in demo version! -- No differences were detected between model and database. -- Error code <strong>%1</strong> found and ignored. Proceeding with export. Save diff as... SQL code (*.sql);;All files (*.*) SQL 代码 (*.sql);;所有文件 (*.*) Diff tool Generate diff code Source database Current model: (model) Compare to Diff Froce the generation of DROP commands for columns and constraints that exist in database but not in the model. This is useful when diff a partial model against the complete database and the user needs to drop columns and constraint but preserve the rest of the objects. Drop missing columns and constraints Truncate tables before alter columns Import && Export Import Export 导出 This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes model not saved yet (none) Step %1/%2: Importing database <strong>%3</strong>... Step %1/%2: Comparing <strong>%3</strong> and <strong>%4</strong>... Step %1/%2: Exporting diff to database <strong>%3</strong>... ModelExportForm File: 文件: Select target file 选择目标文件 PostgreSQL version in which the SQL code should be generated 生成 SQL 代码的 PostgreSQL 版本 Show grid 显示网格 Ignore object duplicity 忽略重复对象 Connection: 连接: &Export 导出(&E) &Close 关闭(&C) Initializing model export... 正在初始化模型导出... Saving file '%1' 正在保存文件 '%1' Exporting process sucessfuly ended! 成功导出! Export model as... 导出模型为... ... ... PostgreSQL: PostgreSQL: Progress label... 处理标签... Export model Settings Database server pgModeler ignores errors generated by duplicated objects and creates only that ones which does not exists in the database. This option may be used when an object was created after a previous model export. PostgreSQL version in which the SQL code should be generated. It is recommended to select this option only when the version of the DBMS, somehow, is not identifiable or if you need to generate a specific version of SQL code for test purposes. If <strong>DB</strong> is checked pgModeler will destroy the database if already exists on the server. When <strong>Objects</strong> is checked pgModeler will execute the DROP command attached to SQL-enabled objects. <strong>WARNING:</strong> this option leads to data loss so make sure to have a backup first. Drop: DB Ob&jects pgModeler will destroy the database if already exists on the server. Make sure to have a backup before use this option because all data will be lost. Graphics file Type: 类型: Zoom: Show delimiters 显示分页符 Exporting the model page by page will generate files with a <strong>_p[n]</strong> suffix where <strong>n</strong> is the page id. Check if the current user has write permission on output folder. Page by page SQL file Output Cancel 取消 Error code <strong>%1</strong> found and ignored. Proceeding with export. Exporting process aborted! SQL script (*.sql);;All files (*.*) Portable Network Graphics (*.png);;All files (*.*) Scalable Vector Graphics (*.svg);;All files (*.*) Exporting process canceled by user! This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes I&mage (PNG) &Vectorial (SVG) ModelExportHelper Generating SQL code for PostgreSQL `%1' Output SQL file `%1' successfully written. Rendering objects to page %1/%2. Output image `%1' successfully written. Exporting model to SVG file. SVG representation of database model SVG file generated by pgModeler Output file `%1' successfully written. Starting export to DBMS. PostgreSQL version detection overridden. Using version `%1'. PostgreSQL `%1' server detected. Generating temporary names for database, roles and tablespaces. Enabling the SQL code for database `%1' to avoid errors. Ignoring object duplication errors. Ignoring the following error code(s): `%1'. Trying to drop database `%1'. Simulation mode activated. Creating object `%1' (%2) Creating database `%1' Connecting to database `%1' Generating SQL for `%1' objects... Destroying objects created on the server. Restoring original names of database, roles and tablespaces. Renaming `%1' (%2) to `%3' Dropping object `%1' (%2) Changing object `%1' (%2) Running auxiliary command. ModelFixForm Model file fix Fix model file <html><head/><body><p>[pgmodeler-cli not found error]</p></body></html> pgmodeler-cli: Browse for pgmodeler-cli tool ... The specified file is not the pgModeler command line tool (pgmodeler-cli). Input file: Output file: Fix tries: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Waiting process to start...</span></p></body></html> Select input file Select output file Load fixed model when finish In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. <strong>NOTE:</strong> relationships may lost their graphical configuration like custom points and line color. &Fix &Close 关闭(&C) Waiting process to start... Could not locate <strong>%1</strong> tool on <strong>%2</strong>. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below. pgModeler command line tool (%1) ModelNavigationWidget Form Form Previous model Ctrl+Left Next model Ctrl+Right Close model 关闭模型 ... Alt+C (model not saved yet) ModelObjectsWidget Model Objects 1 1 Object 对象 Type 类型 Parent Object 父对象 Parent Type 父类型 Select All 选择全部 Clear All 取消全部 Select 选择 Cancel 取消 Tree view 树视图 ... List view 列表视图 Objects view configuration 对象视图配置 Expands all items Collapses all items New 新建 Hide this widget ID Return Esc Filter: By ID Visible object types Model objects ModelOverviewWidget Model overview 模型概览 Failed to generate the overview image. The requested size %1 x %2 was too big and there was not enough memory to allocate! ModelRestorationForm Model restoration 模型恢复 &Restore 恢复(&R) &Cancel 取消(&C) pgModeler was not closed properly in a previous execution and some models were still being edited. Click <strong>Restore</strong> to reopen the models or <strong>Cancel</strong> to abort the restoration. pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler. Keep temporary models in case of restoration failure Database 数据库 File 文件 Modified Size ModelValidationHelper There are pending errors! SQL validation will not be executed. Operation canceled by the user. ModelValidationWidget Form Form Hide this widget ... Enables the validation of SQL code in DBMS. This process requires the use of a pre-configured connection. SQL validation will occur only in the last step (when all objects were validated) or when there are no warnings. SQL Validation: Connection to be used in the SQL validation PostgreSQL version pgModeler will generate unique and temporary names for database, role and tablespace objects. This option avoids object duplication errors when running the SQL validation. Use unique temporary names for cluster level objects Clear validation results Clear Try to resolve the reported issues. Ctrl+S Ctrl+S Change the creation order for two objects by swapping their ids Va&lidate Warnings: does not prevents model to be saved. 0 0 Errors: model will not be saved while there are validation errors. Cancel the SQL validation in progress. Cancel 取消 Esc Try to apply a fix on the selected validation info. Options Autodetect The object <strong>%1</strong> <em>(%2)</em> [id: %3] is being referenced by <strong>%4</strong> object(s) before its creation. The object <strong>%1</strong> <em>(%2)</em> [id: %3]%4 is referencing columns created by <strong>%5</strong> relationship(s) but is created before them. The object <strong>%1</strong> <em>(%2)</em> has a name that conflicts with <strong>%3</strong> object's name(s). The relationship <strong>%1</strong> [id: %2] is in a permanent invalidation state and needs to be relocated. SQL validation failed due to error(s) below. <strong>NOTE:</strong><em> These errors does not invalidates the model but may affect operations like <strong>export</strong> and <strong>diff</strong>.</em> <strong>HINT:</strong> try to swap the relationship by another ones that somehow are linked to it through generated columns or constraints to solve this issue. Note that other objects may be lost in the swap process. <em>The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!</em> Conflicting object: <strong>%1</strong> <em>(%2)</em>. Relationship: <strong>%1</strong> [id: %2]. Referrer object: <strong>%1</strong> <em>(%2)</em> [id: %3]. SQL validation not executed! No connection defined. Database model successfully validated. Running SQL commands on server... Processing object: %1 Apply fixes Swap ids The column <strong>%1</strong> on <strong>%2</strong> <em>(%3)</em> is referencing the geospatial data type <strong>%4</strong> but the <strong>postgis</strong> extension is not present in the model! <strong>HINT:</strong> Create the extension in the model or let it be created by applying the needed fixes. ModelWidget Source code 源代码 Show object source code 显示对象源代码 Properties 属性 Edit the object properties 修改对象属性 Protect 保护 Unprotect 取消保护 Delete 删除 Select all 选择全部 Selects all the graphical objects in the model 选择模型中的全部图形对象 Copy 复制 Paste 粘贴 Cut 剪切 Add a new object in the model 添加新对象到模型中 Rename 重命名 Quick rename the object 快速重命名此对象 Move to schema 移动到模式 Edit permissions 编辑权限 Change owner 变更所有者 Select children 选择子对象 Loading database model 正在载入数据库模型 Saving database model 正在保存数据库模型 Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model. 同时复制选中对象的依赖对象吗?这会最大限度减小已复制对象被粘贴到其他模型时,发生引用失效的机会。 Pasting objects... 正在粘贴对象... Not all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details! 处理过程中发生错误,部分对象没有被粘贴到模型中。详情请见错误堆栈! Do you really want to delete the selected object? 确定要删除选中的对象吗? Constraints 约束 Protects object(s) from modifications (no objects) One to One (1-1) One to Many (1-n) Many to Many (n-n) Inheritance <strong>ATTENTION:</strong> The database model is protected! Operations that could modify it are disabled! Source Alt+S Space Space Del Del Del. cascade Shift+Del Shift+Del Ctrl+A Convert Ctrl+C Ctrl+V Ctrl+X Deps && Referrers New 新建 Quick Quick action for the selected object F2 F2 Set tag Ctrl+E Open relationship Custom SQL Alt+Q Convert to sequence Convert to serial Break line Remove points Enable SQL Disable SQL 90° (vertical) 90° (horizontal) 90° + 90° (vertical) 90° + 90° (horizontal) Zoom: %1% Do you really want to convert the relationship into an intermediate table? Do you want to %1 the selected schema's children too? protect unprotect Validating object: `%1' (%2) Generating XML for: `%1' (%2) Pasting object: `%1' (%2) <strong>CAUTION:</strong> You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed? <strong>CAUTION:</strong> Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? <strong>CAUTION:</strong> Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed? The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details. Edit data Select tagged Select 选择 Duplicate Ctrl+D Extended attributes Show 显示 Hide Jump to table Schemas rectangles Fade in/out Fade in Fade out Relationships Swap ids Edit the objects creation order by swapping their ids All objects Schemas Tables Views Textboxes None ModelsDiffHelper Processing object `%1' (%2)... Skipping object `%1' (%2)... Processing diff infos... Processing `%1' info for object `%2' (%3)... No differences between the model and database. Preparing diff code... NewObjectOverlayWidget Form Form Tag Cast 类型转换 A Textbox 文本框 Tablespace 表空间 Schema 模式 Language 语言 Role 角色 Event Trigger Domain Conversion 编码转换 Aggregate 聚合 Collation Table Type 类型 Op. Family Sequence 序列 Extension Function 函数 View 视图 Permissions 权限 Op. Class Operator 操作符 Constraint 约束 Column Index 索引 Trigger 触发器 Rule 规则 Many-to-many One-to-many One-to-one Inheritance Copy 复制 G K H J D E F L O U I R S Q T P M M Y W 9 9 Z Z X C V B 1 1 2 2 3 3 5 5 4 4 0 0 Generic SQL Policy 8 8 NumberedTextEditor Upper case Lower case Ident right Ident left Load 打开 Load the object's source code from an external file Edit 编辑 Edit the source code in the preferred external editor Clear SQL file (*.sql);;All files (*.*) Load file The source editor `%1' is running on `pid: %2'. Could not start the source code editor application `%1'! Make to sure that the source editor path defined in the general settings points to a valid executable and the current user has permission to run the application. Error message returned: `%2' ObjectDepsRefsWidget Dependencies 依赖 Object 对象 Type 类型 Parent Object 父对象 Parent Type 父类型 References 引用 Object's dependencies & references ID Exclude indirect dependencies Include indirect references This object does not exists anymore. The dependencies and references listing are disabled. ObjectFinderWidget Form Form Pattern: Defines the search filter Filter Clears the search results Clear ... Hide this widget Regular Expression Exact Match Select All 选择全部 Clear All 取消全部 Case Sensitive ID Object 对象 Type 类型 Parent Object 父对象 Parent Type 父类型 Find Found <strong>%1</strong> object(s). No objects found. (Un)selects the graphical objects in the results grid Select 选择 Fades outs all the graphical objects in the results grid (or those not listed). The current fade in/out state of all objects is modified. Fade out Listed Not listed ObjectRenameWidget Form Form .... to: Rename 重命名 Cancel 取消 ObjectSelectorWidget Clear field 清空字段 Select Object 选择对象 Form Form Select %1 ObjectsTableWidget Form Form Add Item 添加项目 Ins Ins Remove Item 移除项目 Del Del Update Item 更新项目 Alt+R Alt+R Remove All 删除全部 Shift+Del Shift+Del Duplicate item Ctrl+D Edit Item 编辑项目 Space Space Move Up 上移 Ctrl+Up Ctrl+Up Move Down 下移 Ctrl+Down Ctrl+Down Move to start 移至开头 Ctrl+Home Ctrl+Home Move to end 移至末尾 Ctrl+End, Ctrl+S Ctrl+End, Ctrl+S Confirmation 确认 Do you really want to remove the selected item? 要移除选中的项目吗? Do you really want to remove all the items? OperationList (invalid object) OperationListWidget Executed Operations 执行的操作 Operations: 操作: Position: 位置: Delete operation history 删除操作记录 Undo 撤销 Redo 重做 Object: %1 对象:%1 Name: %1 名称:%1 removed 删除成功 modified 修改成功 moved 移动成功 Operation: %1 操作:%1 Operation history exclusion 不显示操作记录 Delete the executed operations history is an irreversible action, do you want to continue? 删除操作记录是不可逆操作,要继续吗? 1 1 0 0 created 创建成功 Hide this widget ... OperatorClassWidget Default Class: 默认类: Indexing: 索引类型: Elements 元素 Operator 操作符 Function 函数 Storage 存储 Function: 函数: Operator: 操作符: Support/Strategy: 支持/策略: Storage Type 存储类型 Object 对象 Type 类型 Support/Strategy 支持/策略 Element Type: Op. Family: Operator Family 操作符族 OperatorFamilyWidget Indexing: 正在建立索引: OperatorWidget Options: 选项: Arguments 参数 Right Argument Type 右参数类型 Left Argument Type 左参数类型 To create a unary operator it is necessary to specify as <strong><em>'any'</em></strong> one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator. 在创建单目操作符时必须指定它们参数中的<strong><em>任何</em></strong>一个。另外,作为操作符的函数必须有且只有一个参数,而且这个参数的类型必须与单目操作符参数的类型相同。 MERGES 融合连接 (MERGES) HASHES 哈希连接 (HASHES) Join: 连接: Advanced Restrict: Negator: Operator Func.: Commutator: ParameterWidget Default Value: 默认值: Mode: 模式: IN IN OUT OUT VARIADIC PermissionWidget Roles 角色 Privileges 权限 Cancel Operation 取消操作 Update Permission 更新权限 Add Permission 添加权限 ID: ID: Permissions 权限 GRANT OPTION CRANT OPTION Id Id Privilege 权限 Disable SQL code Cascade Edit permissions 编辑权限 &Grant Re&voke Code Preview 代码预览 -- No permissions defined for the specified object! /* Could not generate the SQL code preview for permissions! Name 名称 Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. PgModelerCLI Unrecognized option '%1'. Value not specified for option '%1'. Option '%1' does not accept values. Usage: pgmodeler-cli [OPTIONS] command line interface. DBMS export options: Input file must be different from output! Incomplete connection information! Starting model export... General options: PNG and SVG export options: Miscellaneous options: There are no connections configured. Invalid zoom specified! Invalid action specified to update mime option! Starting model fixing... Starting mime update... Model successfully fixed! Extracting objects' XML... Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted! Recreating objects... ** Object(s) that couldn't fixed: WARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2) Database model files (.dbm) are already associated to pgModeler! There is no file association related to pgModeler and .dbm files! Mime database operation: %1 Can't erase the file %1! Check if the current user has permissions to delete it and if the file exists. Running update-mime-database command... Connection aliased as '%1' was not found in the configuration file. PostgreSQL Database Modeler Project - pgmodeler.io Copyright 2006-2018 Raphael A. Silva <raphael@pgmodeler.io> This CLI tool provides several operations over models and databases without the need to perform them in pgModeler's graphical interface. All available options are described below. %1, %2 [FILE] Input model file (.dbm). This is mandatory for fix, export operations. %1, %2 [DBNAME] Input database name. This is mandatory for import operation. %1, %2 [FILE] Output file. This is mandatory for fixing model or exporting to file, png or svg. %1, %2 Try to fix the structure of the input model file in order to make it loadable again. %1, %2 [NUMBER] Model fix tries. When reaching the maximum count the invalid objects will be discarded. %1, %2 Export the input model to a sql script file. %1, %2 Export the input model to a png image. %1, %2 Export the input model to a svg file. %1, %2 Export the input model directly to a PostgreSQL server. %1, %2 Import a database to an output file. %1, %2 Compares a model and a database or two databases generating the SQL script to synch the latter in relation to the first. %1, %2 Force the PostgreSQL version of generated SQL code. %1, %2 Silent execution. Only critical messages and errors are shown during process. %1, %2 Show this help menu. Connection options: %1, %2 List available connections in file %3. %1, %2 [ALIAS] Connection configuration alias to be used. %1, %2 [HOST] PostgreSQL host in which a task will operate. %1, %2 [PORT] PostgreSQL host listening port. %1, %2 [USER] PostgreSQL username. %1, %2 [PASSWORD] PostgreSQL user password. %1, %2 [DBNAME] Connection's initial database. %1, %2 Draws the grid in the exported image. %1, %2 Draws the page delimiters in the exported image. %1, %2 Each page will be exported in a separated png image. (Only for PNG images) %1, %2 [FACTOR] Applies a zoom (in percent) before export to png image. Accepted zoom interval: %3-%4 (Only for PNG images) %1, %2 Ignores errors related to duplicated objects that eventually exist in the server. %1, %2 [CODES] Ignores additional errors by their codes. A comma-separated list of alphanumeric codes should be provided. %1, %2 Drop the database before execute a export process. %1, %2 Runs the DROP commands attached to SQL-enabled objects. %1, %2 Simulates an export process by executing all steps but undoing any modification in the end. %1, %2 Generates temporary names for database, roles and tablespaces when in simulation mode. Database import options: %1, %2 Ignore all errors and try to create as many as possible objects. %1, %2 Import system built-in objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Import extension objects. This option causes the model bloating due to the importing of unneeded objects. %1, %2 Run import in debug mode printing all queries executed in the server. Diff options: %1, %2 [DBNAME] The database used in the comparison. All the SQL code generated is applied to it. %1, %2 Save the generated diff code to output file. %1, %2 Apply the generated diff code on the database server. %1, %2 Don't preview the generated diff code when applying it to the server. %1, %2 Drop cluster level objects like roles and tablespaces. %1, %2 Revoke permissions already set on the database. New permissions configured in the input model are still applied. %1, %2 Drop missing objects. Generates DROP commands for objects that are present in the input model but not in the compared database. %1, %2 Force the drop of missing columns and constraints. Causes only columns and constraints to be dropped, other missing objects aren't removed. %1, %2 Rename the destination database when the names of the involved databases are different. %1, %2 Don't drop or truncate objects in cascade mode. %1, %2 Truncate tables prior to alter columns. Avoids errors related to type casting when the new type of a column isn't compatible to the old one. %1, %2 Don't reuse sequences on serial columns. Drop the old sequence assigned to a serial column and creates a new one. %1, %2 Don't force the recreation of objects. Avoids the usage of a DROP and CREATE commands to create a new version of the objects. %1, %2 Don't recreate the unmodifiable objects. These objects are the ones which can't be changed via ALTER command. %1, %2 [ACTION] Handles the file association to .dbm files. The ACTION can be [%3 | %4]. ** The diff process allows the usage of the following options related to import and export operations: * Export: * Import: ** When running the diff using two databases (%1 and %2) there's the need to specify two connections/aliases. If only one connection is set it will be used to import the input database as well to retrieve database used in the comparison. A second connection can be specified by appending a 1 on any connection configuration parameter listed above. Available connections (alias : connection string) No operation mode was specified! Export, fix model, import database, diff and update mime operations can't be used at the same time! Multiple export mode was specified! No input file was specified! No input database was specified! No output file was specified! No input file or database was specified! The input file and database can't be used at the same time! No database to be compared was specified! No diff action (save or apply) was specified! No output file for the diff code was specified! ** Error code `%1' found and ignored. Proceeding with export. ** Command: %1 Loading input file: %1 Fixed model file: %1 Export to PNG image: %1 Export to SVG file: %1 Export to SQL script file: %1 Export to DBMS: %1 Export successfully ended! Starting database import... Input database: %1 Saving the imported database to file... Import successfully ended! Starting diff process... Input model: %1 Compare to: %1 Loading input model... Importing the database `%1'... Comparing the generated models... No differences were detected. Saving diff to file `%1' ** WARNING: You are about to apply the generated diff code to the server. Data can be lost in the process! ** Proceed with the diff applying? (yes/no) > yes no Diff code not applied to the server. Applying diff to the database `%1'... Diff successfully ended! Mime database successfully updated! PgModelerPlugin Plugin Information Version: %1 Author: %1 PgModelerUiNS Do you want to apply the <strong>SQL %1 status</strong> to the object's references too? This will avoid problems when exporting or validating the model. disabling enabling PgSQLTypeWidget Data Type 数据类型 Type: 类型: Length 长度 Precision 精度 Dimension 维度 Interval: 区间: Format: 格式: Form Form L: L: P: P: [ ]: [ ]: Timezone: 时区: Spatial: 空间: Variation: 变异: Z Z M M SRID: NONE PluginsConfigWidget Form Form Plug-ins root directory: 插件根目录: Open in file manager 在文件管理器中打开 Loaded plug-ins 已加载的插件 Plugin 插件 Version 版本 Library 动态链接库 PolicyWidget Basics Command: Permissive Roles 角色 Expressions USING: CHECK: Name 名称 Leave the <em><strong>Roles</strong></em> grid empty in order to create a %1 applicable to <strong><em>PUBLIC</em></strong>. QObject new_database new_database %1 (line: %2) %1 (行:%2) Relationship %1_has_one_%2 %1_has_many_%2 many_%1_has_many_%2 %1_inherits_%2 %1_copies_%2 RelationshipConfigWidget Form Form Connection Mode Connect FK to PK columns Connect tables' center points FK Settings && Patterns Foreign key settings Deferral: 延迟: Deferrable: ON DELETE: ON DELETE: ON UPDATE: ON UPDATE: Name patterns Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Foreign Key (Source): Relationship type: Pattern for columns generated based upon target table's pk (n-n). Column (Target): One to one (1:1) One to many (1:n) Many to many (n:n) Generalization 泛化 Copy 复制 Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Column (Source): Pattern for foreign key generated based upon target table's pk (n-n). Foreign Key (Target): Pattern for unique key generated by the relationship. Unique Key Name: Pattern for primary key generated by identifier relationship. Primary Key Name: Primary Key Column: Default 默认 This mode renders the relationships in crow's foot notation which has a better semantics and readability. It also determines the optimal point where the relationship is connected on the tables' edges taking their position into account. Crow's foot notation This mode determines the optimal point where the relationship is connected on the tables' edges taking their position into account. It implies the usage of the classical ER notation. Connect tables' edges This mode is available only for <strong>one-to-one</strong>, <strong>one-to-many</strong> and <strong>fk relationships</strong> but provides a better semantics when linking tables by placing the lines on the exact point where the relationship occurs. It implies the usage of the classical ER notation. This mode is the classical one. It connects the relationship to tables through their central points. It implies the usage of the classical ER notation. RelationshipWidget General 常规 One to one relationship 一对一关系 One to many relationship 一对多关系 Many to many relationship 多对多关系 Generalization relationship (inheritance) 泛化关系 (继承) Identifier 标识符 Cardinality: 基数: Name of the table generated from many to many relationship 多对多关系生成表的名称 Deferrable: 可延迟: Deferral: 延迟: Attributes 属性 Constraints 约束 Primary key 主键 Attribute 属性 Type 类型 Constraint 约束 1-n 1-N n-n N-N dep dep Dependency / Copy relationship Relationship generated via foreign key fk Table 1: Table 2: [SRC] is required [DST] is required Copy Options INDEXES COMMENTS INCLUDING DEFAULTS CONSTRAINTS Use defaults ALL STORAGE Advanced Name 名称 This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables. is required Reference Table: Receiver Table: Name Patterns Use the values defined on settings dialogs for the fields below Use global settings for these fields Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Column (Source): Pattern for columns generated based upon target table's pk (n-n). Column (Target): Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Foreign Key (Source): Pattern for foreign key generated based upon target table's pk (n-n). Foreign Key (Target): Pattern for primary key generated by identifier relationship. Primary Key Name: Pattern for unique key generated by the relationship. Unique Key Name: Primay Key Column: Gen. Table Name: Rel. Type: Foreign key Settings ON DELETE: ON DELETE: ON UPDATE: ON UPDATE: &1-1 &gen The receiver's primary key will be composed by the generated foreign key columns. Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key. Single PK column Custom Color: E&XCLUDING Use the special primary key if you want to include a primary key containing generated columns to the receiver table. <strong>Important:</strong> if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key. Available tokens to define name patterns:<br/> <strong>%1</strong> = Reference (source) primary key column name. <em>(Ignored on constraint patterns)</em><br/> <strong>%2</strong> = Reference (source) table name.<br/> <strong>%3</strong> = Receiver (destination) table name.<br/> <strong>%4</strong> = Generated table name. <em>(Only for n:n relationships)</em> Default 默认 Referer View: Referer view references one or more columns of a table to construct it's own columns. Referenced table has its columns referenced by a view in order to construct the columns of this latter. Referer Table: Referer table references one or more columns of a table through foreign keys. This is the (n) side of relationship. Referenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship. Referenced Table: 引用表: Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship. Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship. In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table. ResultSetModel [binary data] RoleWidget Password: 密码: Connections: 连接: Attributes 属性 Superuser 超级用户 Members 成员 Role 角色 Validity 合法性 Members (Admin.) 成员(管理员) Member of 成员 Encrypted yyyy-MMM-dd hh:mm:ss Assigning <strong><em>-1</em></strong> to <strong><em>Connections</em></strong> creates a role without connection limit.<br/> Unchecking <strong><em>Validity</em></strong> creates an role that never expires. Inherit permissions Can create database Bypass RLS Can use replication Can login Can create role RuleWidget Event: 事件: Execution Type: 执行类型: Conditional Expr.: 条件表达式: SQL Command: SQL 命令: To create a rule that does not perform any action (<strong>DO NOTHING</strong>) simply do not specify commands in the SQL commands table. 创建一个不执行任何操作的规则(<STRONG>DO NOTHING</STRONG>)简单点说,就是 SQL 命令表中没有的命令。 SQL command SQL 命令 Commands SQLExecutionWidget Form Form Save SQL commands Search in SQL code Alt+F Run the specified SQL command Run SQL F6 F6 Clear sql input field and results Clear All 取消全部 Export results to a CSV file Snippe&ts E&xport Toggles the output pane &Output Alt+O Results ... Messages History SQL file (*.sql);;All files (*.*) [binary data] No results retrieved or changes done due to the error above. Messages (%1) Results (%1) Rows affected Rows retrieved Load SQL commands Save CSV file Comma-separated values file (*.csv);;All files (*.*) The SQL input field and the results grid will be cleared! Want to proceed? Copy selection Clear history Close the current SQL script SQL script currently handled (not saved) Handle external SQL script &Script Fi&nd Alt+T Alt+X Current working database Load 打开 Save 保存 Save as 另存为 [%1]: SQL command successfully executed in <em><strong>%2</strong></em>. <em>%3 <strong>%4</strong></em> Plain format CVS format This action will wipe out all the SQL commands history for all connections! Do you really want to proceed? Save history Reload history Find in history Hide find tool This action will wipe out all the SQL commands history for the current connection! Do you really want to proceed? SQLToolWidget Form Form Database explorer Disconnect from all databases ... Update the database list Toggle the object's attributes grid Attributes 属性 Alt+R Alt+R Toggle the display of source code pane Source code 源代码 SQL execution Warning <strong>ATTENTION:</strong> Disconnect from all databases will close any opened tab in this view! Do you really want to proceed? SceneInfoWidget Form Form Current position of the mouse in the canvas - Current zoom factor Currently selected object(s) Dimensions of the selected object(s) No selection N/A Sel. objects: %1 SchemaWidget Show rectangle Fill color: SequenceWidget Cyclic: 循环: Start: 起始值: Maximum: 最大值: Minimum: 最小值: Increment: 增量: Cache: 缓存: Owner Col.: Defualt values: User defined SnippetsConfigWidget Form Form Label: Applies to: ID: ID: Create new connection 建立新连接 Cancel edition 取消编辑 Edit selected connection 编辑选中的连接 Delete selected connection 删除选中的连接 Remove All 删除全部 Shift+Del Shift+Del Snippets: Parse the snippet in order to check if there are syntax errors. Parse Add 新建 Update 更新 Parsable or dynamic snippets are written in the <strong>schema micro language</strong> syntax. When using a parsable snippet the attributes surrounded in <strong>{}</strong> will be replaced by the selected object's matching attributes. Parsable When handling parsable snippets empty attributes will be replaced by a value in the format <strong>{attribute}</strong>. Note that this option can affect the semantics of the resulting snippet. Placeholders Filter: General purpose All snippets /* Error parsing the snippet '%1': %2 */ Duplicated snippet id <strong>%1</strong> detected. Please, specify a different one! Invalid ID pattern detected <strong>%1</strong>. This one must start with at leat one letter and be composed by letters, numbers and/or underscore! Empty label for snippet <strong>%1</strong>. Please, specify a value for it! Empty code for snippet <strong>%1</strong>. Please, specify a value for it! The dynamic snippet contains syntax error(s). Additional info: <br/><em>%1</em> Do you really want to remove all snippets? No syntax errors found in the snippet. General 常规 SourceCodeWidget Version: 版本: Source code visualization 查看源代码 Generating source code... 正在生成源代码...... -- SQL code unavailable for this type of object -- -- 无法生成此对象类型的 SQL 代码 -- PostgreSQL PostgreSQL iconecodigo iconecodigo SQL SQL XML XML Code display: Original Original + depedencies' SQL Original + children's SQL Save the SQL code to a file. Save SQL <strong>Original:</strong> displays only the original object's SQL code.<br/><br/> <strong>Dependencies:</strong> displays the original code including all dependencies needed to properly create the selected object.<br/><br/> <strong>Children:</strong> displays the original code including all object's children SQL code. This option is used only by schemas, tables and views. Save SQL code as... SQL code (*.sql);;All files (*.*) SQL 代码 (*.sql);;所有文件 (*.*) -- NOTE: the code below contains the SQL for the selected object -- as well for its dependencies and children (if applicable). -- -- This feature is only a convinience in order to permit you to test -- the whole object's SQL definition at once. -- -- When exporting or generating the SQL for the whole database model -- all objects will be placed at their original positions. -- SQL code purposely truncated at this point in demo version! <!-- XML code preview disabled in demonstration version --> SwapObjectsIdsWidget Change objects creation order Create: ID: ID: Before: Swap the values of the fields Swap values Change the objects creation order is an irreversible operation and cause the operations history to be automatically erased. Note that the creation order configured in this form is not definitive and may change after a model validation. Swap the object ids changing their creation order Swap ids Filter: ID Object 对象 Type 类型 Parent Object 父对象 Parent Type 父类型 Table new_table In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2' TableDataWidget Edit table data Add empty rows Ins Ins Add an empty column Remove all rows from the grid preserving columns Shift+Del Shift+Del Delete the selected rows Del Del Duplicate the selected rows Ctrl+D Delete the selected columns Remove all columns (and rows) from the grid Ctrl+Shift+Del Delete columns is an irreversible action! Do you really want to proceed? Remove all rows is an irreversible action! Do you really want to proceed? Remove all columns is an irreversible action! Do you really want to proceed? Unknown column Duplicated column Copy items on the grid Copy 复制 Add row Delete column Paste items on the grid Paste 粘贴 Ctrl+V Fills the grid using a CSV file <html><head/><body><p>Some invalid or duplicated columns were detected. In order to solve this issue double-click the header of the highlighted ones in order to define the correct name in which the data belongs to or delete the entire column. Note that these columns are completely ignored when generating the <span style=" font-weight:600;">INSERT</span> commands.</p></body></html> Add column Duplicate rows Change the values of all selected cells at once Bulk data edit Ctrl+E Delete all columns Delete rows <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> Delete all rows TableObjectView Relationship: %1 TableWidget Name 名称 Type 类型 Default Value 默认值 Refer. Table 引用表 Events 事件 Execution 执行 Event 事件 Indexing 索引 ON DELETE ON DELETE ON UPDATE ON UPDATE Firing 触发 Schema 模式 Parent Copy 复制 Options Tag: With OID Generate ALTER for columns/constraints Unlogged &Columns Co&nstraints Tri&ggers &Rules &Indexes &Tables Edit data Define initial data for the table Enable row level security Force RLS for owner &Policies PK Attribute(s) It is not possible to mark a column as primary key when the table already has a primary key which was created by a relationship! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. It is not possible to mark a column created by a relationship as primary key! This action should be done in the section <strong>Primary key</strong> of the relationship's editing form. Command Permissive USING expression CHECK expression Roles 角色 Yes No TablespaceWidget Directory: 字典: Form Form TagWidget Colors Body: Title: Schema name: Table name: Extended body: TaskProgressWidget Executing tasks 正在执行的任务 Waiting task to start... TextboxWidget Bold 粗体 Italic 斜体 Select text color 选择文本颜色 Underline 下划线 Font: 字体: Text pt Color: TriggerWidget Event: 事件: Deferrable: 可延迟: Columns Column: 列: Arguments 参数 Argument: 参数: Function: 函数: Column Type 类型 INSERT INSERT DELETE DELETE UPDATE UPDATE TRUNCATE TRUNCATE Constraint 约束 FOR EACH ROW Refer. Table: Condition: Options: 选项: Excution: TypeWidget Configuration: 配置: Base Type 基本类型 Enumeration 枚举 Enumerations 枚举 Enumeration: 枚举: Attributes 属性 Internal Length: 内部长度: Storage: 存储: Category: 类别: Delimiter: 分隔符: Alignment: 对齐: Default Value: 默认值: Functions 函数 Element Type 元素类型 Name 名称 Type 类型 char char smallint smallint integer integer double precision double precision INPUT: INPUT: OUTPUT: OUTPUT: RECV: RECV: SEND: SEND: TPMOD_IN: TPMOD_IN: TPMOD_OUT: TPMOD_OUT: ANALYZE: ANALYZE: The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table> 用于类型定义的函数要用 C 语言编写,并且符合下列的函数签名:<br/> <table> <tr> <td><strong>INPUT:</strong> <em>any function(cstring, oid, integer)</em></td> <td><strong>OUTPUT:</strong> <em>cstring function(any)</em></td> </tr> <tr> <td><strong>SEND:</strong> <em>byta function(any)</em></td> <td><strong>RECV:</strong> <em>any function(internal, oid, integer)</em></td> </tr> <tr> <td><strong>TPMOD_IN:</strong> <em>integer function(cstring[])</em></td> <td><strong>TPMOD_OUT:</strong> <em>cstring function(integer)</em></td> </tr> <tr> <td><strong>ANALYZE:</strong> <em>boolean function(internal)</em></td> <tr> </table> Range Options: 选项: By value Preferred Collatable Name: 名称: Collation: Subtype Diff Func.: Operator Class: 操作符类: Canonical Func.: Like Type Subtype Collation The functions to be assigned to a range type should have the following signatures:<br/><br/><strong>Canonical:</strong> <em>any function(any)</em> <br/><strong>Subtype Diff:</strong> <em>double precision function(subtype, subtype)</em> Co&mposite UpdateNotifierWidget Update Notifier Update found! Hide this widget ... Released in: mmm dd, yyyy New version: 0.0.0 0.0.0 Changelog Redirects to purchase page. Get binary package Redirects to GitHub source repository. Get source code Failed to check updates No updates found You are running the most recent pgModeler version! No update needed. The update notifier failed to check for new versions! A HTTP status code was returned: <strong>%1</strong> The update notifier failed to check for new versions! Please, verify your internet connectivity and try again! Connection error returned: <em>%1</em> - <strong>%2</strong>. ViewWidget References 引用 Column Expression 表达式 Used in: 被用在: Table: 表: Table Alias: 表别名: Column: 列: Column Alias: 列别名: Expression: 表达式: Expression Alias: 表达式别名: Code Preview 代码预览 Col./Expr. 列/表达式 Alias 别名 Alias Col. 列别名 Reference Type: View Definition Triggers 触发器 Rules 规则 Table Expression Name 名称 Refer. Table 引用表 Firing 触发 Events 事件 Execution 执行 Event 事件 /* Could not generate the SQL code. Make sure all attributes are correctly filled! Options Tag: Mode: 模式: Ordinary Recursi&ve &Materialized With no data The element will be used as part of the SELECT statement to retrieve columns or expressions that will compose the view's columns SELECT ... The element will be used as part of the WHERE clause in form of conditional expression WHERE ... The element is used in the FROM portion of the command in order to reference tables or construct JOIN statements FROM ... The element's expression is used exclusively as the view's definition The element will be appended to the very end of the view's definition. This is useful when using GROUP BY/HAVING statements End expression Indexes 索引 Flags: SF FW AW EX VD To reference all columns in a table (*) just do not fill the field <strong>Column</strong>, this is the same as write <em><strong>[schema].[table].*</strong></em> Indexing 索引 WelcomeWidget Form Form New model Open model Sample models Recent models Last session pgmodeler-0.9.2/libobjrenderer/000077500000000000000000000000001360462764600165065ustar00rootroot00000000000000pgmodeler-0.9.2/libobjrenderer/libobjrenderer.pro000066400000000000000000000035531360462764600222260ustar00rootroot00000000000000# libobjrenderer.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = lib TARGET = objrenderer windows: DESTDIR = $$PWD HEADERS += src/baseobjectview.h \ src/textboxview.h \ src/tableview.h \ src/graphicalview.h \ src/relationshipview.h \ src/tabletitleview.h \ src/tableobjectview.h \ src/basetableview.h \ src/objectsscene.h \ src/schemaview.h \ src/roundedrectitem.h \ src/styledtextboxview.h \ src/beziercurveitem.h \ src/textpolygonitem.h \ src/attributestoggleritem.h SOURCES += src/baseobjectview.cpp \ src/textboxview.cpp \ src/tableview.cpp \ src/graphicalview.cpp \ src/relationshipview.cpp \ src/tabletitleview.cpp \ src/tableobjectview.cpp \ src/basetableview.cpp \ src/objectsscene.cpp \ src/schemaview.cpp \ src/roundedrectitem.cpp \ src/styledtextboxview.cpp \ src/beziercurveitem.cpp \ src/textpolygonitem.cpp \ src/attributestoggleritem.cpp unix|windows: LIBS += -L$$OUT_PWD/../libpgmodeler/ -lpgmodeler \ -L$$OUT_PWD/../libparsers/ -lparsers \ -L$$OUT_PWD/../libutils/ -lutils INCLUDEPATH += $$PWD/../libpgmodeler/src \ $$PWD/../libparsers/src \ $$PWD/../libutils/src DEPENDPATH += $$PWD/../libpgmodeler \ $$PWD/../libparsers \ $$PWD/../libutils # Deployment settings target.path = $$PRIVATELIBDIR INSTALLS = target pgmodeler-0.9.2/libobjrenderer/src/000077500000000000000000000000001360462764600172755ustar00rootroot00000000000000pgmodeler-0.9.2/libobjrenderer/src/attributestoggleritem.cpp000066400000000000000000000336621360462764600244440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "attributestoggleritem.h" #include #include #include #include "baseobjectview.h" QPolygonF AttributesTogglerItem::btn_polygons[7]; AttributesTogglerItem::AttributesTogglerItem(QGraphicsItem *parent) : RoundedRectItem(parent) { createButtonPolygons(); this->setRoundedCorners(RoundedRectItem::BottomLeftCorner | RoundedRectItem::BottomRightCorner); sel_rect = new QGraphicsRectItem; for(unsigned arr_id = 0; arr_id < 7; arr_id++) { buttons[arr_id] = new QGraphicsPolygonItem; buttons[arr_id]->setPolygon(btn_polygons[arr_id]); btns_selected[arr_id] = false; } buttons[AttribsExpandBtn]->setToolTip(trUtf8("Expands the currently collapsed section of the object")); buttons[AttribsCollapseBtn]->setToolTip(trUtf8("Collapses the currently expanded section of the object")); buttons[NextAttribsPageBtn]->setToolTip(trUtf8("Displays the next attributes page")); buttons[PrevAttribsPageBtn]->setToolTip(trUtf8("Displays the previous attributes page")); buttons[NextExtAttribsPageBtn]->setToolTip(trUtf8("Displays the next extended attributes page")); buttons[PrevExtAttribsPageBtn]->setToolTip(trUtf8("Displays the previous extended attributes page")); buttons[PaginationTogglerBtn]->setToolTip(trUtf8("Toggles the attributes pagination on the object")); has_ext_attribs = false; pagination_enabled = false; collapse_mode = CollapseMode::NotCollapsed; btns_width = btns_height = 0; for(unsigned idx = 0; idx < 2; idx++) current_page[idx] = max_pages[idx] = 0; configureButtonsState(); } AttributesTogglerItem::~AttributesTogglerItem(void) { for(unsigned arr_id = 0; arr_id < 7; arr_id++) delete(buttons[arr_id]); delete(sel_rect); } void AttributesTogglerItem::setButtonsBrush(const QBrush &brush) { for(unsigned arr_id = 0; arr_id < 7; arr_id++) buttons[arr_id]->setBrush(brush); } void AttributesTogglerItem::setButtonsPen(const QPen &pen) { for(unsigned arr_id = 0; arr_id < 7; arr_id++) buttons[arr_id]->setPen(pen); } void AttributesTogglerItem::setRect(const QRectF &rect) { configureButtons(rect); } void AttributesTogglerItem::setCollapseMode(CollapseMode coll_mode) { //Avoiding setting up extended attributes collapsed when the toggler is configured to not having extended attribs if(!has_ext_attribs && coll_mode == CollapseMode::ExtAttribsCollapsed) collapse_mode = CollapseMode::NotCollapsed; else collapse_mode = coll_mode; configureButtonsState(); } void AttributesTogglerItem::setButtonSelected(const QPointF &pnt, bool clicked) { QRectF rect; double h_spacing = 4 * BaseObjectView::HorizSpacing; unsigned coll_mode = static_cast(collapse_mode), section_id = 0; this->setToolTip(QString()); clearButtonsSelection(); for(unsigned arr_id = 0; arr_id < 7; arr_id++) { rect.setSize(QSizeF(buttons[arr_id]->boundingRect().width() + h_spacing, this->boundingRect().height())); rect.moveTo(buttons[arr_id]->pos().x() - (h_spacing/2), 0); btns_selected[arr_id] = rect.contains(pnt) && buttons[arr_id]->isVisible(); if(btns_selected[arr_id]) { this->setToolTip(buttons[arr_id]->toolTip()); if(clicked) { if(arr_id == AttribsExpandBtn || arr_id == AttribsCollapseBtn) { if(arr_id == AttribsExpandBtn) coll_mode++; else if(arr_id == AttribsCollapseBtn) coll_mode--; if(!has_ext_attribs && static_cast(coll_mode) == CollapseMode::ExtAttribsCollapsed) coll_mode += (arr_id == AttribsExpandBtn ? 1 : -1); if(coll_mode > enum_cast(CollapseMode::NotCollapsed)) collapse_mode = (arr_id == AttribsExpandBtn ? CollapseMode::NotCollapsed : CollapseMode::AllAttribsCollapsed); else collapse_mode = static_cast(coll_mode); } else if(arr_id == PaginationTogglerBtn) { pagination_enabled = !pagination_enabled; } else { if(arr_id == PrevAttribsPageBtn || arr_id == NextAttribsPageBtn) section_id = BaseTable::AttribsSection; else section_id = BaseTable::ExtAttribsSection; if(max_pages[section_id] != 0) { if(arr_id == PrevAttribsPageBtn || arr_id == PrevExtAttribsPageBtn) current_page[section_id]--; else current_page[section_id]++; if(current_page[section_id] >= max_pages[section_id]) current_page[section_id] = (arr_id == PrevAttribsPageBtn || arr_id == PrevExtAttribsPageBtn ? 0 : max_pages[section_id] - 1); } } configureButtons(this->rect()); clearButtonsSelection(); configureButtonsState(); if(arr_id == PaginationTogglerBtn) emit s_paginationToggled(pagination_enabled); else if(arr_id == AttribsExpandBtn || arr_id == AttribsCollapseBtn) emit s_collapseModeChanged(collapse_mode); else emit s_currentPageChanged(section_id, current_page[section_id]); } else { //Configuring the selection rectangle if the arrows isn't clicked QRectF rect; QSizeF size = QSizeF(buttons[AttribsExpandBtn]->boundingRect().size().width() + (2 * BaseObjectView::HorizSpacing), btns_height + BaseObjectView::VertSpacing); double px = 0, py = 0, arr_x = buttons[arr_id]->pos().x(); rect.setSize(size); px = arr_x - (((arr_x + size.width()) - (arr_x + buttons[arr_id]->boundingRect().width()))/2); py = (this->boundingRect().size().height() - size.height())/2.5; sel_rect->setBrush(BaseObjectView::getFillStyle(Attributes::ObjSelection)); sel_rect->setPen(BaseObjectView::getBorderStyle(Attributes::ObjSelection)); sel_rect->setRect(rect); sel_rect->setPos(px, py); } break; } } } void AttributesTogglerItem::configureButtonsState(void) { buttons[AttribsExpandBtn]->setOpacity(collapse_mode == CollapseMode::ExtAttribsCollapsed || collapse_mode == CollapseMode::AllAttribsCollapsed? 1 : ButtonMinOpacity); buttons[AttribsCollapseBtn]->setOpacity(collapse_mode == CollapseMode::ExtAttribsCollapsed || collapse_mode == CollapseMode::NotCollapsed ? 1 : ButtonMinOpacity); buttons[PrevAttribsPageBtn]->setOpacity(max_pages[BaseTable::AttribsSection] != 0 && current_page[BaseTable::AttribsSection] > 0 ? 1 : ButtonMinOpacity); buttons[NextAttribsPageBtn]->setOpacity(max_pages[BaseTable::AttribsSection] != 0 && current_page[BaseTable::AttribsSection] < max_pages[BaseTable::AttribsSection] - 1 ? 1 : ButtonMinOpacity); buttons[PrevExtAttribsPageBtn]->setOpacity(has_ext_attribs && max_pages[BaseTable::ExtAttribsSection] != 0 && current_page[BaseTable::ExtAttribsSection] > 0 ? 1 : ButtonMinOpacity); buttons[NextExtAttribsPageBtn]->setOpacity(has_ext_attribs && max_pages[BaseTable::ExtAttribsSection] != 0 && current_page[BaseTable::ExtAttribsSection] < max_pages[BaseTable::ExtAttribsSection] - 1 ? 1 : ButtonMinOpacity); buttons[PrevAttribsPageBtn]->setVisible(pagination_enabled); buttons[NextAttribsPageBtn]->setVisible(pagination_enabled); buttons[PrevExtAttribsPageBtn]->setVisible(pagination_enabled); buttons[NextExtAttribsPageBtn]->setVisible(pagination_enabled); } void AttributesTogglerItem::setHasExtAttributes(bool value) { has_ext_attribs = value; configureButtonsState(); } void AttributesTogglerItem::setPaginationEnabled(bool value, bool hide_pag_toggler) { buttons[PaginationTogglerBtn]->setVisible(!hide_pag_toggler); pagination_enabled = value; configureButtons(this->boundingRect()); configureButtonsState(); } void AttributesTogglerItem::setPaginationValues(unsigned section_id, unsigned curr_page, unsigned max_page) { if(!pagination_enabled || section_id > BaseTable::ExtAttribsSection) return; if(curr_page > max_page) current_page[section_id] = max_pages[section_id] = max_page; else { current_page[section_id] = curr_page; max_pages[section_id] = max_page; } } void AttributesTogglerItem::clearButtonsSelection(void) { for(unsigned arr_id = 0; arr_id < 7; arr_id++) btns_selected[arr_id] = false; this->update(); } double AttributesTogglerItem::getButtonsWidth(void) { return(btns_width); } double AttributesTogglerItem::getButtonsHeight(void) { return(btns_height); } void AttributesTogglerItem::configureButtons(const QRectF &rect) { double arr_width = 0, px = 0, h_spacing = 6 * BaseObjectView::HorizSpacing, height = 4 * BaseObjectView::VertSpacing; QRectF new_rect = rect; btns_height = btn_polygons[PrevAttribsPageBtn].boundingRect().height(); height += btns_height; if(pagination_enabled) { arr_width = btn_polygons[PrevAttribsPageBtn].boundingRect().width() + btn_polygons[NextAttribsPageBtn].boundingRect().width() + btn_polygons[PrevExtAttribsPageBtn].boundingRect().width() + btn_polygons[NextExtAttribsPageBtn].boundingRect().width() + (4 * h_spacing); } arr_width += btn_polygons[AttribsCollapseBtn].boundingRect().width() + btn_polygons[AttribsExpandBtn].boundingRect().width() + (2 * h_spacing); if(buttons[PaginationTogglerBtn]->isVisible()) arr_width += btn_polygons[AttribsExpandBtn].boundingRect().width() + h_spacing; btns_width = arr_width; new_rect.setHeight(height); RoundedRectItem::setRect(new_rect); px = (new_rect.width() - arr_width + h_spacing)/2; if(buttons[PaginationTogglerBtn]->isVisible()) { buttons[PaginationTogglerBtn]->setPos(px, (new_rect.height() - buttons[PaginationTogglerBtn]->boundingRect().height())/2); px += buttons[PaginationTogglerBtn]->boundingRect().width() + h_spacing; if(pagination_enabled) { buttons[PrevExtAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[PrevExtAttribsPageBtn]->boundingRect().height())/2); px += buttons[PrevExtAttribsPageBtn]->boundingRect().width() + h_spacing; buttons[PrevAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[PrevAttribsPageBtn]->boundingRect().height())/2); px += buttons[PrevAttribsPageBtn]->boundingRect().width() + h_spacing; buttons[NextAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[NextAttribsPageBtn]->boundingRect().height())/2); px += buttons[PrevExtAttribsPageBtn]->boundingRect().width() + h_spacing; buttons[NextExtAttribsPageBtn]->setPos(px, (new_rect.height() - buttons[NextExtAttribsPageBtn]->boundingRect().height())/2); px += buttons[NextExtAttribsPageBtn]->boundingRect().width() + h_spacing; } } buttons[AttribsCollapseBtn]->setPos(px, (new_rect.height() - buttons[AttribsCollapseBtn]->boundingRect().height())/2); px += buttons[AttribsCollapseBtn]->boundingRect().width() + h_spacing * 0.80; buttons[AttribsExpandBtn]->setPos(px, (new_rect.height() - buttons[AttribsExpandBtn]->boundingRect().height())/2); } void AttributesTogglerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QGraphicsItem *parent = this->parentItem(); RoundedRectItem::paint(painter, option, widget); for(unsigned arr_id = 0; arr_id < 7; arr_id++) { if(!buttons[arr_id]->isVisible()) continue; painter->save(); painter->translate(buttons[arr_id]->pos()); painter->setOpacity(buttons[arr_id]->opacity() * (parent ? parent->opacity() : 1)); buttons[arr_id]->paint(painter, option, widget); painter->restore(); // Drawing the selection rectangle over the button if it isn't faded if(btns_selected[arr_id] && buttons[arr_id]->opacity() > ButtonMinOpacity) { painter->save(); painter->translate(sel_rect->pos()); sel_rect->paint(painter, option, widget); painter->restore(); } } } void AttributesTogglerItem::createButtonPolygons(void) { if(!btn_polygons[0].isEmpty()) return; QPolygonF *pol = nullptr; double fnt_factor = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow()))->logicalDotsPerInch() / 96.0, pixel_ratio = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow()))->devicePixelRatio(), factor = fnt_factor * pixel_ratio; pol = &btn_polygons[PrevAttribsPageBtn]; pol->append(QPointF(0, 5 * factor)); pol->append(QPointF(8 * factor, 0)); pol->append(QPointF(8 * factor, 10 * factor)); pol = &btn_polygons[NextAttribsPageBtn]; pol->append(QPointF(0, 0)); pol->append(QPointF(8 * factor, 5 * factor)); pol->append(QPointF(0, 10 * factor)); pol = &btn_polygons[PrevExtAttribsPageBtn]; pol->append(QPointF(0, 0)); pol->append(QPointF(2 * factor, 0)); pol->append(QPointF(2 * factor, 4 * factor)); pol->append(QPointF(8 * factor, 0)); pol->append(QPointF(8 * factor, 10 * factor)); pol->append(QPointF(2 * factor, 6 * factor)); pol->append(QPointF(2 * factor, 10 * factor)); pol->append(QPointF(0, 10 * factor)); pol = &btn_polygons[NextExtAttribsPageBtn]; pol->append(QPointF(0, 0)); pol->append(QPointF(6 * factor, 4 * factor)); pol->append(QPointF(6 * factor, 0 * factor)); pol->append(QPointF(8 * factor, 0)); pol->append(QPointF(8 * factor, 10 * factor)); pol->append(QPointF(6 * factor, 10 * factor)); pol->append(QPointF(6 * factor, 6 * factor)); pol->append(QPointF(0, 10 * factor)); pol = &btn_polygons[AttribsCollapseBtn]; pol->append(QPointF(5 * factor, 0)); pol->append(QPointF(0, 8 * factor)); pol->append(QPointF(10 * factor, 8 * factor)); pol = &btn_polygons[AttribsExpandBtn]; pol->append(QPointF(0, 0)); pol->append(QPointF(10 * factor, 0)); pol->append(QPointF(5 * factor, 8 * factor)); pol = &btn_polygons[PaginationTogglerBtn]; pol->append(QPointF(4 * factor, 0)); pol->append(QPointF(8 * factor, 4 * factor)); pol->append(QPointF(4 * factor, 8 * factor)); pol->append(QPointF(0, 4 * factor)); } pgmodeler-0.9.2/libobjrenderer/src/attributestoggleritem.h000066400000000000000000000136771360462764600241150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class AttributesTogglerItem \brief Implements a basic table's attributes toggler/pagination used by BaseTableView. */ #ifndef ATTRIBUTES_TOGGLER_ITEM_H #define ATTRIBUTES_TOGGLER_ITEM_H #include #include #include "roundedrectitem.h" #include "basetable.h" class AttributesTogglerItem: public QObject, public RoundedRectItem { private: Q_OBJECT static QPolygonF btn_polygons[7]; //! \brief Stores the selection rectangle of the item's internal elements QGraphicsRectItem *sel_rect; //! \brief Stores the current collasping mode related to the table associated to this toggler CollapseMode collapse_mode; //! \brief Stores the polygonal items denoting the control buttons of the toggler QGraphicsPolygonItem *buttons[7]; //! \brief Stores the selected status of the buttons bool btns_selected[7], /*! \brief Indicates if the table associated to this toggler has extended attributes * This attribute changes the way some buttons are rendered */ has_ext_attribs, //! \brief Indicates if the pagination is enabled for the table associated to this toggler pagination_enabled; //! \brief Stores the width of all visible buttons double btns_width, //! \brief Stores the height of all visible buttons btns_height; //! \brief Store the current page visible on the table associated to this toggler unsigned current_page[2], //! \brief Store the maximum pages allowed for the table associated to this toggler max_pages[2]; //! \brief The minimum opacity factor used to fade buttons static constexpr double ButtonMinOpacity = 0.40; //! \brief Constant used to reference the attributes expand button static constexpr unsigned AttribsExpandBtn=0, //! \brief Constant used to reference the attributes collapse button AttribsCollapseBtn=1, //! \brief Constant used to reference the next page button NextAttribsPageBtn=2, //! \brief Constant used to reference the previous page button PrevAttribsPageBtn=3, //! \brief Constant used to reference the next page button NextExtAttribsPageBtn=4, //! \brief Constant used to reference the previous page button PrevExtAttribsPageBtn=5, //! \brief Constant used to reference the pagination toggler button PaginationTogglerBtn=6; /*! \brief Configures the postion and dimensions of the buttons based on the provided bounding rect * If the provided rect is smaller than the total width/height of the buttons it will be assumed * as bouding rect the latter dimensions */ void configureButtons(const QRectF &rect); /*! \brief Configure the buttons visibility and opacity based upon the current values * of pagination and collapse mode */ void configureButtonsState(void); static void createButtonPolygons(void); public: AttributesTogglerItem(QGraphicsItem *parent = nullptr); ~AttributesTogglerItem(void); //! \brief Configures the buttons brush void setButtonsBrush(const QBrush &brush); //! \brief Configures the buttons pen void setButtonsPen(const QPen &pen); //! \brief Configures the bounding rect of the whole toggler item void setRect(const QRectF &rect); //! \brief Configures the current collapse mode of the toggler void setCollapseMode(CollapseMode coll_mode); /*! \brief Set a button selected (highlighted by the selection rectangle) if the provided * point is within a button's bouding rect. The parameter 'clicked' indicates if the button * is also clicked and not only hovered (the default behaviour) which causes addtional actions to be executed */ void setButtonSelected(const QPointF &pnt, bool clicked = false); //! \brief Defines if the toggles is controlling extended attributes pagination/collapsing void setHasExtAttributes(bool value); /*! \brief Toggles the pagination. If the hide_pag_toggler is set then the button that enables/disables * the pagination will be hidden permanently and the pagination automatically disabled */ void setPaginationEnabled(bool value, bool hide_pag_toggler = false); /*! \brief Defines the current values of the pagination (current page and maximum allowed pages) * Thes values are used to control the buttons fading when the page navigation reaches one of the limits (min/max) */ void setPaginationValues(unsigned page_id, unsigned curr_page, unsigned max_page); //! \brief Clears the selection status of the buttons void clearButtonsSelection(void); //! \brief Returns the width of the area occupied by all buttons (including spacing between them) double getButtonsWidth(void); //! \brief Returns the height of the area occupied by all buttons (including a vertical spacing) double getButtonsHeight(void); //! \brief Paints the toggler and its internal componets void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr); signals: //! \brief Signal emitted when the current collapse mode changes (the user clicks the collpase/expand buttons) void s_collapseModeChanged(CollapseMode); //! \brief Signal emitted when the current page changes (the user clicks the page navigation buttons) void s_currentPageChanged(unsigned, unsigned); //! \brief Signal emitted when the user clicks the pagination toggler buttons void s_paginationToggled(bool); }; #endif pgmodeler-0.9.2/libobjrenderer/src/baseobjectview.cpp000066400000000000000000000417301360462764600230020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baseobjectview.h" #include "textboxview.h" #include "roundedrectitem.h" #include "objectsscene.h" map BaseObjectView::font_config; map> BaseObjectView::color_config; unsigned BaseObjectView::global_sel_order=1; bool BaseObjectView::use_placeholder=true; bool BaseObjectView::compact_view=false; BaseObjectView::BaseObjectView(BaseObject *object) { sel_order=0; protected_icon=nullptr; obj_shadow=nullptr; obj_selection=nullptr; pos_info_item=nullptr; sql_disabled_item=nullptr; placeholder=nullptr; setSourceObject(object); } BaseObjectView::~BaseObjectView(void) { setSourceObject(nullptr); } void BaseObjectView::mousePressEvent(QGraphicsSceneMouseEvent *event) { if(event->button()==Qt::RightButton && !this->isSelected()) { //Faking an left-click in order to force the object selection using the right button. QGraphicsSceneMouseEvent *m_event=new QGraphicsSceneMouseEvent; m_event->setPos(event->pos()); m_event->setScenePos(event->scenePos()); m_event->setScreenPos(event->screenPos()); m_event->setButton(Qt::LeftButton); QGraphicsItemGroup::mousePressEvent(m_event); event->ignore(); } else if(event->button()==Qt::LeftButton) QGraphicsItemGroup::mousePressEvent(event); } void BaseObjectView::setSourceObject(BaseObject *object) { BaseGraphicObject *graph_obj=dynamic_cast(object); //Stores the reference to the source object as the data of graphical object this->setData(0, QVariant::fromValue(object)); if(!graph_obj) { if(obj_shadow) { this->removeFromGroup(obj_shadow); delete(obj_shadow); obj_shadow=nullptr; } if(protected_icon) { this->removeFromGroup(protected_icon); delete(protected_icon); protected_icon=nullptr; } if(pos_info_item) { this->removeFromGroup(pos_info_item); delete(pos_info_item); pos_info_item=nullptr; } if(sql_disabled_item) { this->removeFromGroup(sql_disabled_item); delete(sql_disabled_item); sql_disabled_item=nullptr; } if(placeholder) { delete(placeholder); placeholder=nullptr; } } else { QGraphicsPolygonItem *pol_item=nullptr; graph_obj->disconnect(); graph_obj->setReceiverObject(this); connect(graph_obj, SIGNAL(s_objectProtected(bool)), this, SLOT(toggleProtectionIcon(bool))); //By default the item can be selected and send geometry changes to the scene this->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); //The object is only movable if is not protected this->setFlag(QGraphicsItem::ItemIsMovable, !graph_obj->isProtected()); if(!protected_icon) { protected_icon=new QGraphicsItemGroup; protected_icon->setVisible(graph_obj->isProtected()); protected_icon->setZValue(3); pol_item=new QGraphicsPolygonItem; protected_icon->addToGroup(pol_item); pol_item=new QGraphicsPolygonItem; protected_icon->addToGroup(pol_item); this->addToGroup(protected_icon); } if(!pos_info_item) { pos_info_item=new TextPolygonItem; pos_info_item->setZValue(10); this->addToGroup(pos_info_item); } if(!sql_disabled_item && object->getObjectType()!=ObjectType::Textbox) { sql_disabled_item=new TextPolygonItem; sql_disabled_item->setZValue(100); this->addToGroup(sql_disabled_item); } } } BaseObject *BaseObjectView::getUnderlyingObject(void) { return(reinterpret_cast(this->data(0).value())); } void BaseObjectView::loadObjectsStyle(void) { QTextCharFormat font_fmt; QFont font; attribs_map attribs; map::iterator itr; QStringList list; QString elem, config_file=GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectsStyleConf + GlobalAttributes::ConfigurationExt; XmlParser xmlparser; try { xmlparser.restartParser(); xmlparser.setDTDFile(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectDTDDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectsStyleConf + GlobalAttributes::ObjectDTDExt, GlobalAttributes::ObjectsStyleConf); xmlparser.loadXMLFile(config_file); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { xmlparser.getElementAttributes(attribs); elem=xmlparser.getElementName(); if(elem==Attributes::Global) { font.setFamily(attribs[Attributes::Font]); font.setPointSizeF(attribs[Attributes::Size].toDouble()); font.setBold(attribs[Attributes::Bold]==Attributes::True); font.setItalic(attribs[Attributes::Italic]==Attributes::True); font.setUnderline(attribs[Attributes::Underline]==Attributes::True); font_fmt.setFont(font); font_config[Attributes::Global]=font_fmt; } else if(elem==Attributes::Font) { font_config[attribs[Attributes::Id]]=font_fmt; itr=font_config.find(attribs[Attributes::Id]); font=font_fmt.font(); font.setBold(attribs[Attributes::Bold]==Attributes::True); font.setItalic(attribs[Attributes::Italic]==Attributes::True); font.setUnderline(attribs[Attributes::Underline]==Attributes::True); (itr->second).setFont(font); (itr->second).setForeground(QColor(attribs[Attributes::Color])); } else if(elem==Attributes::Object) { list=attribs[Attributes::FillColor].split(','); vector colors; colors.push_back(!list.isEmpty() ? QColor(list[0]) : QColor(0,0,0)); colors.push_back(list.size()==2 ? QColor(list[1]) : colors[0]); colors.push_back(QColor(attribs[Attributes::BorderColor])); color_config[attribs[Attributes::Id]]=colors; } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__, __FILE__, __LINE__, &e, config_file); } } void BaseObjectView::setFontStyle(const QString &id, QTextCharFormat font_fmt) { QFont font; if(id!=Attributes::Global) { font=font_config[Attributes::Global].font(); font.setItalic(font_fmt.font().italic()); font.setBold(font_fmt.font().bold()); font.setUnderline(font_fmt.font().underline()); font_fmt.setFont(font); } else { map::iterator itr, itr_end; itr=font_config.begin(); itr_end=font_config.end(); font=font_fmt.font(); while(itr!=itr_end) { font.setItalic((itr->second).font().italic()); font.setBold((itr->second).font().bold()); font.setUnderline((itr->second).font().underline()); (itr->second).setFont(font); itr++; } } if(font_config.count(id)) font_config[id]=font_fmt; } void BaseObjectView::setElementColor(const QString &id, QColor color, unsigned color_id) { if(color_id < 3 && color_config.count(id)) color_config[id][color_id]=color; } QColor BaseObjectView::getElementColor(const QString &id, unsigned color_id) { if(color_config.count(id) > 0 && color_id < 3) return(color_config[id][color_id]); else return(QColor(0,0,0)); } void BaseObjectView::getFillStyle(const QString &id, QColor &color1, QColor &color2) { if(color_config.count(id) > 0) { color1=color_config[id][0]; color2=color_config[id][1]; } } QLinearGradient BaseObjectView::getFillStyle(const QString &id) { vector colors; QLinearGradient grad(QPointF(0,0),QPointF(0,1)); if(color_config.count(id) > 0) { colors=color_config[id]; if(!colors.empty()) { if(id==Attributes::ObjSelection || id==Attributes::Placeholder) { colors[0].setAlpha(ObjectAlphaChannel); colors[1].setAlpha(ObjectAlphaChannel); } grad.setCoordinateMode(QGradient::ObjectBoundingMode); grad.setColorAt(0, colors[0]); grad.setColorAt(1, colors[1]); } } return(grad); } QPen BaseObjectView::getBorderStyle(const QString &id) { QPen pen; vector colors; if(color_config.count(id) > 0) { colors=color_config[id]; if(!colors.empty()) { if(id==Attributes::ObjSelection) colors[2].setAlpha(ObjectAlphaChannel); pen.setWidthF(ObjectBorderWidth); pen.setColor(colors[2]); } } return(pen); } QTextCharFormat BaseObjectView::getFontStyle(const QString &id) { if(font_config.count(id)) return(font_config[id]); else return(QTextCharFormat()); } void BaseObjectView::setPlaceholderEnabled(bool value) { use_placeholder=value; } bool BaseObjectView::isPlaceholderEnabled(void) { return(use_placeholder); } void BaseObjectView::setCompactViewEnabled(bool value) { compact_view = value; } bool BaseObjectView::isCompactViewEnabled(void) { return(compact_view); } QVariant BaseObjectView::itemChange(GraphicsItemChange change, const QVariant &value) { if(change==ItemPositionHasChanged) { BaseGraphicObject *graph_obj=dynamic_cast(this->getUnderlyingObject()); if(graph_obj && !graph_obj->isProtected()) { if(ObjectsScene::isAlignObjectsToGrid()) this->setPos(ObjectsScene::alignPointToGrid(this->scenePos())); graph_obj->setPosition(this->scenePos()); this->configurePositionInfo(this->pos()); } } else if(change == ItemSelectedHasChanged && obj_selection) { this->setSelectionOrder(value.toBool()); pos_info_item->setVisible(value.toBool()); obj_selection->setVisible(value.toBool()); this->configurePositionInfo(this->pos()); emit s_objectSelected(dynamic_cast(this->getUnderlyingObject()), value.toBool()); } return(value); } void BaseObjectView::setSelectionOrder(bool selected) { if(this->sel_order==0 && selected) this->sel_order=++BaseObjectView::global_sel_order; else if(!selected) this->sel_order=0; } QRectF BaseObjectView::boundingRect(void) const { return(bounding_rect); } void BaseObjectView::toggleProtectionIcon(bool value) { BaseGraphicObject *obj_graf=dynamic_cast(this->getUnderlyingObject()); protected_icon->setVisible(value); this->setFlag(QGraphicsItem::ItemIsMovable, !value); if(obj_graf) obj_graf->setModified(true); } void BaseObjectView::configureObjectSelection(void) { RoundedRectItem *rect_item=dynamic_cast(obj_selection); if(rect_item) { rect_item->setRect(this->boundingRect()); rect_item->setPos(0, 0); rect_item->setBorderRadius(5); rect_item->setBrush(this->getFillStyle(Attributes::ObjSelection)); rect_item->setPen(this->getBorderStyle(Attributes::ObjSelection)); } } void BaseObjectView::configurePositionInfo(QPointF pos) { if(this->isSelected()) { QFont fnt=font_config[Attributes::PositionInfo].font(); pos_info_item->setBrush(BaseObjectView::getFillStyle(Attributes::PositionInfo)); pos_info_item->setPen(BaseObjectView::getBorderStyle(Attributes::PositionInfo)); fnt.setPointSizeF(fnt.pointSizeF() * 0.95); pos_info_item->setFont(fnt); pos_info_item->setTextBrush(font_config[Attributes::PositionInfo].foreground()); pos_info_item->setText(QString(" x:%1 y:%2 ").arg(round(pos.x())).arg(round(pos.y()))); pos_info_item->setPolygon(QPolygonF(pos_info_item->getTextBoundingRect())); pos_info_item->setPos(-0.5, -pos_info_item->boundingRect().height()/2); } } void BaseObjectView::configureSQLDisabledInfo(void) { if(sql_disabled_item) { double px=0, py=0; sql_disabled_item->setVisible(this->getUnderlyingObject()->isSQLDisabled()); if(this->getUnderlyingObject()->isSQLDisabled()) { QTextCharFormat char_fmt; char_fmt=BaseObjectView::getFontStyle(Attributes::PositionInfo); char_fmt.setFontPointSize(char_fmt.font().pointSizeF() * 0.80); sql_disabled_item->setFont(char_fmt.font()); sql_disabled_item->setText(trUtf8("SQL off")); sql_disabled_item->setTextBrush(char_fmt.foreground()); sql_disabled_item->setPolygon(QRectF(QPointF(0,0), sql_disabled_item->getTextBoundingRect().size() + QSizeF(1.5 * HorizSpacing, 1.5 * VertSpacing))); sql_disabled_item->setPen(BaseObjectView::getBorderStyle(Attributes::PositionInfo)); sql_disabled_item->setBrush(BaseObjectView::getFillStyle(Attributes::PositionInfo)); px=bounding_rect.width() - sql_disabled_item->boundingRect().width() + (1.5 * HorizSpacing); py=-(sql_disabled_item->boundingRect().height()/2); sql_disabled_item->setPos(px, py); sql_disabled_item->setTextPos(HorizSpacing * 0.75, VertSpacing * 0.75); } } } void BaseObjectView::configureProtectedIcon(void) { if(protected_icon) { QGraphicsPolygonItem *pol_item=nullptr; QPolygonF pol; double factor; //Calculates the factor used to resize the protection icon accordding the font size factor=font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize; pol.append(QPointF(2,5)); pol.append(QPointF(2,2)); pol.append(QPointF(3,1)); pol.append(QPointF(4,0)); pol.append(QPointF(7,0)); pol.append(QPointF(8,1)); pol.append(QPointF(9,2)); pol.append(QPointF(9,5)); pol.append(QPointF(7,5)); pol.append(QPointF(7,3)); pol.append(QPointF(6,2)); pol.append(QPointF(5,2)); pol.append(QPointF(4,3)); pol.append(QPointF(4,5)); if(factor!=1.0) TextPolygonItem::resizePolygon(pol, pol.boundingRect().width() * factor, pol.boundingRect().height() * factor); pol_item=dynamic_cast(protected_icon->childItems().at(0)); pol_item->setPolygon(pol); pol_item->setBrush(this->getFillStyle(Attributes::LockerArc)); pol_item->setPen(this->getBorderStyle(Attributes::LockerArc)); pol.clear(); pol.append(QPointF(1,5)); pol.append(QPointF(10,5)); pol.append(QPointF(11,6)); pol.append(QPointF(11,9)); pol.append(QPointF(10,10)); pol.append(QPointF(1,10)); pol.append(QPointF(0,9)); pol.append(QPointF(0,6)); if(factor!=1.0) TextPolygonItem::resizePolygon(pol, pol.boundingRect().width() * factor, pol.boundingRect().height() * factor); pol_item=dynamic_cast(protected_icon->childItems().at(1)); pol_item->setPolygon(pol); pol_item->setBrush(this->getFillStyle(Attributes::LockerBody)); pol_item->setPen(this->getBorderStyle(Attributes::LockerBody)); } } void BaseObjectView::configurePlaceholder(void) { if(!placeholder) { placeholder=new RoundedRectItem(); placeholder->setVisible(false); placeholder->setZValue(-1); placeholder->setFlag(QGraphicsItem::ItemIsMovable, false); placeholder->setFlag(QGraphicsItem::ItemIsSelectable, false); } } void BaseObjectView::__configureObject(void) { BaseGraphicObject *graph_obj=dynamic_cast(this->getUnderlyingObject()); if(graph_obj) { this->setPos(graph_obj->getPosition()); this->setToolTip(graph_obj->getName(true) + QString(" (") + graph_obj->getTypeName() + QString(") ") + QString("\nId: %1").arg(graph_obj->getObjectId())); this->configurePositionInfo(graph_obj->getPosition()); this->configureProtectedIcon(); } } unsigned BaseObjectView::getSelectionOrder(void) { return(sel_order); } QPointF BaseObjectView::getCenter(void) { return(QPointF(this->pos().x() + this->boundingRect().width()/2.0, this->pos().y() + this->boundingRect().height()/2.0)); } void BaseObjectView::togglePlaceholder(bool visible) { if(use_placeholder && placeholder && this->scene()) { if(!placeholder->scene()) this->scene()->addItem(placeholder); if(visible) { QPen pen=BaseObjectView::getBorderStyle(Attributes::Placeholder); pen.setStyle(Qt::DashLine); placeholder->setBrush(BaseObjectView::getFillStyle(Attributes::Placeholder)); placeholder->setPen(pen); placeholder->setRect(QRectF(QPointF(0,0),this->bounding_rect.size())); placeholder->setPos(this->mapToScene(this->bounding_rect.topLeft())); } placeholder->setVisible(visible); } } double BaseObjectView::getFontFactor(void) { return(font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize); } void BaseObjectView::setLayer(unsigned layer) { BaseGraphicObject *graph_obj = dynamic_cast(this->getUnderlyingObject()); if(graph_obj) graph_obj->setLayer(layer); } unsigned BaseObjectView::getLayer(void) { BaseGraphicObject *graph_obj = dynamic_cast(this->getUnderlyingObject()); if(graph_obj) return(graph_obj->getLayer()); return(0); } double BaseObjectView::getScreenDpiFactor(void) { QScreen *screen = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow())); double factor = screen->logicalDotsPerInch() / 96.0; double pixel_ratio = screen->devicePixelRatio(); if(factor < 1) return (1); return(factor * pixel_ratio); } pgmodeler-0.9.2/libobjrenderer/src/baseobjectview.h000066400000000000000000000173411360462764600224500ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class BaseObjectView \brief Implements the basic routines to graphically represent the objects: table, relationship, textbox, view. */ #ifndef BASE_OBJECT_VIEW_H #define BASE_OBJECT_VIEW_H #include #include "basegraphicobject.h" #include "baserelationship.h" #include "xmlparser.h" #include "roundedrectitem.h" #include "textpolygonitem.h" class BaseObjectView: public QObject, public QGraphicsItemGroup { private: Q_OBJECT protected: /*! \brief Indicates if the placeholder object must be used when moving objects. Place holder objects when enabled causes a significant performance gain mainly when moving tables linked to relationships because the relationships will be updated only when the table moviment ends and not during it */ static bool use_placeholder; /*! \brief Stores the global selection order of objects. This attributes is incremented each time an object is selected. */ static unsigned global_sel_order; /*! \brief Stores the current status for object's compact view display. * In compact view the alias of object's are shown instead of name. Also, data types and constraint types are hidden, * as well the table's extended area is collapsed by default */ static bool compact_view; /*! \brief Stores the selection order of the current object. This attribute is used to know when an item was selected before another in the scene because the implementation of the method QGraphicsScene :: selectedItem() the selected objects are returned without any sort, but for the database model objects is the ESSENTIAL to know the selection order mainly when creating relationships between tables. */ unsigned sel_order; //! \brief This item display the current object position on the scene TextPolygonItem *pos_info_item; //! \brief Stores the objects bounding rect QRectF bounding_rect; //! \brief Graphical object that represents the object selection QGraphicsItem *obj_selection; //! \brief Icon that represent the object protection QGraphicsItemGroup *protected_icon; //! \brief Graphical object that represents the current object shadow QGraphicsItem *obj_shadow; //! \brief Graphical object that represents the placeholder when the object is being moved RoundedRectItem *placeholder; //! \brief Graphical object of the sql disabled info QGraphicsRectItem *sql_disabled_box; //! \brief Graphical text for the sql disabled info QGraphicsSimpleTextItem *sql_disabled_txt; //! \brief This items is used to display the sql disabled status of the object TextPolygonItem *sql_disabled_item; //! \brief Stores the object font configuration static map font_config; //! \brief Stores the object colors configuration static map> color_config; //! \brief Configures the objects shadow polygon void configureObjectShadow(void) {} //! \brief Configures the object selection polygon void configureObjectSelection(void); //! \brief Configures the polygons used to show the current object position void configurePositionInfo(QPointF pos); //! \brief Configures the rectangle used to show the sql disabled status void configureSQLDisabledInfo(void); //! \brief Configures the icon that denotes the object's protection void configureProtectedIcon(void); void configurePlaceholder(void); void mousePressEvent(QGraphicsSceneMouseEvent *event); void setSelectionOrder(bool selected); //! \brief Defines in which layer the object is visible void setLayer(unsigned layer); public: static constexpr double VertSpacing=2.0, HorizSpacing=2.0, DefaultFontSize=9.0, ObjectBorderWidth=0.85; static constexpr int ObjectAlphaChannel=128; BaseObjectView(BaseObject *object=nullptr); virtual ~BaseObjectView(void); //! \brief Returns the object selection order unsigned getSelectionOrder(void); //! \brief Controls the changes during the object's selection and moving QVariant itemChange(GraphicsItemChange change, const QVariant &value); //! \brief Returns the object that is representend by the graphical object BaseObject *getUnderlyingObject(void); //! \brief Loads the font / color styels for the objects from a XML configuration file static void loadObjectsStyle(void); //! \brief Returns the objects bounding rect in local coordination QRectF boundingRect(void) const; //! \brief Returns the fill style in a form of gradient for the specified element id static QLinearGradient getFillStyle(const QString &id); /*! \brief Returns fill style storing the colors on the specified parameters color1 and color2 for the specified element id */ static void getFillStyle(const QString &id, QColor &color1, QColor &color2); //! \brief Returns the border style for the specified element id static QPen getBorderStyle(const QString &id); //! \brief Returns the font style for the specified element id static QTextCharFormat getFontStyle(const QString &id); static void setPlaceholderEnabled(bool value); static bool isPlaceholderEnabled(void); static void setCompactViewEnabled(bool value); static bool isCompactViewEnabled(void); //! \brief Sets the font style for the specified element id static void setFontStyle(const QString &id, QTextCharFormat font_fmt); //! \brief Sets the color for the specified element id (used to set color for objects and font) static void setElementColor(const QString &id, QColor color, unsigned color_id); //! \brief Returns the color for the specified element id (used to get color for objects and font) static QColor getElementColor(const QString &id, unsigned color_id); //! \brief Defines the object that the view represents void setSourceObject(BaseObject *object); //! \brief Pure virtual object (the derived classes must implement it) virtual void configureObject(void)=0; /*! \brief Returns the center point of the whole object. Note: this is not the same as calling boundingRect()->center(). Instead, this method calculates the center point based upon the current object's position */ virtual QPointF getCenter(void); //! \brief Toggles the wireframe display virtual void togglePlaceholder(bool visible); /*! \brief Returns the current font DPI factor of the screen. This factor is used to resize * objects according to the screen's resolution/font dpi */ static double getScreenDpiFactor(void); //! \brief Returns the current factor between the default font size and the current defined one static double getFontFactor(void); //! \brief Returns the layer in which the object is visible unsigned getLayer(void); protected slots: //! \brief Make the basic object operations void __configureObject(void); //! \brief Toggles the protection icon void toggleProtectionIcon(bool value); signals: //! \brief Signal emmited when the object is (un)selected void s_objectSelected(BaseGraphicObject *object, bool selected); //! \brief Signal emmited whenever the width or height of the table changes void s_objectDimensionChanged(void); friend class ObjectsScene; }; #endif pgmodeler-0.9.2/libobjrenderer/src/basetableview.cpp000066400000000000000000000450521360462764600226240ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "basetableview.h" bool BaseTableView::hide_ext_attribs = false; bool BaseTableView::hide_tags = false; unsigned BaseTableView::attribs_per_page[2] = { 10, 5 }; BaseTableView::BaseTableView(BaseTable *base_tab) : BaseObjectView(base_tab) { if(!base_tab) throw Exception(ErrorCode::AsgNotAllocattedObject, __PRETTY_FUNCTION__, __FILE__, __LINE__); pending_geom_update = false; body=new RoundedRectItem; body->setRoundedCorners(RoundedRectItem::BottomLeftCorner | RoundedRectItem::BottomRightCorner); title=new TableTitleView; title->setZValue(2); ext_attribs_body=new RoundedRectItem; ext_attribs_body->setRoundedCorners(RoundedRectItem::NoCorners); ext_attribs=new QGraphicsItemGroup; ext_attribs->setZValue(1); ext_attribs->setFlag(QGraphicsItem::ItemClipsChildrenToShape); columns=new QGraphicsItemGroup; columns->setZValue(1); columns->setFlag(QGraphicsItem::ItemClipsChildrenToShape); tag_item = new TextPolygonItem; tag_item->setZValue(3); obj_shadow=new RoundedRectItem; obj_shadow->setZValue(-1); obj_selection=new RoundedRectItem; obj_selection->setVisible(false); obj_selection->setZValue(4); attribs_toggler = new AttributesTogglerItem; attribs_toggler->setZValue(1); this->addToGroup(obj_selection); this->addToGroup(obj_shadow); this->addToGroup(columns); this->addToGroup(body); this->addToGroup(title); this->addToGroup(tag_item); this->addToGroup(ext_attribs); this->addToGroup(ext_attribs_body); this->addToGroup(attribs_toggler); this->setAcceptHoverEvents(true); sel_child_obj_view=nullptr; configurePlaceholder(); sel_enabler_timer.setInterval(500); connect(attribs_toggler, SIGNAL(s_collapseModeChanged(CollapseMode)), this, SLOT(configureCollapsedSections(CollapseMode))); connect(attribs_toggler, SIGNAL(s_paginationToggled(bool)), this, SLOT(togglePagination(bool))); connect(attribs_toggler, SIGNAL(s_currentPageChanged(unsigned,unsigned)), this, SLOT(configureCurrentPage(unsigned,unsigned))); connect(&sel_enabler_timer, &QTimer::timeout, [&](){ this->setFlag(QGraphicsItem::ItemIsSelectable, true); }); } BaseTableView::~BaseTableView(void) { this->removeFromGroup(body); this->removeFromGroup(title); this->removeFromGroup(attribs_toggler); this->removeFromGroup(ext_attribs_body); this->removeFromGroup(ext_attribs); this->removeFromGroup(columns); this->removeFromGroup(tag_item); delete(attribs_toggler); delete(ext_attribs_body); delete(ext_attribs); delete(body); delete(title); delete(columns); delete(tag_item); } void BaseTableView::setHideExtAttributes(bool value) { hide_ext_attribs=value; } void BaseTableView::setHideTags(bool value) { hide_tags=value; } bool BaseTableView::isExtAttributesHidden(void) { return(hide_ext_attribs); } bool BaseTableView::isTagsHidden(void) { return(hide_tags); } QVariant BaseTableView::itemChange(GraphicsItemChange change, const QVariant &value) { if(change==ItemSelectedHasChanged) { this->setToolTip(this->table_tooltip); configureObjectSelection(); attribs_toggler->clearButtonsSelection(); } else if(change == ItemVisibleHasChanged) { if(value.toBool() && pending_geom_update) { this->configureObject(); pending_geom_update = false; } } if(change==ItemPositionHasChanged) emit s_objectMoved(); BaseObjectView::itemChange(change, value); return(value); } void BaseTableView::mousePressEvent(QGraphicsSceneMouseEvent *event) { //Emit a signal containing the select child object if the user right-click the focused item if(!this->isSelected() && event->buttons()==Qt::RightButton && sel_child_obj_view) { // Avoiding clear selection when the focused child item is amongst the other selected children if(sel_child_obj_view->getUnderlyingObject() && !sel_child_objs.contains(sel_child_obj_view)) { // Forcing the selection clearing when we right click an child object that is not selected yet emit s_sceneClearRequested(); clearChildrenSelection(); /* Deactivate the table in order not to hide the child object selection. The table object is reativated when the context menu is hidden */ this->setEnabled(false); emit s_popupMenuRequested(dynamic_cast(sel_child_obj_view->getUnderlyingObject())); } } else { QPointF pnt = attribs_toggler->mapFromScene(event->scenePos()); //If the user clicks the extended attributes toggler if(!this->isSelected() && event->buttons()==Qt::LeftButton && event->modifiers() == Qt::NoModifier && attribs_toggler->isVisible() && attribs_toggler->boundingRect().contains(pnt)) attribs_toggler->setButtonSelected(pnt, true); /* We select children object only if the have a source object (column, constraint, trigger, etc). View references * items should not be selected here because they do not have a source object */ if(sel_child_obj_view && sel_child_obj_view->getUnderlyingObject() && event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { this->setFlag(QGraphicsItem::ItemIsSelectable, false); sel_child_obj_view->setFakeSelection(!sel_child_obj_view->hasFakeSelection()); if(!sel_child_obj_view->hasFakeSelection()) sel_child_objs.removeAll(sel_child_obj_view); else sel_child_objs.append(sel_child_obj_view); sel_child_obj_view = nullptr; event->ignore(); emit s_childrenSelectionChanged(); sel_enabler_timer.start(); } else if((this->flags() & QGraphicsItem::ItemIsSelectable) == QGraphicsItem::ItemIsSelectable) { // Forcing the scene selection clearing when we right click the table itself directly if(event->buttons() == Qt::RightButton && !this->isSelected()) { emit s_sceneClearRequested(); this->setSelected(true); } clearChildrenSelection(); BaseObjectView::mousePressEvent(event); } } } void BaseTableView::setAttributesPerPage(unsigned section_id, unsigned value) { if(section_id > BaseTable::ExtAttribsSection) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(value > 0) attribs_per_page[section_id] = value; } unsigned BaseTableView::getAttributesPerPage(unsigned section_id) { if(section_id > BaseTable::ExtAttribsSection) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(attribs_per_page[section_id]); } void BaseTableView::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { if(!this->isSelected() && obj_selection->isVisible()) obj_selection->setVisible(false); attribs_toggler->clearButtonsSelection(); sel_child_obj_view=nullptr; } void BaseTableView::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { /* Case the table itself is not selected shows the child selector at mouse position */ if(!this->isSelected()) { QList items; double cols_height, item_idx, ext_height=0; QRectF rect, rect1; QPointF pnt = attribs_toggler->mapFromScene(event->scenePos()); items.append(columns->childItems()); if(!hide_ext_attribs && dynamic_cast(this->getUnderlyingObject())->getCollapseMode() == CollapseMode::NotCollapsed) { items.append(ext_attribs->childItems()); ext_height=ext_attribs->boundingRect().height(); } //Calculates the default item height cols_height=(columns->boundingRect().height() + ext_height + (2*VertSpacing)) / static_cast(items.size()); //Calculates the item index based upon the mouse position rect=this->mapRectToItem(title, title->boundingRect()); item_idx=(event->pos().y() - rect.bottom()) / cols_height; if(attribs_toggler->isVisible() && attribs_toggler->boundingRect().contains(pnt)) { attribs_toggler->setButtonSelected(pnt); } //If the index is invalid clears the selection else if(item_idx < 0 || item_idx >= items.size()) { this->hoverLeaveEvent(event); this->setToolTip(this->table_tooltip); } else if(!items.isEmpty()) { TableObjectView *item=dynamic_cast(items[static_cast(item_idx)]); //Configures the selection with the item's dimension if(obj_selection->boundingRect().height() != item->boundingRect().height()) { dynamic_cast(obj_selection)->setBorderRadius(2); dynamic_cast(obj_selection)->setRect(QRectF(0, 0, title->boundingRect().width() - (2.5 * HorizSpacing), item->boundingRect().height() - VertSpacing)); } //Sets the selection position as same as item's position rect1=this->mapRectToItem(item, item->boundingRect()); obj_selection->setVisible(true); obj_selection->setPos(QPointF(title->pos().x() + HorizSpacing, -rect1.top() + VertSpacing/2)); //Stores the selected child object sel_child_obj_view = item; this->setToolTip(item->toolTip()); } } } void BaseTableView::addConnectedRelationship(BaseRelationship *base_rel) { BaseTable *tab = dynamic_cast(getUnderlyingObject()); if(!base_rel || (base_rel && base_rel->getTable(BaseRelationship::SrcTable) != tab && base_rel->getTable(BaseRelationship::DstTable) != tab)) return; connected_rels.push_back(base_rel); } void BaseTableView::removeConnectedRelationship(BaseRelationship *base_rel) { connected_rels.erase(std::find(connected_rels.begin(), connected_rels.end(), base_rel)); } int BaseTableView::getConnectedRelationshipIndex(BaseRelationship *base_rel, bool only_self_rels) { vector::iterator itr; vector self_rels, *vet_rels = nullptr; if(!only_self_rels) vet_rels = &connected_rels; else { for(auto &rel : connected_rels) { if(rel->isSelfRelationship()) self_rels.push_back(rel); } vet_rels = &self_rels; } itr = std::find(vet_rels->begin(), vet_rels->end(), base_rel); if(itr != vet_rels->end()) return(itr - vet_rels->begin()); return(-1); } unsigned BaseTableView::getConnectedRelsCount(BaseTable *src_tab, BaseTable *dst_tab) { unsigned count = 0; for(auto &rel : connected_rels) { if((rel->getTable(BaseRelationship::SrcTable) == src_tab && rel->getTable(BaseRelationship::DstTable) == dst_tab) || (rel->getTable(BaseRelationship::SrcTable) == dst_tab && rel->getTable(BaseRelationship::DstTable) == src_tab)) count++; } return(count); } void BaseTableView::configureTag(void) { BaseTable *tab=dynamic_cast(this->getUnderlyingObject()); Tag *tag=tab->getTag(); tag_item->setVisible(tag!=nullptr && !hide_tags); if(!hide_tags && tag) { QPolygonF pol; QPointF p1, p2; double bottom; QFont fnt=BaseObjectView::getFontStyle(Attributes::Tag).font(); fnt.setPointSizeF(fnt.pointSizeF() * 0.80); tag_item->setFont(fnt); tag_item->setText(tag->getName()); tag_item->setBrush(BaseObjectView::getFontStyle(Attributes::Tag).foreground()); p1=tag_item->getTextBoundingRect().topLeft(); p2=tag_item->getTextBoundingRect().bottomRight(); bottom=this->boundingRect().bottom(); pol.append(QPointF(p1.x()- HorizSpacing, p1.y() - VertSpacing)); pol.append(QPointF(p2.x(), p1.y() - VertSpacing)); pol.append(QPointF(p2.x() + HorizSpacing + 5, p2.y()/2)); pol.append(QPointF(p2.x(), p2.y() + VertSpacing)); pol.append(QPointF(p1.x(), p2.y() + VertSpacing)); pol.append(QPointF(p1.x()-HorizSpacing, p2.y() + VertSpacing)); tag_item->setPolygon(pol); tag_item->setPen(BaseObjectView::getBorderStyle(Attributes::Tag)); tag_item->setBrush(BaseObjectView::getFillStyle(Attributes::Tag)); tag_item->setPos(-5, bottom - 1.5); tag_item->setTextPos(HorizSpacing/2, 0); } } void BaseTableView::__configureObject(double width) { BaseTable *tab = dynamic_cast(getUnderlyingObject()); double height = 0, factor = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow()))->logicalDotsPerInch() / 96.0, pixel_ratio = qApp->screens().at(qApp->desktop()->screenNumber(qApp->activeWindow()))->devicePixelRatio(); QPen pen = body->pen(); attribs_toggler->setBrush(body->brush()); attribs_toggler->setPen(body->pen()); QLinearGradient grad(QPointF(0,0),QPointF(0,1)); grad.setCoordinateMode(QGradient::ObjectBoundingMode); grad.setColorAt(0, body->pen().color().lighter(200)); grad.setColorAt(1, body->pen().color().lighter()); pen.setStyle(Qt::SolidLine); attribs_toggler->setButtonsBrush(grad); attribs_toggler->setButtonsPen(body->pen()); attribs_toggler->setRect(QRectF(0, 0, width, 12 * factor * pixel_ratio)); attribs_toggler->setCollapseMode(tab->getCollapseMode()); //Set the protected icon position to the top-right on the title protected_icon->setPos(title->pos().x() + (2 * HorizSpacing), title->boundingRect().height() * 0.25); this->bounding_rect = title->boundingRect(); body->setRoundedCorners(RoundedRectItem::NoCorners); height = title->boundingRect().height() + attribs_toggler->boundingRect().height() - VertSpacing; height += (body->isVisible() ? body->boundingRect().height() : 1); height += (ext_attribs_body->isVisible() ? ext_attribs_body->boundingRect().height() - VertSpacing + 1 : 0); this->bounding_rect.setHeight(height); attribs_toggler->setPos(title->pos().x(), height - attribs_toggler->boundingRect().height()); this->table_tooltip=this->getUnderlyingObject()->getName(true) + QString(" (") + this->getUnderlyingObject()->getTypeName() + QString(") \n") + QString("Id: %1\n").arg(this->getUnderlyingObject()->getObjectId()) + trUtf8("Connected rels: %1").arg(this->getConnectRelsCount()); this->setToolTip(this->table_tooltip); configureObjectSelection(); configureObjectShadow(); } double BaseTableView::calculateWidth(void) { /* Calculating the maximum width between the title, columns, extended attributes and the attribs toggler. * This width is used to set the uniform width of table */ vector widths = { columns->isVisible() ? columns->boundingRect().width() : 0, ext_attribs->isVisible() ? ext_attribs->boundingRect().width() : 0, attribs_toggler->isVisible() ? attribs_toggler->getButtonsWidth() : 0, title->boundingRect().width() }; std::sort(widths.begin(), widths.end()); return (widths.back() + (2 * HorizSpacing)); } int BaseTableView::getConnectRelsCount(void) { return(connected_rels.size()); } void BaseTableView::requestRelationshipsUpdate(void) { emit s_relUpdateRequest(); } void BaseTableView::togglePlaceholder(bool value) { BaseObjectView::togglePlaceholder(!connected_rels.empty() && value); } void BaseTableView::configureObjectShadow(void) { RoundedRectItem *rect_item=dynamic_cast(obj_shadow); rect_item->setPen(Qt::NoPen); rect_item->setBrush(QColor(50,50,50,60)); rect_item->setRect(this->boundingRect()); rect_item->setPos(3.5, 4.5); } QList BaseTableView::getSelectedChidren(void) { return(sel_child_objs); } void BaseTableView::clearChildrenSelection(void) { if(sel_child_objs.isEmpty()) return; for(auto &tab_obj : sel_child_objs) tab_obj->setFakeSelection(false); sel_child_objs.clear(); emit s_childrenSelectionChanged(); } void BaseTableView::startGeometryUpdate(void) { //We need to force the object to be not selectable so further calls to mousePressEvent doesn't select the object this->setFlag(QGraphicsItem::ItemIsSelectable, false); } void BaseTableView::finishGeometryUpdate(void) { //Updating the object's geometry to reflect the geometry change this->configureObject(); obj_selection->setVisible(false); // Using a single shot time to restore the selectable flag QTimer::singleShot(300, [&]{ this->setFlag(QGraphicsItem::ItemIsSelectable, true); }); //Updating the schema box that holds the object (if visible) dynamic_cast(this->getUnderlyingObject()->getSchema())->setModified(true); } bool BaseTableView::configurePaginationParams(unsigned section_id, unsigned total_attrs, unsigned &start_attr, unsigned &end_attr) { if(section_id > BaseTable::ExtAttribsSection) return false; BaseTable *table = dynamic_cast(getUnderlyingObject()); unsigned attr_per_page = attribs_per_page[section_id]; start_attr = end_attr = 0; attribs_toggler->setPaginationEnabled(table->isPaginationEnabled()); /* If the pagination is enabled for the table and the amount of objects is greater than the * number of objects per page we configure the pagination parameter */ if(table->isPaginationEnabled() && total_attrs > attr_per_page) { // Calculating the proportions of columns and extended attributes displayed per page unsigned max_pages = 0, curr_page = table->getCurrentPage(section_id); // Determining the maximum amount of pages max_pages = ceil(total_attrs / static_cast(attr_per_page)); // Validating the current page related to the maximum determined if(curr_page >= max_pages) curr_page = max_pages - 1; // Calculating the start and end columns/ext. attributes for the current page start_attr = curr_page * attr_per_page; end_attr = start_attr + attr_per_page; // Validating the determined start/end indexes avoiding the extrapolation of limits if(start_attr > total_attrs) start_attr = total_attrs; if(end_attr > total_attrs) end_attr = total_attrs; // Configure the attributes toggler item withe the calculated pagination parameters attribs_toggler->setPaginationValues(section_id, curr_page, max_pages); return(true); } else { attribs_toggler->setPaginationValues(section_id, 0, 0); return(false); } } void BaseTableView::configureCollapsedSections(CollapseMode coll_mode) { startGeometryUpdate(); dynamic_cast(this->getUnderlyingObject())->setCollapseMode(coll_mode); finishGeometryUpdate(); emit s_collapseModeChanged(); } void BaseTableView::togglePagination(bool enabled) { BaseTable *tab = dynamic_cast(this->getUnderlyingObject()); startGeometryUpdate(); tab->setPaginationEnabled(enabled); tab->resetCurrentPages(); finishGeometryUpdate(); emit s_paginationToggled(); } void BaseTableView::configureCurrentPage(unsigned section_id, unsigned page) { startGeometryUpdate(); dynamic_cast(this->getUnderlyingObject())->setCurrentPage(section_id, page); finishGeometryUpdate(); emit s_currentPageChanged(); } pgmodeler-0.9.2/libobjrenderer/src/basetableview.h000066400000000000000000000207501360462764600222670ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class BaseTableView \brief Base class shared by the classes TableView and GraphicalView */ #ifndef BASE_TABLE_VIEW_H #define BASE_TABLE_VIEW_H #include "baseobjectview.h" #include "basetable.h" #include "tabletitleview.h" #include "tableobjectview.h" #include "roundedrectitem.h" #include "baserelationship.h" #include "textpolygonitem.h" #include "attributestoggleritem.h" class BaseTableView: public BaseObjectView { private: Q_OBJECT /*! \brief This timer is used to control the selection enabling of the object * in mouse presse event in order to avoid select it instead of a child. * See mousePressEvent() for details */ QTimer sel_enabler_timer; /*! \brief Stores the references to the relationships connected to this table. */ vector connected_rels; protected: //! \brief Stores the selected child objects in order to retrieve them in ObjectScene/ModelWidget QList sel_child_objs; /*! \brief This attributes indicates that the object's geometry update is pending demanding a * call to configureObject(). This attribute is set to true only when the objects is invisible * the the configureObject is called. Once the object gets visible again this attribute is set * to false and the geometry updated immediately (see BaseTableView::itemChange()) */ bool pending_geom_update; //! \brief Item groups that stores columns and extended attributes, respectively QGraphicsItemGroup *columns, *ext_attribs; //! brief Indicates if the extended attributes body should be hidden static bool hide_ext_attribs, //! brief Indicates if the tag object should be hidden hide_tags; //! brief Controls the maximum amount of attributes visible per page (columns/references + extended attributes) static unsigned attribs_per_page[2]; //! \brief Polygonal object that defines the table body RoundedRectItem *body, //! \brief Extended table attributes (indexes, rules, triggers) section body *ext_attribs_body; AttributesTogglerItem *attribs_toggler; TextPolygonItem *tag_item; //! \brief Stores the reference to the child object currently selected on table TableObjectView *sel_child_obj_view; //! \brief Table title TableTitleView *title; //! \brief Stores the original table's tool tip QString table_tooltip; QVariant itemChange(GraphicsItemChange change, const QVariant &value); void addConnectedRelationship(BaseRelationship *base_rel); void removeConnectedRelationship(BaseRelationship *base_rel); /*! \brief Returns the index of the relationship in the list of the connected relationships * If 'only_self_rels' is true then only self relationship are searched */ int getConnectedRelationshipIndex(BaseRelationship *base_rel, bool only_self_rels = false); //! \brief Configures the tag object when the source object has one. void configureTag(void); /*! \brief Configures basic attributes of the table. A width need to be provided so the extended attributes section can follow the same width as the body and title */ void __configureObject(double width); //! \brief Determines the table width based upon its subsection (title, body and extended attribs) double calculateWidth(void); /*! \brief This as an auxiliary method called before the object changes its dimensions and it causes * the object to not being selectable. This method is called whenever one of the signals are captured * from the attributes toggler: s_paginationToggled s_currentPageChanged s_collapseModeChanged */ void startGeometryUpdate(void); /*! \brief This auxiliary method is called after any geometry change finishes forcing the update of the object * and in some cases the schema box which contains it */ void finishGeometryUpdate(void); /*! \brief Determines the pagination paramenters for a section of the table. The input parameters are * the section (BaseTable::AttribsSection | ExtAttribsSection) and the total amount of attributes in the section. * The other paramenters start_attr and end_attr are reference parameters that will hold the indexes of items * to be displayed in the current page. See configureObject() on TableView and GraphicalView */ bool configurePaginationParams(unsigned page_id, unsigned total_attrs, unsigned &start_attr, unsigned &end_attr); public: static constexpr unsigned LeftConnPoint=0, RightConnPoint=1; BaseTableView(BaseTable *base_tab); virtual ~BaseTableView(void); void hoverLeaveEvent(QGraphicsSceneHoverEvent *); void hoverMoveEvent(QGraphicsSceneHoverEvent *event); void mousePressEvent(QGraphicsSceneMouseEvent *event); //! brief Defines the amount of attributes per page to be displayed static void setAttributesPerPage(unsigned section_id, unsigned value); //! brief Returns the current amount of attributes per page to be displayed static unsigned getAttributesPerPage(unsigned section_id); //! \brief Hides the table's extended attributes (rules, triggers, indexes). This applies to all table/view instances static void setHideExtAttributes(bool value); //! \brief Hides the table tags. This applies to all table instances static void setHideTags(bool value); //! \brief Returns the current visibility state of extended attributes static bool isExtAttributesHidden(void); //! \brief Returns the current visibility state of tags static bool isTagsHidden(void); //! \brief Returns the current count of connected relationships int getConnectRelsCount(void); //! \brief This method just emits the signal to indicate that the relationships attached must be updated void requestRelationshipsUpdate(void); //! \brief Toggles the placeholder object when there is at least one relationship connected to the object virtual void togglePlaceholder(bool value); unsigned getConnectedRelsCount(BaseTable *src_tab, BaseTable *dst_tab); //! \brief Configures the shadow for the table void configureObjectShadow(void); //! \brief Returns a list of selected children objects QList getSelectedChidren(void); //! \brief Clear the selection over all selected children void clearChildrenSelection(void); private slots: /*! \brief This slot reconfigures the table when the attributes toggler emits the signal s_collapseModeChanged * hiding or exposing the sections related to the current collapse mode */ void configureCollapsedSections(CollapseMode coll_mode); //! \brief This slot reconfigures the table when the attributes toggler emits the signal s_paginationToggled void togglePagination(bool enabled); /*! \brief This slot reconfigures the table when the attributes toggler emits the signal s_currentPageChanged * causing the the attributes of the current page to be displayed */ void configureCurrentPage(unsigned section_id, unsigned page); signals: //! \brief Signal emitted when a table is moved over the scene void s_objectMoved(void); //! \brief Signal emitted to indicate that the relationships attached to the table need to be updated void s_relUpdateRequest(void); //! \brief Signal emitted when the user right-click a focused table child object requesting a popup menu void s_popupMenuRequested(TableObject *); //! \brief Signal emitted when the user clicks a focused table child object and holding Control+Shift void s_childrenSelectionChanged(void); //! \brief Signal emitted when the user toggles the table's collapse mode void s_collapseModeChanged(void); //! \brief Signal emitted when the user toggles the table's attributes pagination void s_paginationToggled(void); //! \brief Signal emitted when the user changes the current table's attributes page void s_currentPageChanged(void); //! \brief Signal emitted when the object need the scene to clear its selection void s_sceneClearRequested(void); friend class RelationshipView; }; #endif pgmodeler-0.9.2/libobjrenderer/src/beziercurveitem.cpp000066400000000000000000000053611360462764600232120ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "beziercurveitem.h" #include "baserelationship.h" BezierCurveItem::BezierCurveItem(QGraphicsItem *parent) : QGraphicsPathItem(parent) { invert_cpoints = simple_curve = straight_line = false; } void BezierCurveItem::setPath(const QPainterPath &path) { QPainterPathStroker ps; QGraphicsPathItem::setPath(path); stroke = ps.createStroke(path); } void BezierCurveItem::setLine(const QLineF &line, bool simple_curve, bool invert_cpoints) { QPainterPath path; this->straight_line = false; this->invert_cpoints = invert_cpoints; this->simple_curve = simple_curve; if(line.dx() == 0 || line.dy() == 0) { path = QPainterPath(line.p1()); path.lineTo(line.p2()); this->straight_line = true; } else { if(simple_curve) { QPointF cp1, start, end; start = line.p1(); end = line.p2(); if(!invert_cpoints) cp1 = QPointF(start.x(), end.y()); else cp1 = QPointF(end.x(), start.y()); path = QPainterPath(start); path.quadTo(cp1, end); } else { QRectF brect; if(!invert_cpoints) { brect.setTopLeft(line.p1()); brect.setBottomRight(line.p2()); path = QPainterPath(brect.topLeft()); path.cubicTo(QPointF(brect.center().x(), brect.top()), QPointF(brect.center().x(), brect.bottom()), brect.bottomRight()); } else { brect.setBottomLeft(line.p1()); brect.setTopRight(line.p2()); path = QPainterPath(brect.topRight()); path.cubicTo(QPointF(brect.right(), brect.center().y()), QPointF(brect.left(), brect.center().y()), brect.bottomLeft()); } } } this->setPath(path); } bool BezierCurveItem::isControlPointsInverted(void) { return(invert_cpoints); } bool BezierCurveItem::isSimpleCurve(void) { return(simple_curve); } bool BezierCurveItem::isStraightLine(void) { return(straight_line); } bool BezierCurveItem::contains(const QPointF &pnt) const { return(stroke.contains(pnt)); } bool BezierCurveItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode) const { return(stroke.intersects(path)); } pgmodeler-0.9.2/libobjrenderer/src/beziercurveitem.h000066400000000000000000000047651360462764600226660ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class BezierCurveItem \brief Represents a simple bezier curve item used by relationships to draw curved lines */ #ifndef BEZIER_CURVE_ITEM_H #define BEZIER_CURVE_ITEM_H #include class BezierCurveItem: public QGraphicsPathItem { private: /*! \brief Stores the stroke of the curve itself. * This object is used to do a better colision detection */ QPainterPath stroke; bool invert_cpoints; bool simple_curve; bool straight_line; protected: void setPath(const QPainterPath &path); public: BezierCurveItem(QGraphicsItem *parent = 0); /*! \brief Configures the curve based upon a straight line. * * The simple_curve param causes the curve to be drawn using the quadratic mode and one control point. * Non-simple curves are cubic ones where two control points are used. * See QPainterPath::quadTo and QPainterPath::cubicTo for details. * * The invert_cpoints param causes the control points of the curve to be inverted * making the curve to be drawn inverted. */ void setLine(const QLineF &line, bool simple_curve, bool invert_cpoints); //! \brief Returns if the curve has the control points inverted bool isControlPointsInverted(void); //! \brief Returns if the curve is a simple one (with only one control point) bool isSimpleCurve(void); //! \brief Returns if the curve object was created from a straight line (90 or 180 degrees) bool isStraightLine(void); //! \brief Returns if the specified point is contained by the curve (specifically, by the stroke) virtual bool contains(const QPointF &pnt) const; //! \brief Returns if the specified path collides with the curve (specifically, by the stroke) virtual bool collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode) const; }; #endif pgmodeler-0.9.2/libobjrenderer/src/graphicalview.cpp000066400000000000000000000247221360462764600226350ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "graphicalview.h" GraphicalView::GraphicalView(View *view) : BaseTableView(view) { connect(view, SIGNAL(s_objectModified(void)), this, SLOT(configureObject(void))); columns=new QGraphicsItemGroup; columns->setZValue(1); this->addToGroup(columns); configurePlaceholder(); this->configureObject(); } void GraphicalView::configureObject(void) { /* If the table isn't visible we abort the current configuration * and mark its geometry update as pending so in the next call to * setVisible(true) the geometry can be updated (see BaseObjectView::itemChange()) */ if(!this->isVisible()) { pending_geom_update = true; return; } View *view=dynamic_cast(this->getUnderlyingObject()); int i = 0, count = 0; unsigned start_col = 0, end_col = 0, start_ext = 0, end_ext = 0; QPen pen; TableObjectView *graph_ref=nullptr; QList subitems; vector tab_objs, ext_tab_objs; vector view_cols; QGraphicsItemGroup *groups[]={ columns, ext_attribs }; RoundedRectItem *bodies[]={ body, ext_attribs_body }; QString attribs[]={ Attributes::ViewBody, Attributes::ViewExtBody }, tag_attribs[]={ Attributes::TableBody, Attributes::TableExtBody }; double width, type_width=0, px=0; TableObjectView *col_item=nullptr; QList col_items; TableObject *tab_obj=nullptr; Tag *tag=view->getTag(); CollapseMode collapse_mode = view->getCollapseMode(); bool has_col_pag = false, has_ext_pag = false; // Clear the selected children objects vector since we'll (re)configure the whole view sel_child_objs.clear(); //Configures the view's title title->configureObject(view); for(auto &obj : view->getObjects()) ext_tab_objs.push_back(dynamic_cast(obj)); attribs_toggler->setHasExtAttributes(!hide_ext_attribs && !ext_tab_objs.empty()); view_cols = view->getColumns(); has_col_pag = configurePaginationParams(BaseTable::AttribsSection, view_cols.size(), start_col, end_col); has_ext_pag = configurePaginationParams(BaseTable::ExtAttribsSection, collapse_mode != CollapseMode::ExtAttribsCollapsed ? ext_tab_objs.size() : 0, start_ext, end_ext); //Moves the references group to the origin to be moved latter columns->moveBy(-columns->scenePos().x(), -columns->scenePos().y()); columns->setVisible(view->getCollapseMode() != CollapseMode::AllAttribsCollapsed && start_col < static_cast(view_cols.size())); body->setVisible(columns->isVisible()); if(!columns->isVisible()) { for(auto &item : columns->childItems()) { columns->removeFromGroup(item); delete(item); } } else { vector aux_view_cols; if(has_col_pag) aux_view_cols.assign(view_cols.begin() + start_col, view_cols.begin() + end_col); else aux_view_cols = view_cols; count = aux_view_cols.size(); subitems=columns->childItems(); for(i=0; i < count; i++) { //Reuses the subitem if it was allocated before if(!subitems.isEmpty() && i < subitems.size()) { graph_ref=dynamic_cast(subitems[i]); //Moves the reference to the origin to be moved latter graph_ref->moveBy(-graph_ref->scenePos().x(), -graph_ref->scenePos().y()); } else graph_ref=new TableObjectView; graph_ref->configureObject(aux_view_cols[i]); graph_ref->moveBy(HorizSpacing, (i * graph_ref->boundingRect().height()) + VertSpacing); /* Calculates the width of the name + type of the object. This is used to align all the constraint labels on table */ width=graph_ref->getChildObject(TableObjectView::ObjDescriptor)->boundingRect().width() + graph_ref->getChildObject(TableObjectView::NameLabel)->boundingRect().width() + (8 * HorizSpacing); if(px < width) px=width; //Gets the maximum width of the column type label to align all at same horizontal position if(type_width < graph_ref->getChildObject(TableObjectView::TypeLabel)->boundingRect().width()) type_width=graph_ref->getChildObject(TableObjectView::TypeLabel)->boundingRect().width() + (3 * HorizSpacing); col_items.push_back(graph_ref); } //Destroy the graphical references not used i=subitems.size()-1; while(i > count-1) { graph_ref=dynamic_cast(subitems[i]); columns->removeFromGroup(graph_ref); delete(graph_ref); i--; } //Set all items position while(!col_items.isEmpty()) { col_item=dynamic_cast(col_items.front()); columns->removeFromGroup(col_item); col_items.pop_front(); //Positioning the type label col_item->setChildObjectXPos(TableObjectView::TypeLabel, px); //Positioning the constraints label col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel, px + type_width); columns->addToGroup(col_item); } } if(!hide_ext_attribs && view->getCollapseMode() == CollapseMode::NotCollapsed) { if(view->isPaginationEnabled() && has_ext_pag) tab_objs.assign(ext_tab_objs.begin() + start_ext, ext_tab_objs.begin() + end_ext); else tab_objs.assign(ext_tab_objs.begin(), ext_tab_objs.end()); } ext_attribs->setVisible(!tab_objs.empty() && view->getCollapseMode() == CollapseMode::NotCollapsed); ext_attribs_body->setVisible(ext_attribs->isVisible()); if(tab_objs.empty()) { for(auto &item : ext_attribs->childItems()) { ext_attribs->removeFromGroup(item); delete(item); } } else { count=tab_objs.size(); //Gets the subitems of the current group subitems=ext_attribs->childItems(); ext_attribs->moveBy(-ext_attribs->scenePos().x(), -ext_attribs->scenePos().y()); for(i=0; i < count; i++) { tab_obj=tab_objs.at(i); //Reusing the subitem if it was allocated before if(!subitems.isEmpty() && i < subitems.size()) { col_item=dynamic_cast(subitems[i]); col_item->setSourceObject(tab_obj); col_item->configureObject(); col_item->moveBy(-col_item->scenePos().x(), -col_item->scenePos().y()); } else col_item=new TableObjectView(tab_obj); //Configures the item and set its position col_item->configureObject(); col_item->moveBy(HorizSpacing, (i * col_item->boundingRect().height()) + VertSpacing); /* Calculates the width of the name + type of the object. This is used to align all the constraint labels on table */ width=col_item->getChildObject(TableObjectView::ObjDescriptor)->boundingRect().width() + col_item->getChildObject(TableObjectView::NameLabel)->boundingRect().width() + (3 * HorizSpacing); if(px < width) px=width; //Gets the maximum width of the column type label to align all at same horizontal position if(type_width < col_item->getChildObject(TableObjectView::TypeLabel)->boundingRect().width()) type_width=col_item->getChildObject(TableObjectView::TypeLabel)->boundingRect().width() + (3 * HorizSpacing); col_items.push_back(col_item); } //Destroy the unused items i=subitems.size()-1; while(i > count-1) { col_item=dynamic_cast(subitems[i]); ext_attribs->removeFromGroup(col_item); delete(col_item); i--; } //Set all items position while(!col_items.isEmpty()) { col_item=dynamic_cast(col_items.front()); ext_attribs->removeFromGroup(col_item); col_items.pop_front(); //Positioning the type label col_item->setChildObjectXPos(TableObjectView::TypeLabel, px); //Positioning the constraints label col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel, px + type_width); ext_attribs->addToGroup(col_item); } } width = calculateWidth(); //Resizes the title using the new width title->resizeTitle(width, title->boundingRect().height()); //Resizes the columns/extended attributes using the new width for(int idx=0; idx < 2; idx++) { /* Configuring the brush and pen of the bodies even if they aren't visible * the attributes toggler at the bottom of the view uses the color of the attributes body * this will avoid the creation of a transparent toggler */ if(!tag) { bodies[idx]->setBrush(this->getFillStyle(attribs[idx])); pen=this->getBorderStyle(attribs[idx]); } else { bodies[idx]->setBrush(tag->getFillStyle(tag_attribs[idx])); pen.setColor(tag->getElementColor(tag_attribs[idx], Tag::BorderColor)); } pen.setStyle(Qt::DashLine); bodies[idx]->setPen(pen); // We avoid the construction of the rect related to the current body item if the related group isn't visible if(!groups[idx]->isVisible()) continue; bodies[idx]->setRect(QRectF(0,0, width, groups[idx]->boundingRect().height() + (2 * VertSpacing))); if(idx==0) bodies[idx]->setPos(title->pos().x(), title->boundingRect().height() - 1); else { if(bodies[0]->isVisible()) bodies[idx]->setPos(title->pos().x(), title->boundingRect().height() + bodies[0]->boundingRect().height() - 2); else bodies[idx]->setPos(title->pos().x(), title->boundingRect().height()-1); } groups[idx]->setPos(bodies[idx]->pos()); subitems=groups[idx]->childItems(); while(!subitems.isEmpty()) { col_item=dynamic_cast(subitems.front()); subitems.pop_front(); col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel, width - col_item->getChildObject(3)->boundingRect().width() - (2 * HorizSpacing)); } } this->bounding_rect.setTopLeft(title->boundingRect().topLeft()); this->bounding_rect.setWidth(title->boundingRect().width()); BaseTableView::__configureObject(width); if(!view->getAlias().isEmpty()) table_tooltip += QString("\nAlias: %1").arg(view->getAlias()); if(!view->getComment().isEmpty()) table_tooltip += QString("\n---\n%1").arg(view->getComment()); BaseObjectView::__configureObject(); BaseObjectView::configureObjectShadow(); BaseObjectView::configureObjectSelection(); configureTag(); configureSQLDisabledInfo(); requestRelationshipsUpdate(); } pgmodeler-0.9.2/libobjrenderer/src/graphicalview.h000066400000000000000000000021101360462764600222650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class GraphicalView \brief Implements the graphical representation for Views */ #ifndef GRAPHICAL_VIEW_H #define GRAPHICAL_VIEW_H #include "view.h" #include "basetableview.h" class GraphicalView: public BaseTableView { private: Q_OBJECT public: GraphicalView(View *view); private slots: void configureObject(void); }; #endif pgmodeler-0.9.2/libobjrenderer/src/objectsscene.cpp000066400000000000000000001157431360462764600224630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectsscene.h" bool ObjectsScene::align_objs_grid=false; bool ObjectsScene::show_grid=true; bool ObjectsScene::show_page_delim=true; unsigned ObjectsScene::grid_size=20; QPrinter::PageSize ObjectsScene::paper_size=QPrinter::A4; QPrinter::Orientation ObjectsScene::page_orientation=QPrinter::Landscape; QRectF ObjectsScene::page_margins=QRectF(2,2,2,2); QSizeF ObjectsScene::custom_paper_size=QSizeF(0,0); QBrush ObjectsScene::grid; bool ObjectsScene::corner_move=true; bool ObjectsScene::invert_rangesel_trigger=false; ObjectsScene::ObjectsScene(void) { layers.push_back(trUtf8("Default layer")); active_layers.push_back(layers.at(0)); moving_objs=move_scene=false; enable_range_sel=true; this->setBackgroundBrush(grid); sel_ini_pnt.setX(DNaN); sel_ini_pnt.setY(DNaN); selection_rect=new QGraphicsPolygonItem; selection_rect->setVisible(false); selection_rect->setZValue(100); rel_line=new QGraphicsLineItem; rel_line->setVisible(false); rel_line->setZValue(-1); rel_line->setPen(QColor(80,80,80)); this->addItem(selection_rect); this->addItem(rel_line); scene_move_dx=scene_move_dy=0; connect(&scene_move_timer, SIGNAL(timeout()), this, SLOT(moveObjectScene())); connect(&corner_hover_timer, SIGNAL(timeout()), this, SLOT(enableSceneMove())); connect(&object_move_timer, &QTimer::timeout, [&](){ //If the timer reaches its timeout we execute the procedures to finish the objects movement finishObjectsMove(itemsBoundingRect(true, true).center()); object_move_timer.stop(); }); scene_move_timer.setInterval(SceneMoveTimeout); corner_hover_timer.setInterval(SceneMoveTimeout * 10); object_move_timer.setInterval(SceneMoveTimeout * 10); } ObjectsScene::~ObjectsScene(void) { QGraphicsItemGroup *item=nullptr; QList items; vector obj_types={ ObjectType::Relationship, ObjectType::Textbox, ObjectType::View, ObjectType::Table, ObjectType::ForeignTable, ObjectType::Schema }; this->removeItem(selection_rect); this->removeItem(rel_line); delete(selection_rect); delete(rel_line); //Destroy the objects in the order defined on obj_types vector for(auto &type : obj_types) { items=this->items(); while(!items.isEmpty()) { /* Try to convert the item to QGraphicsItemGroup because all the objects used to represent database object are derived from this class */ item=dynamic_cast(items.front()); /* Case the object is converted to a item group and can be converted to database objects, indicates that the object can be removed from the scene */ if(item && !item->parentItem() && ((dynamic_cast(item) && type==ObjectType::Relationship) || (dynamic_cast(item) && type==ObjectType::Textbox) || (dynamic_cast(item) && type==ObjectType::Textbox) || (dynamic_cast(item) && type==ObjectType::View) || (dynamic_cast(item) && (type==ObjectType::Table || type==ObjectType::ForeignTable)) || (dynamic_cast(item) && type==ObjectType::Schema))) { this->removeItem(item); } items.pop_front(); } } //The graphical representation of db objects must be destroyed in a sorted way std::sort(removed_objs.begin(), removed_objs.end()); while(!removed_objs.empty()) { delete(removed_objs.back()); removed_objs.pop_back(); } } QString ObjectsScene::formatLayerName(const QString &name) { QString fmt_name; unsigned idx = 1; //Removing invalid chars for(auto &chr : name) { if(chr.isLetterOrNumber() || chr == ' ' || chr == '_') fmt_name.append(chr); else fmt_name.append('_'); } //Doing the desambiguation (if needed) while(layers.contains(fmt_name)) fmt_name = QString("%1 %2").arg(name).arg(QString::number(idx++)); return(fmt_name); } QString ObjectsScene::addLayer(const QString &name) { if(name.isEmpty()) return(QString()); QString fmt_name = formatLayerName(name); layers.push_back(fmt_name); emit s_layersChanged(); return(fmt_name); } QString ObjectsScene::renameLayer(unsigned idx, const QString &name) { if(name.isEmpty() || idx >= static_cast(layers.size())) return (QString()); if(name != layers[idx]) layers[idx] = formatLayerName(name); emit s_layersChanged(); return(layers[idx]); } void ObjectsScene::removeLayer(const QString &name) { int idx = layers.indexOf(name); if(idx > 0) { moveObjectsToLayer(idx, DefaultLayer); layers.removeAll(name); active_layers.removeAll(name); emit s_layersChanged(); } } void ObjectsScene::removeLayers(void) { BaseObjectView *obj_view = nullptr; QString def_layer = layers[DefaultLayer]; bool is_active = active_layers.contains(def_layer); layers.clear(); active_layers.clear(); layers.push_back(def_layer); if(is_active) active_layers.push_back(def_layer); for(auto &item : this->items()) { obj_view = dynamic_cast(item); if(obj_view && !obj_view->parentItem() && obj_view->getLayer() != DefaultLayer) { obj_view->setLayer(DefaultLayer); obj_view->setVisible(is_active); } } emit s_layersChanged(); updateActiveLayers(); } void ObjectsScene::setActiveLayers(QStringList act_layers) { QList layers_idxs; int idx = -1; for(auto &layer : act_layers) { idx = layers.indexOf(layer); if(idx >= 0) layers_idxs.push_back(idx); } setActiveLayers(layers_idxs); } void ObjectsScene::setActiveLayers(QList layers_idxs) { BaseObjectView *obj_view = nullptr; active_layers.clear(); if(!layers_idxs.isEmpty()) { bool is_in_layer = false; unsigned layer_cnt = static_cast(layers.size()); SchemaView *sch_view = nullptr; for(auto &item : this->items()) { obj_view = dynamic_cast(item); if(obj_view && !obj_view->parentItem() && obj_view->getLayer() < layer_cnt) { sch_view = dynamic_cast(obj_view); is_in_layer = layers_idxs.contains(obj_view->getLayer()); if(!obj_view->isVisible() && is_in_layer) { if(!sch_view || (sch_view && dynamic_cast(sch_view->getUnderlyingObject())->isRectVisible())) obj_view->setVisible(true); } else if(obj_view->isVisible() && !is_in_layer) obj_view->setVisible(false); } } for(auto &idx : layers_idxs) { if(idx < layer_cnt) active_layers.push_back(layers[idx]); } } else { for(auto &item : this->items()) { obj_view = dynamic_cast(item); if(obj_view && !obj_view->parentItem()) obj_view->setVisible(false); } } emit s_activeLayersChanged(); } void ObjectsScene::moveObjectsToLayer(unsigned old_layer, unsigned new_layer) { BaseObjectView *obj_view = nullptr; unsigned total_layers = layers.size(); if(old_layer == new_layer || old_layer >= total_layers || new_layer >= total_layers) return; for(auto &item : this->items()) { obj_view = dynamic_cast(item); if(obj_view && !obj_view->parentItem() && obj_view->getLayer() == old_layer) { obj_view->setLayer(new_layer); obj_view->setVisible(isLayerActive(layers[new_layer])); } } emit s_objectsMovedLayer(); } bool ObjectsScene::isLayerActive(const QString &name) { return(active_layers.contains(name)); } bool ObjectsScene::isLayerActive(unsigned layer_id) { if(layer_id >= static_cast(layers.size())) return(false); return(active_layers.contains(layers[layer_id])); } QStringList ObjectsScene::getActiveLayers(void) { return(active_layers); } QList ObjectsScene::getActiveLayersIds(void) { QList list; for(auto &layer : active_layers) list.push_back(layers.indexOf(layer)); return(list); } QStringList ObjectsScene::getLayers(void) { return(layers); } unsigned ObjectsScene::getLayerId(const QString &name) { int idx = layers.contains(name); return(idx < 0 ? InvalidLayer : static_cast(idx)); } void ObjectsScene::updateActiveLayers(void) { setActiveLayers(active_layers); } void ObjectsScene::setEnableCornerMove(bool enable) { ObjectsScene::corner_move=enable; } void ObjectsScene::setInvertRangeSelectionTrigger(bool invert) { ObjectsScene::invert_rangesel_trigger=invert; } bool ObjectsScene::isCornerMoveEnabled(void) { return(ObjectsScene::corner_move); } QPointF ObjectsScene::alignPointToGrid(const QPointF &pnt) { int px = static_cast(round(pnt.x()/static_cast(grid_size))) * grid_size, py = static_cast(round(pnt.y()/static_cast(grid_size))) * grid_size; if(px < 0) px = 0; if(py < 0) py = 0; return(QPointF(px, py)); } void ObjectsScene::setSceneRect(const QRectF &rect) { QGraphicsScene::setSceneRect(0, 0, rect.width(), rect.height()); } QRectF ObjectsScene::itemsBoundingRect(bool seek_only_db_objs, bool selected_only) { if(!seek_only_db_objs) return(QGraphicsScene::itemsBoundingRect()); else { QRectF rect=QGraphicsScene::itemsBoundingRect(); QList items= (selected_only ? this->selectedItems() : this->items()); double x=rect.width(), y=rect.height(), x2 = -10000, y2 = -10000; BaseObjectView *obj_view=nullptr; QPointF pnt; BaseGraphicObject *graph_obj=nullptr; for(auto &item : items) { obj_view=dynamic_cast(item); if(obj_view && obj_view->isVisible()) { graph_obj=dynamic_cast(obj_view->getUnderlyingObject()); if(graph_obj) { if(graph_obj->getObjectType()!=ObjectType::Relationship && graph_obj->getObjectType()!=ObjectType::BaseRelationship) pnt=graph_obj->getPosition(); else pnt=dynamic_cast(obj_view)->__boundingRect().topLeft(); if(pnt.x() < x) x=pnt.x(); if(pnt.y() < y) y=pnt.y(); if(selected_only) { if(graph_obj->getObjectType()!=ObjectType::Relationship && graph_obj->getObjectType()!=ObjectType::BaseRelationship) pnt = pnt + dynamic_cast(obj_view)->boundingRect().bottomRight(); else pnt = pnt + dynamic_cast(obj_view)->__boundingRect().bottomRight(); if(pnt.x() > x2) x2 = pnt.x(); if(pnt.y() > y2) y2 = pnt.y(); } } } } if(selected_only) return(QRectF(QPointF(x, y), QPointF(x2, y2))); else return(QRectF(QPointF(x, y), rect.bottomRight())); } } void ObjectsScene::setGridSize(unsigned size) { if(size >= 20 || grid.style()==Qt::NoBrush) { QImage grid_img; double width, height, x, y; int img_w, img_h; QSizeF aux_size; QPrinter printer; QPainter painter; QPen pen; configurePrinter(&printer); aux_size=printer.paperSize(QPrinter::Point); aux_size-=page_margins.size(); //Calculates where the extreme width and height where delimiter lines will be drawn width=aux_size.width()/static_cast(size) * size; height=aux_size.height()/static_cast(size) * size; //Calculates the grid pixmpa size img_w=ceil(width/size) * size; img_h=ceil(height/size) * size; grid_size=size; grid_img=QImage(img_w, img_h, QImage::Format_ARGB32); grid_img.fill(Qt::white); painter.begin(&grid_img); if(show_grid) { pen.setColor(QColor(225, 225, 225)); painter.setPen(pen); //Draws the grid for(x=0; x < width; x+=size) for(y=0; y < height; y+=size) painter.drawRect(QRectF(QPointF(x,y),QPointF(x + size,y + size))); } //Creates the page delimiter lines if(show_page_delim) { pen.setColor(QColor(75,115,195)); pen.setStyle(Qt::DashLine); pen.setWidthF(1.0); painter.setPen(pen); painter.drawLine(width-1, 0,width-1,img_h-1); painter.drawLine(0, height-1,img_w-1,height-1); } painter.end(); grid.setTextureImage(grid_img); } } void ObjectsScene::showRelationshipLine(bool value, const QPointF &p_start) { QList items=this->items(); QGraphicsItem::GraphicsItemFlags flags; BaseObjectView *object=nullptr; BaseGraphicObject *base_obj=nullptr; if(!std::isnan(p_start.x()) && !std::isnan(p_start.y())) rel_line->setLine(QLineF(p_start,p_start)); rel_line->setVisible(value); while(!items.isEmpty()) { //When showing the relationship line all the objects cannot be moved flags=QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges; object=dynamic_cast(items.front()); if(object && object->getUnderlyingObject()) { base_obj=dynamic_cast(object->getUnderlyingObject()); if(!value && base_obj && base_obj->getObjectType()!=ObjectType::Relationship && base_obj->getObjectType()!=ObjectType::BaseRelationship && !base_obj->isProtected()) flags=QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges; else flags=QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges; } items.front()->setFlags(flags); items.pop_front(); } } void ObjectsScene::setGridOptions(bool show_grd, bool align_objs_grd, bool show_pag_dlm) { bool redef_grid=(ObjectsScene::show_grid!=show_grd || ObjectsScene::show_page_delim!=show_pag_dlm || grid.style()==Qt::NoBrush); ObjectsScene::show_grid=show_grd; ObjectsScene::show_page_delim=show_pag_dlm; ObjectsScene::align_objs_grid=align_objs_grd; if(redef_grid) { grid.setStyle(Qt::NoBrush); setGridSize(ObjectsScene::grid_size); } } bool ObjectsScene::isAlignObjectsToGrid(void) { return(align_objs_grid); } bool ObjectsScene::isShowGrid(void) { return(show_grid); } bool ObjectsScene::isShowPageDelimiters(void) { return(show_page_delim); } void ObjectsScene::setPaperConfiguration(QPrinter::PaperSize paper_sz, QPrinter::Orientation orient, QRectF margins, QSizeF custom_size) { ObjectsScene::paper_size=paper_sz; ObjectsScene::page_orientation=orient; ObjectsScene::page_margins=margins; ObjectsScene::custom_paper_size=custom_size; } void ObjectsScene::getPaperConfiguration(QPrinter::PaperSize &paper_sz, QPrinter::Orientation &orient, QRectF &margins, QSizeF &custom_size) { paper_sz=ObjectsScene::paper_size; orient=ObjectsScene::page_orientation; margins=ObjectsScene::page_margins; custom_size=ObjectsScene::custom_paper_size; } void ObjectsScene::configurePrinter(QPrinter *printer) { if(!printer) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(paper_size!=QPrinter::Custom) printer->setPaperSize(paper_size); else { #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) //The QTBUG-33645 is fixed on Qt 5.3 QPageLayout pl; QPageSize ps; ps=QPageSize(QSizeF(custom_paper_size.width(), custom_paper_size.height()), QPageSize::Point, QString(), QPageSize::ExactMatch); pl.setPageSize(ps); pl.setOrientation(page_orientation==QPrinter::Landscape ? QPageLayout::Landscape : QPageLayout::Portrait); printer->setPageSize(pl.pageSize()); #else #warning "Custom page size bug (QTBUG-33645) workaround for Qt 5.2 or lower. NOTE: This issue is fixed on Qt 5.3" printer->setPaperSize(QSizeF(custom_paper_size.height(), custom_paper_size.width()), QPrinter::Point); #endif } if(paper_size==QPrinter::Custom) { if(custom_paper_size.width() > custom_paper_size.height()) ObjectsScene::page_orientation=QPrinter::Landscape; else ObjectsScene::page_orientation=QPrinter::Portrait; } else printer->setOrientation(page_orientation); printer->setPageMargins(page_margins.left(), page_margins.top(), page_margins.width(), page_margins.height(), QPrinter::Millimeter); } void ObjectsScene::configurePrinter(QPrinter *printer, const QSizeF &custom_size, QPrinter::Orientation orient) { QPrinter::PaperSize orig_page_sz=paper_size; QPrinter::Orientation orig_orient=page_orientation; QSizeF orig_custom_sz=custom_paper_size; paper_size=QPrinter::Custom; page_orientation=orient; custom_paper_size=custom_size; configurePrinter(printer); paper_size=orig_page_sz; page_orientation=orig_orient; custom_paper_size=orig_custom_sz; } void ObjectsScene::handlePopupMenuRequested(TableObject *child_obj) { emit s_popupMenuRequested(child_obj); } void ObjectsScene::handleObjectSelection(BaseGraphicObject *object, bool selected) { if(object) emit s_objectSelected(object, selected); } void ObjectsScene::handleChildrenSelectionChanged(void) { BaseTableView *tab_view = dynamic_cast(sender()); if(!tab_view) return; if(tab_view->getSelectedChidren().empty()) tabs_sel_children.removeAll(tab_view); else if(!tabs_sel_children.contains(tab_view)) tabs_sel_children.append(tab_view); emit s_childrenSelectionChanged(); } void ObjectsScene::addItem(QGraphicsItem *item) { if(item) { RelationshipView *rel=dynamic_cast(item); BaseTableView *tab=dynamic_cast(item); BaseObjectView *obj=dynamic_cast(item); if(rel) connect(rel, SIGNAL(s_relationshipModified(BaseGraphicObject*)), this, SIGNAL(s_objectModified(BaseGraphicObject*))); else if(tab) { connect(tab, SIGNAL(s_popupMenuRequested(TableObject*)), this, SLOT(handlePopupMenuRequested(TableObject*))); connect(tab, SIGNAL(s_childrenSelectionChanged()), this, SLOT(handleChildrenSelectionChanged())); connect(tab, SIGNAL(s_collapseModeChanged()), this, SIGNAL(s_collapseModeChanged())); connect(tab, SIGNAL(s_paginationToggled()), this, SIGNAL(s_paginationToggled())); connect(tab, SIGNAL(s_currentPageChanged()), this, SIGNAL(s_currentPageChanged())); connect(tab, SIGNAL(s_sceneClearRequested()), this, SLOT(clearSelection())); } if(obj) { obj->setVisible(isLayerActive(obj->getLayer())); connect(obj, SIGNAL(s_objectSelected(BaseGraphicObject*,bool)), this, SLOT(handleObjectSelection(BaseGraphicObject*,bool))); } QGraphicsScene::addItem(item); } } void ObjectsScene::removeItem(QGraphicsItem *item) { if(item) { BaseObjectView *object=dynamic_cast(item); RelationshipView *rel=dynamic_cast(item); if(rel) rel->disconnectTables(); item->setVisible(false); item->setActive(false); QGraphicsScene::removeItem(item); if(object) { disconnect(object, nullptr, this, nullptr); disconnect(object, nullptr, dynamic_cast(object->getUnderlyingObject()), nullptr); disconnect(dynamic_cast(object->getUnderlyingObject()), nullptr, object, nullptr); removed_objs.push_back(object); } } } void ObjectsScene::blockItemsSignals(bool block) { BaseObjectView *obj_view = nullptr; for(auto &item : this->items()) { obj_view = dynamic_cast(item); if(obj_view) obj_view->blockSignals(block); } } void ObjectsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { QGraphicsScene::mouseDoubleClickEvent(event); if(this->selectedItems().size()==1 && event->buttons()==Qt::LeftButton && !rel_line->isVisible()) { //Gets the selected graphical object BaseObjectView *obj=dynamic_cast(this->selectedItems().at(0)); if(obj) emit s_objectDoubleClicked(dynamic_cast(obj->getUnderlyingObject())); } else //Emit a signal indicating that no object was selected emit s_objectDoubleClicked(nullptr); } void ObjectsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { //Gets the item at mouse position QGraphicsItem* item=this->itemAt(event->scenePos(), QTransform()); bool is_deselection = !this->selectedItems().isEmpty() && !item; if(selectedItems().empty()) emit s_objectsScenePressed(event->buttons()); /* If the relationship line is visible, indicates that the user is in the middle of a relationship creation, thus is needed to inform to the scene to activate the the multiselection to be able to select two tables and link them. By default, the multiselection modifier is the Control key */ if(rel_line->isVisible()) event->setModifiers(Qt::ControlModifier); if(is_deselection) this->blockItemsSignals(true); /* If we're handling a deselection of the user selected another object whitout being holding Control * we need to deselect the tables' children objects too */ if(is_deselection || (event->buttons()==Qt::LeftButton && (event->modifiers() & Qt::ControlModifier) != Qt::ControlModifier)) //Forcing the clear on all selected table children object clearTablesChildrenSelection(); QGraphicsScene::mousePressEvent(event); if(is_deselection) { this->blockItemsSignals(false); emit s_objectSelected(nullptr, false); } if(event->buttons()==Qt::LeftButton) { sel_ini_pnt=event->scenePos(); if((!invert_rangesel_trigger && event->modifiers()==Qt::ShiftModifier) || (invert_rangesel_trigger && event->modifiers()==Qt::NoModifier)) { if(enable_range_sel && this->selectedItems().isEmpty()) { selection_rect->setVisible(true); emit s_objectSelected(nullptr,false); } } else { //Selects the object (without press control) if the user is creating a relationship if(item && item->isEnabled() && !item->isSelected() && rel_line->isVisible()) item->setSelected(true); } } else if(event->buttons()==Qt::RightButton) { //Case there is no item at the mouse position clears the selection on the scene if(!item) { this->clearSelection(); emit s_objectSelected(nullptr,false); } emit s_popupMenuRequested(); } } bool ObjectsScene::mouseIsAtCorner(void) { QGraphicsView *view=getActiveViewport(); if(view) { QPoint pos=view->mapFromGlobal(QCursor::pos()); QRect rect=view->rect(); if(rect.contains(pos)) { if(pos.x() <= SceneMoveThreshold) scene_move_dx=-SceneMoveStep; else if(pos.x() >= (view->width() - view->verticalScrollBar()->width() - SceneMoveThreshold)) scene_move_dx=SceneMoveStep; else scene_move_dx=0; if(pos.y() <= SceneMoveThreshold) scene_move_dy=-SceneMoveStep; else if(pos.y() >= (view->height() - view->horizontalScrollBar()->height() - SceneMoveThreshold)) scene_move_dy=SceneMoveStep; else scene_move_dy=0; return(scene_move_dx!=0 || scene_move_dy!=0); } else return(false); } else return(false); } QGraphicsView *ObjectsScene::getActiveViewport(void) { QGraphicsView *view_p=nullptr; for(auto &view : this->views()) { if(view && view->isActiveWindow()) { view_p=view; break; } } return(view_p); } void ObjectsScene::moveObjectScene(void) { if(scene_move_dx!=0 || scene_move_dy!=0) { QGraphicsView *view=getActiveViewport(); if(view && mouseIsAtCorner()) { view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() + scene_move_dx); view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() + scene_move_dy); move_scene=true; } else { move_scene=false; scene_move_timer.stop(); } } } void ObjectsScene::enableSceneMove(bool value) { if(value) { scene_move_timer.start(); corner_hover_timer.stop(); } else { corner_hover_timer.stop(); scene_move_timer.stop(); } move_scene=value; } void ObjectsScene::enableRangeSelection(bool value) { enable_range_sel=value; if(!value && selection_rect->isVisible()) selection_rect->setVisible(value); } void ObjectsScene::adjustScenePositionOnKeyEvent(int key) { QGraphicsView *view = getActiveViewport(); if(view) { QRectF brect = itemsBoundingRect(true, true); QRectF view_rect = QRectF(view->mapToScene(view->rect().topLeft()), view->mapToScene(view->rect().bottomRight())), scene_rect = sceneRect(); if(view_rect.right() < brect.right() && key == Qt::Key_Right) { /* If the objects are being moved right and the scene width is lesser than the items bounding rect's width we need to resize the scene prior the position adjustment */ scene_rect.setRight(brect.right()); setSceneRect(scene_rect); view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() + ((brect.right() - view_rect.right()) * 2)); } else if(view_rect.left() > brect.left() && key == Qt::Key_Left) view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() - ((view_rect.left() - brect.left()) * 2)); if(view_rect.bottom() < brect.bottom() && key == Qt::Key_Down) { /* If the objects are being moved down and the scene hight is lesser than the items bounding rect's height we need to resize the scene prior the position adjustment */ scene_rect.setBottom(brect.bottom()); setSceneRect(scene_rect); view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() + ((brect.bottom() - view_rect.bottom()) * 2)); } else if(view_rect.top() > brect.top() && key == Qt::Key_Up) view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() - ((view_rect.top() - brect.top()) * 2)); } } void ObjectsScene::keyPressEvent(QKeyEvent *event) { if((event->key() == Qt::Key_Up || event->key() == Qt::Key_Down || event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) && !selectedItems().isEmpty()) { double dx = 0, dy = 0; BaseObjectView *obj_view=nullptr; QRectF brect = itemsBoundingRect(true, true); if(!moving_objs) { sel_ini_pnt = brect.center(); moving_objs = true; /* If the object move timer is not active we need to send the s_objectsMoved() signal in order to alert the classes like ModelWidget to save the current objects' position in the operation history */ if(!object_move_timer.isActive()) emit s_objectsMoved(false); for(auto item : selectedItems()) { obj_view=dynamic_cast(item); if(obj_view && BaseObjectView::isPlaceholderEnabled()) obj_view->togglePlaceholder(true); } } if(event->key() == Qt::Key_Up) dy = -1; else if(event->key() == Qt::Key_Down) dy = 1; if(event->key() == Qt::Key_Left) dx = -1; else if(event->key() == Qt::Key_Right) dx = 1; if(event->modifiers() == Qt::ControlModifier) { dx *= 10; dy *= 10; } else if(event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { dx *= 100; dy *= 100; } for(auto item : selectedItems()) { obj_view=dynamic_cast(item); if(obj_view && !dynamic_cast(obj_view)) obj_view->moveBy(dx, dy); } adjustScenePositionOnKeyEvent(event->key()); } else QGraphicsScene::keyPressEvent(event); } void ObjectsScene::keyReleaseEvent(QKeyEvent *event) { if((event->key() == Qt::Key_Up || event->key() == Qt::Key_Down || event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) && !event->isAutoRepeat() && !selectedItems().isEmpty()) { if(moving_objs) { object_move_timer.start(); adjustScenePositionOnKeyEvent(event->key()); } } else QGraphicsScene::keyReleaseEvent(event); } void ObjectsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if(event->buttons()==Qt::LeftButton || rel_line->isVisible()) { if(corner_move) { if(mouseIsAtCorner()) { if(move_scene) scene_move_timer.start(); else corner_hover_timer.start(); } else enableSceneMove(false); } if(!rel_line->isVisible()) { int sel_items_count = this->selectedItems().size(); //Case the user starts a object moviment if(sel_items_count != 0 && !moving_objs) { if(BaseObjectView::isPlaceholderEnabled()) { QList items=this->selectedItems(); BaseObjectView *obj_view=nullptr; for(QGraphicsItem *item : items) { obj_view=dynamic_cast(item); obj_view->togglePlaceholder(true); } } emit s_objectsMoved(false); moving_objs=true; } //If the alignment to grid is active, adjust the event scene position if(align_objs_grid && !selection_rect->isVisible() && sel_items_count <= 1) event->setScenePos(this->alignPointToGrid(event->scenePos())); else if(selection_rect->isVisible()) { QPolygonF pol; pol.append(sel_ini_pnt); pol.append(QPointF(event->scenePos().x(), sel_ini_pnt.y())); pol.append(QPointF(event->scenePos().x(), event->scenePos().y())); pol.append(QPointF(sel_ini_pnt.x(), event->scenePos().y())); selection_rect->setPolygon(pol); selection_rect->setBrush(BaseObjectView::getFillStyle(Attributes::ObjSelection)); selection_rect->setPen(BaseObjectView::getBorderStyle(Attributes::ObjSelection)); } } } if(rel_line->isVisible()) rel_line->setLine(QLineF(rel_line->line().p1(), event->scenePos())); QGraphicsScene::mouseMoveEvent(event); } void ObjectsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { QGraphicsScene::mouseReleaseEvent(event); if(event->button()==Qt::LeftButton && corner_move) enableSceneMove(false); //If there is selected object and the user ends the object moviment if(!this->selectedItems().isEmpty() && moving_objs && event->button()==Qt::LeftButton/* && event->modifiers()==Qt::NoModifier */) { finishObjectsMove(event->scenePos()); } else if(selection_rect->isVisible() && event->button()==Qt::LeftButton) { QPolygonF pol; QPainterPath sel_area; sel_area.addRect(selection_rect->polygon().boundingRect()); this->blockItemsSignals(true); this->setSelectionArea(sel_area, Qt::IntersectsItemShape); this->blockItemsSignals(false); selection_rect->setVisible(false); selection_rect->setPolygon(pol); sel_ini_pnt.setX(DNaN); sel_ini_pnt.setY(DNaN); if(!this->selectedItems().isEmpty()) emit s_objectsSelectedInRange(); } } void ObjectsScene::finishObjectsMove(const QPointF &pnt_end) { QList items=this->selectedItems(), rel_list; double x1,y1,x2,y2, dx, dy; QRectF rect; SchemaView *sch_view=nullptr; vector points; vector::iterator itr; vector rels, base_rels; QSet schemas; BaseRelationship *base_rel=nullptr; RelationshipView *rel=nullptr; BaseObjectView *obj_view=nullptr; BaseTableView *tab_view=nullptr; TableObjectView *tab_obj_view=nullptr; QSet tables; //Gathering the relationships inside the selected schemsa in order to move their points too for(auto &item : items) { obj_view=dynamic_cast(item); sch_view=dynamic_cast(item); tab_view=dynamic_cast(item); tab_obj_view=dynamic_cast(item); // Ignoring table objects items if(tab_obj_view) continue; if(obj_view) obj_view->togglePlaceholder(false); if(tab_view) tables.insert(tab_view); else if(sch_view) { //Get the schema object Schema *schema=dynamic_cast(sch_view->getUnderlyingObject()); if(!schema->isProtected()) { //Get the table-table and table-view relationships rels=dynamic_cast(schema->getDatabase())->getObjects(ObjectType::Relationship, schema); base_rels=dynamic_cast(schema->getDatabase())->getObjects(ObjectType::BaseRelationship, schema); rels.insert(rels.end(), base_rels.begin(), base_rels.end()); for(auto &rel : rels) { base_rel=dynamic_cast(rel); /* If the relationship contains points and it is not selected then it will be included on the list in order to move their custom line points */ if(!dynamic_cast(base_rel->getOverlyingObject())->isSelected() && !base_rel->getPoints().empty()) rel_list.push_back(dynamic_cast(base_rel->getOverlyingObject())); } tables.unite(sch_view->getChildren().toSet()); } } } items.append(rel_list); /* Get the extreme points of the scene to check if some objects are out the area forcing the scene to be resized */ x1=this->sceneRect().left(); y1=this->sceneRect().top(); x2=this->sceneRect().right(); y2=this->sceneRect().bottom(); dx=pnt_end.x() - sel_ini_pnt.x(); dy=pnt_end.y() - sel_ini_pnt.y(); for(auto &item : items) { // Ignoring table objects items tab_obj_view=dynamic_cast(item); if(tab_obj_view) continue; rel=dynamic_cast(item); if(!rel) { if(align_objs_grid) item->setPos(alignPointToGrid(item->pos())); else { QPointF p=item->pos(); if(p.x() < 0) p.setX(0); if(p.y() < 0) p.setY(0); item->setPos(p); } rect.setTopLeft(item->pos()); rect.setSize(item->boundingRect().size()); } else { /* If the relationship has points added to the line is necessary to move the points too. Since relationships cannot be moved naturally (by user) this will be done by the scene. NOTE: this operation is done ONLY WHEN there is more than one object selected! */ points=rel->getUnderlyingObject()->getPoints(); if(items.size() > 1 && !points.empty()) { itr=points.begin(); while(itr!=points.end()) { //Translate the points itr->setX(itr->x() + dx); itr->setY(itr->y() + dy); //Align to grid if the flag is set if(align_objs_grid) (*itr)=alignPointToGrid(*itr); itr++; } //Assing the new points to relationship and reconfigure its line rel->getUnderlyingObject()->setPoints(points); rel->configureLine(); } rect=rel->__boundingRect(); } //Made the comparisson between the scene extremity and the object's bounding rect if(rect.left() < x1) x1=rect.left(); if(rect.top() < y1) y1=rect.top(); if(rect.right() > x2) x2=rect.right(); if(rect.bottom() > y2) y2=rect.bottom(); } //Reconfigures the rectangle with the most extreme points rect.setCoords(x1, y1, x2, y2); //If the new rect is greater than the scene bounding rect, this latter is resized if(rect!=this->sceneRect()) { rect=this->itemsBoundingRect(); rect.setTopLeft(QPointF(0,0)); rect.setWidth(rect.width() * 1.05); rect.setHeight(rect.height() * 1.05); this->setSceneRect(rect); } for(auto &obj : tables) { tab_view=dynamic_cast(obj); //Realign tables if the parent schema had the position adjusted too if(align_objs_grid) { tab_view->setPos(alignPointToGrid(tab_view->pos())); schemas.insert(dynamic_cast(tab_view->getUnderlyingObject()->getSchema())); } if(BaseObjectView::isPlaceholderEnabled()) tab_view->requestRelationshipsUpdate(); } //Updating schemas bounding rects after moving objects for(auto &obj : schemas) obj->setModified(true); emit s_objectsMoved(true); moving_objs=false; sel_ini_pnt.setX(DNaN); sel_ini_pnt.setY(DNaN); } void ObjectsScene::alignObjectsToGrid(void) { QList items=this->items(); RelationshipView *rel=nullptr; BaseTableView *tab=nullptr; TextboxView *lab=nullptr; vector points; vector schemas; unsigned i, count, i1, count1; count=items.size(); for(i=0; i < count; i++) { if(dynamic_cast(items[i]) && !items[i]->parentItem()) { tab=dynamic_cast(items[i]); rel=dynamic_cast(items[i]); if(tab) tab->setPos(this->alignPointToGrid(tab->pos())); else if(rel) { //Align the relationship points points=rel->getUnderlyingObject()->getPoints(); count1=points.size(); for(i1=0; i1 < count1; i1++) points[i1]=this->alignPointToGrid(points[i1]); if(count1 > 0) { rel->getUnderlyingObject()->setPoints(points); rel->configureLine(); } //Align the labels for(i1=BaseRelationship::SrcCardLabel; i1<=BaseRelationship::RelNameLabel; i1++) { lab=rel->getLabel(i1); if(lab) lab->setPos(this->alignPointToGrid(lab->pos())); } } else if(!dynamic_cast(items[i])) items[i]->setPos(this->alignPointToGrid(items[i]->pos())); else schemas.push_back(dynamic_cast(dynamic_cast(items[i])->getUnderlyingObject())); } } //Updating schemas dimensions while(!schemas.empty()) { schemas.back()->setModified(true); schemas.pop_back(); } } void ObjectsScene::update(void) { this->setBackgroundBrush(grid); QGraphicsScene::update(this->sceneRect()); } void ObjectsScene::clearTablesChildrenSelection(void) { for(auto &tab_obj_view : tabs_sel_children) tab_obj_view->clearChildrenSelection(); tabs_sel_children.clear(); } void ObjectsScene::clearSelection(void) { clearTablesChildrenSelection(); QGraphicsScene::clearSelection(); } vector ObjectsScene::getPagesForPrinting(const QSizeF &paper_size, const QSizeF &margin, unsigned &h_page_cnt, unsigned &v_page_cnt) { vector pages; QRectF page_rect, max_rect; double width, height, page_width, page_height; unsigned h_page=0, v_page=0, start_h=99999, start_v=99999; QList list; page_width=ceil(paper_size.width() - margin.width()-1); page_height=ceil(paper_size.height() - margin.height()-1); //Calculates the horizontal and vertical page count based upon the passed paper size h_page_cnt=round(this->sceneRect().width()/page_width) + 1; v_page_cnt=round(this->sceneRect().height()/page_height) + 1; //Calculates the maximum count of horizontal and vertical pages for(v_page=0; v_page < v_page_cnt; v_page++) { for(h_page=0; h_page < h_page_cnt; h_page++) { //Calculates the current page rectangle page_rect=QRectF(QPointF(h_page * page_width, v_page * page_height), QSizeF(page_width, page_height)); //Case there is selected items recalculates the maximum page size list=this->items(page_rect, Qt::IntersectsItemShape); if(!list.isEmpty()) { if(start_h > h_page) start_h=h_page; if(start_v > v_page) start_v=v_page; width=page_rect.left() + page_rect.width(); height=page_rect.top() + page_rect.height(); if(width > max_rect.width()) max_rect.setWidth(width); if(height > max_rect.height()) max_rect.setHeight(height); } } } //Re calculates the maximum page count based upon the maximum page size h_page_cnt=round(max_rect.width()/page_width); v_page_cnt=round(max_rect.height()/page_height); //Inserts the page rectangles on the list for(v_page=static_cast(start_v); v_page < v_page_cnt; v_page++) for(h_page=static_cast(start_h); h_page < h_page_cnt; h_page++) pages.push_back(QRectF(QPointF(h_page * page_width, v_page * page_height), QSizeF(page_width, page_height))); return(pages); } bool ObjectsScene::isRangeSelectionEnabled(void) { return(enable_range_sel); } bool ObjectsScene::isRangeSelectionTriggerInverted(void) { return(invert_rangesel_trigger); } bool ObjectsScene::isRelationshipLineVisible(void) { return(rel_line->isVisible()); } bool ObjectsScene::isMovingObjects(void) { return(moving_objs); } QList ObjectsScene::selectedItems(void) const { if(tabs_sel_children.empty()) return(QGraphicsScene::selectedItems()); QList items = QGraphicsScene::selectedItems(); for(auto &tab_view :tabs_sel_children) { for(auto &tab_obj : tab_view->getSelectedChidren()) items.append(tab_obj); } return(items); } bool ObjectsScene::hasOnlyTableChildrenSelection() const { return(QGraphicsScene::selectedItems().isEmpty() && !tabs_sel_children.isEmpty()); } pgmodeler-0.9.2/libobjrenderer/src/objectsscene.h000066400000000000000000000322261360462764600221220ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class ObjectsScene \brief Implements the basic operations to visualize and manipulate the graphical objects. */ #ifndef OBJECTS_SCENE_H #define OBJECTS_SCENE_H #include #include #include "relationshipview.h" #include "graphicalview.h" #include "tableview.h" #include "schemaview.h" #include "styledtextboxview.h" class ObjectsScene: public QGraphicsScene { private: Q_OBJECT //! \brief Holds the names of the layers on the scene used to separate in the objects on the canvas QStringList layers, active_layers; vector removed_objs; //! \brief Holds the tables/views which have selected children objects QList tabs_sel_children; //! \brief Indicates if the corner move is enabled for the scene static bool corner_move, /*! \brief Indicates that panning mode and range selection model are activate in inverse mode. By default panning model is activated with a single left-click and range selection with SHIFT + left-click */ invert_rangesel_trigger; //! \brief Indicates if the scene need to be moved bool move_scene; static constexpr int SceneMoveStep=20, SceneMoveTimeout=50, SceneMoveThreshold=30; //! \brief Timer responsible to move the scene QTimer scene_move_timer, /*! \brief Timer responsible to check if the user puts cursor at corners for a certain amount of time. When this timeout the scene_move_timer will be triggered and the scene will be moved */ corner_hover_timer, /*! brief Timer responsible to control the interval between key presses/releases when moving objects with the keyboard. This timer is started whenever the user releases the arrow keys. If the timer emits timeout() signal indicates that the user take more than 500ms to press and release the arrow keys again, this indicates to the scene to emit the signal s_objectsMove(true) to alert the end of the objects moving. If the user presses/releases the keys when the timer is still running the same will be restarted, until its timeout is reached. This trick avoids 'spamming' the operation list in ModelWidget creating registries only when the user starts and ends the objects movement. Intermediate key presses/releases aren't not registered in the operation history */ object_move_timer; //! \brief Attributes used to control the direction of scene movement when user puts cursor at corners int scene_move_dx, scene_move_dy; //! \brief Object alignemnt, grid showing, page delimiter showing options static bool align_objs_grid, show_grid, show_page_delim; //! \brief Scene grid size static unsigned grid_size; //! \brief Paper size, used to segmentate the view (via page delimiters) and printing the model static QPrinter::PaperSize paper_size; //! \brief Used to store the custom paper size. This attribute is used only when paper_size=QPrinter::Custom static QSizeF custom_paper_size; //! \brief Page orientation (landscape / portrait) static QPrinter::Orientation page_orientation; //! \brief Page margins (applied to paper total size) static QRectF page_margins; //! \brief Indicates that there are objects being moved and the signal s_objectsMoved must be emitted bool moving_objs, //! \brief Indicates if the range selection (selection using a rectangle drawn on the canvas) enable_range_sel; //! \brief Initial point of selection rectangle QPointF sel_ini_pnt; //! \brief Rectangle used to select several objects on the scene QGraphicsPolygonItem *selection_rect; //! \brief Line used as a guide when inserting new relationship QGraphicsLineItem *rel_line; /*! \brief Indicates if the mouse cursor is under a move spot portion of scene. Additionally this method configures the direction of movement when returning true */ bool mouseIsAtCorner(void); QGraphicsView *getActiveViewport(void); //! \brief Performs the final steps when moving the objects like adjusting position to grid, moving children object, etc void finishObjectsMove(const QPointF &pnt_end); /*! \brief Performs the scene position adjustment when pressing/releasing the arrow keys to avoid objects to be hidden in the corners. This method will adjust the scene size automatically when moving objects right or down if the selected items bounding rects exceeds the scene's size limits */ void adjustScenePositionOnKeyEvent(int key); //! \brief Formats the name of the layer removing any invalid chars and doing the desambiguation in case the name already exists QString formatLayerName(const QString &name); void clearTablesChildrenSelection(void); protected: //! \brief Brush used to draw the grid over the scene static QBrush grid; void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); //! \brief Draws a line from the point 'p_start' to the cursor position and simulates the relationship creation void showRelationshipLine(bool value, const QPointF &p_start=QPointF(DNaN,DNaN)); void blockItemsSignals(bool block); public: static constexpr unsigned DefaultLayer = 0, InvalidLayer = UINT_MAX; ObjectsScene(void); ~ObjectsScene(void); /*! \brief Add a new layer to the scene. In case of duplicated name this method * automatically does the desambiguation. The name of the new layer is returned. */ QString addLayer(const QString &name); /*! \brief Rename the layer of the provided index. In case of duplicated name this method * automatically does the desambiguation. */ QString renameLayer(unsigned idx, const QString &name); //! \brief Remove the named layer. Objects in the destroyed layer are automatically moved to the default one void removeLayer(const QString &name); //! \brief Destroy all layers (except the default one) moving all objects from the destroyed layers to the default one void removeLayers(void); //! \brief Set the named layers as active. Activating a layer causes objects attached to it to be visible void setActiveLayers(QStringList act_layers); //! \brief Set the layers with the provided indexes as active. Activating a layer causes objects attached to it to be visible void setActiveLayers(QList ids); /*! \brief Move the objects from a layer to another. This method automatically hides/show the objects in the new layer * according to the activation status of the destination layer */ void moveObjectsToLayer(unsigned old_layer, unsigned new_layer); //! \brief Returns true when the named layer is currenctly activated bool isLayerActive(const QString &name); //! \brief Returns true when the layer with the provided id is currenctly activated bool isLayerActive(unsigned layer_id); //! \brief Returns a list containing the names of the active layers QStringList getActiveLayers(void); //! \brief Returns a list containing the ids of the active layers QList getActiveLayersIds(void); //! \brief Returns a list containing the names of all layers in the scene QStringList getLayers(void); //! \brief Returns the id of the named layer. If the layer does not exist the constant ObjectsScene::InvalidLayer is returned unsigned getLayerId(const QString &name); //! \brief This method causes objects in the active layers to have their visibility state updated. void updateActiveLayers(void); static void setEnableCornerMove(bool enable); static void setInvertRangeSelectionTrigger(bool invert); static bool isCornerMoveEnabled(void); static void setGridSize(unsigned size); static void setGridOptions(bool show_grd, bool align_objs_grd, bool show_page_dlm); static bool isAlignObjectsToGrid(void); static bool isShowGrid(void); static bool isShowPageDelimiters(void); static void setPaperConfiguration(QPrinter::PaperSize paper_sz, QPrinter::Orientation orient, QRectF margins, QSizeF custom_size=QSizeF(0,0)); static void getPaperConfiguration(QPrinter::PaperSize &paper_sz, QPrinter::Orientation &orient, QRectF &margins, QSizeF &custom_size); static void configurePrinter(QPrinter *printer); static void configurePrinter(QPrinter *printer, const QSizeF &custom_size, QPrinter::Orientation orient); void addItem(QGraphicsItem *item); void removeItem(QGraphicsItem *item); void setSceneRect(const QRectF &rect); //! \brief Aligns the specified point in relation to the grid static QPointF alignPointToGrid(const QPointF &pnt); /*! \brief Returns the items bounding rect. By default the method returns the same as QGraphicsScene::itemsBoundingRect. If the parameter seek_only_db_objs is true the returned rect will have the origin point calculated based upon the visible objects that inherits BaseObjectView and are database model objects (tables, views, textboxes, schemas and relationships). If the paramenter selected_only is true only selected objects will have the bounding rect calculated. Currently this parameter is ignored when using seek_only_db_objs = false Note: using this method with seek_only_db_objs=true can be time expensive depending on the size of the model so use it wisely. */ QRectF itemsBoundingRect(bool seek_only_db_objs=false, bool selected_only = false); //! \brief Returns a vector containing all the page rects. vector getPagesForPrinting(const QSizeF &paper_size, const QSizeF &margin, unsigned &h_page_cnt, unsigned &v_page_cnt); bool isRangeSelectionEnabled(void); bool isRangeSelectionTriggerInverted(void); bool isRelationshipLineVisible(void); bool isMovingObjects(void); QList selectedItems(void) const; bool hasOnlyTableChildrenSelection(void) const; public slots: void alignObjectsToGrid(void); void update(void); void clearSelection(void); //! \brief Toggles the object range selection void enableRangeSelection(bool value); private slots: /*! \brief Start/stop the timer responsible to move the scene. This method is called with true param whenever the user stay with the cursor at corner in a certain amount of time */ void enableSceneMove(bool value=true); //! \brief Moves the scene when the user puts the mouse cursor on one of scene's edges void moveObjectScene(void); //! \brief Handles and redirects the signal emitted by the selected child object void handlePopupMenuRequested(TableObject *child_obj); //! \brief Handles and redirects the signal emitted by the selected object void handleObjectSelection(BaseGraphicObject *object, bool selected); //! \brief Handles the tables children objects selection changes void handleChildrenSelectionChanged(void); signals: //! \brief Signal emitted when the user start or finalizes a object movement. void s_objectsMoved(bool end_moviment); //! \brief Signal emitted when a object is modified on scene void s_objectModified(BaseGraphicObject *objeto); //! \brief Signal emitted when the user toggles a table's collapse mode in the scene void s_collapseModeChanged(void); //! \brief Signal emitted when the user toggles a table's attributes pagination void s_paginationToggled(void); //! \brief Signal emitted when the user changes a table's attributes page void s_currentPageChanged(void); //! \brief Signal emitted when the user right-click a specific object on the scene requesting the popup menu void s_popupMenuRequested(BaseObject *); //! \brief Signal emitted when the user right-click one or more objects on the scene requesting the popup menu void s_popupMenuRequested(void); //! \brief Signal emitted when the user double-click a object void s_objectDoubleClicked(BaseGraphicObject *objeto); //! \brief Signal emitted when a object is selected void s_objectSelected(BaseGraphicObject *objeto, bool selecionado); //! \brief Signal emitted when objects are selected via range selection void s_objectsSelectedInRange(void); //! \brief Signal emitted when a blank area of the canvas is pressed void s_objectsScenePressed(Qt::MouseButtons); //! \brief Signal emitted when the active layers change void s_activeLayersChanged(void); //! \brief Signal emitted when the layers change (add, remove, rename) void s_layersChanged(void); //! \brief Signal emitted when objects are moved from a layer to another void s_objectsMovedLayer(void); //! \brief Signal emitted when tables children objects have their selection statuses changed void s_childrenSelectionChanged(void); friend class ModelWidget; }; #endif pgmodeler-0.9.2/libobjrenderer/src/relationshipview.cpp000066400000000000000000001760601360462764600234070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "relationshipview.h" bool RelationshipView::hide_name_label=false; bool RelationshipView::use_curved_lines=true; bool RelationshipView::use_crows_foot=false; unsigned RelationshipView::line_conn_mode=RelationshipView::ConnectFkToPk; RelationshipView::RelationshipView(BaseRelationship *rel) : BaseObjectView(rel) { if(!rel) throw Exception(ErrorCode::AsgNotAllocattedObject, __PRETTY_FUNCTION__, __FILE__, __LINE__); for(unsigned i=BaseRelationship::SrcCardLabel; i <= BaseRelationship::RelNameLabel; i++) { if(rel->getLabel(i)) { labels[i]=new TextboxView(rel->getLabel(i), true); labels[i]->setZValue(i==BaseRelationship::RelNameLabel ? 1 : 2); this->addToGroup(labels[i]); } else labels[i]=nullptr; } sel_object=nullptr; sel_object_idx=-1; configuring_line=false; using_placeholders=BaseObjectView::isPlaceholderEnabled(); descriptor=new QGraphicsPolygonItem; descriptor->setZValue(0); this->addToGroup(descriptor); obj_shadow=new QGraphicsPolygonItem; obj_shadow->setZValue(-1); this->addToGroup(obj_shadow); obj_selection=new QGraphicsPolygonItem; obj_selection->setZValue(4); obj_selection->setVisible(false); this->addToGroup(obj_selection); tables[0]=tables[1]=nullptr; for(unsigned i=0; i < 2; i++) { round_cf_descriptors[i] = nullptr; cf_descriptors[i] = nullptr; line_circles[i]=new QGraphicsEllipseItem; line_circles[i]->setRect(QRectF(0,0,GraphicPointRadius,GraphicPointRadius)); line_circles[i]->setZValue(0); line_circles[i]->setVisible(false); this->addToGroup(line_circles[i]); } //Relationship has the minor Z, being on the bottom of scene object's stack this->setZValue(-1); this->configureObject(); } RelationshipView::~RelationshipView(void) { QGraphicsItem *item=nullptr; vector *> rel_lines = { &lines, &fk_lines, &pk_lines, &src_cf_lines, &dst_cf_lines }; while(!curves.empty()) { this->removeFromGroup(curves.back()); item = curves.back(); curves.pop_back(); delete(item); } for(int i=0; i < 2; i++) { this->removeFromGroup(line_circles[i]); delete(line_circles[i]); } for(int i=0; i < 3; i++) { if(labels[i]) { this->removeFromGroup(labels[i]); delete(labels[i]); } } while(!attributes.empty()) { item=attributes.back(); this->removeFromGroup(item); attributes.pop_back(); delete(item); } for(auto &lines : rel_lines) { while(!lines->empty()) { item = lines->back(); this->removeFromGroup(item); lines->pop_back(); delete(item); } } this->removeFromGroup(descriptor); delete(descriptor); for(int i =0; i < 2; i++) { if(cf_descriptors[i]) { for(auto &item : cf_descriptors[i]->childItems()) { cf_descriptors[i]->removeFromGroup(item); this->removeFromGroup(item); delete(item); } this->removeFromGroup(cf_descriptors[i]); delete(cf_descriptors[i]); } } } void RelationshipView::setHideNameLabel(bool value) { hide_name_label=value; } bool RelationshipView::isNameLabelHidden(void) { return(hide_name_label); } void RelationshipView::setCurvedLines(bool value) { use_curved_lines = value; } bool RelationshipView::isCurvedLines(void) { return(use_curved_lines); } void RelationshipView::setCrowsFoot(bool value) { use_crows_foot = value; if(value) line_conn_mode=RelationshipView::ConnectTableEdges; } bool RelationshipView::isCrowsFoot(void) { return(use_crows_foot); } void RelationshipView::setLineConnectionMode(unsigned mode) { if(use_crows_foot) line_conn_mode=ConnectTableEdges; else { if(mode > ConnectTableEdges) mode=ConnectTableEdges; line_conn_mode=mode; } } unsigned RelationshipView::getLineConnectinMode(void) { return(line_conn_mode); } QPointF RelationshipView::getConnectionPoint(unsigned table_idx) { if(table_idx > 2) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(conn_points[table_idx]); } BaseRelationship *RelationshipView::getUnderlyingObject(void) { return(dynamic_cast(this->BaseObjectView::getUnderlyingObject())); } TextboxView *RelationshipView::getLabel(unsigned lab_idx) { if(lab_idx > BaseRelationship::RelNameLabel) return(nullptr); else return(labels[lab_idx]); } QVariant RelationshipView::itemChange(GraphicsItemChange change, const QVariant &value) { if(change==ItemPositionChange) { this->setFlag(QGraphicsItem::ItemIsMovable, false); } else if(change==ItemSelectedHasChanged) { unsigned i, count; QPen pen; QColor color, line_color=this->getUnderlyingObject()->getCustomColor(); vector rel_lines; this->setSelectionOrder(value.toBool()); pos_info_item->setVisible(value.toBool()); obj_selection->setVisible(value.toBool() && descriptor->isVisible()); this->configurePositionInfo(); for(i=0; i < 3; i++) { if(labels[i]) labels[i]->itemChange(change, value); } //Show tha graphical points if 'value' is true count=graph_points.size(); for(i=0; i < count; i++) graph_points[i]->setVisible(value.toBool()); //Alter the relationship line color when it is selected if(line_color==Qt::transparent) line_color=BaseObjectView::getBorderStyle(Attributes::Relationship).color(); if(value.toBool()) { QColor cor1=BaseObjectView::getBorderStyle(Attributes::ObjSelection).color(), cor2=line_color; color.setRedF((cor1.redF() + cor2.greenF())/2.0); color.setGreenF((cor1.greenF() + cor2.greenF())/2.0); color.setBlueF((cor1.blueF() + cor2.blueF())/2.0); color.setAlphaF((cor1.alphaF() + cor2.alphaF())/2.0); } else color=line_color; color.setAlpha(255); rel_lines=lines; rel_lines.insert(rel_lines.end(), fk_lines.begin(), fk_lines.end()); rel_lines.insert(rel_lines.end(), pk_lines.begin(), pk_lines.end()); for(auto &lin : rel_lines) { pen=lin->pen(); pen.setColor(color); lin->setPen(pen); } for(auto &curve : curves) { pen = curve->pen(); pen.setColor(color); curve->setPen(pen); } //If the crow's foot descriptors are allocated we change their border color if(cf_descriptors[0] != nullptr) { vector lines; QVector grad_stops = descriptor->brush().gradient()->stops(); QColor sel_color = BaseObjectView::getBorderStyle(Attributes::ObjSelection).color(); QLinearGradient grad(QPointF(0,0),QPointF(0,1)); int color_id = 0; grad.setCoordinateMode(QGradient::ObjectBoundingMode); lines.assign(src_cf_lines.begin(), src_cf_lines.end()); lines.insert(lines.end(), dst_cf_lines.begin(), dst_cf_lines.end()); for(auto &line : lines) line->setPen(pen); for(int idx = 0; idx < 2; idx++) { /* If we have a circle that describes optional cardinality we should * merge its color with the object selection color in order to simulate the * that the descriptor is selected as well */ if(value.toBool()) { color_id = 0; for(auto &stop : grad_stops) { color = stop.second; color.setRedF((color.redF() + sel_color.greenF())/2.0); color.setGreenF((color.greenF() + sel_color.greenF())/2.0); color.setBlueF((color.blueF() + sel_color.blueF())/2.0); grad.setColorAt(color_id++, color); } round_cf_descriptors[idx]->setBrush(grad); } else round_cf_descriptors[idx]->setBrush(descriptor->brush()); if(this->getUnderlyingObject()->getRelationshipType() == BaseRelationship::RelationshipFk) pen.setStyle(Qt::DashLine); round_cf_descriptors[idx]->setPen(pen); } } //Shows/hides the attribute's selection count=attributes.size(); for(i=0; i < count; i++) attributes[i]->childItems().at(3)->setVisible(value.toBool()); emit s_objectSelected(dynamic_cast(this->getUnderlyingObject()), value.toBool()); } return(value); } void RelationshipView::mousePressEvent(QGraphicsSceneMouseEvent *event) { //Marks the flag ItemIsMovable in order to permit the relationship to be selected this->setFlag(QGraphicsItem::ItemIsMovable); BaseObjectView::mousePressEvent(event); this->setFlag(QGraphicsItem::ItemIsMovable, false); if(!this->getUnderlyingObject()->isProtected()) { BaseRelationship *base_rel=this->getUnderlyingObject(); //Resets the labels position when mid-button is pressed if(event->buttons()==Qt::LeftButton && event->modifiers()==(Qt::AltModifier | Qt::ShiftModifier)) { base_rel->resetLabelsDistance(); this->configureLabels(); } else if(event->modifiers()==Qt::ShiftModifier) { QLineF lin; QPointF p; QRectF rect; unsigned i, count; bool pnt_rem=false; vector points=base_rel->getPoints(); if(!base_rel->isSelfRelationship()) { //When the user press SHIFT and clicks on a point this is removed if(event->buttons()==Qt::LeftButton) { emit s_relationshipModified(base_rel); count=graph_points.size(); for(i=0; i < count; i++) { //Calculating the graphical point rect rect.setTopLeft(graph_points[i]->pos()); rect.setSize(graph_points[i]->boundingRect().size()); //Case the mouse pos is inside the point rect if(rect.contains(event->pos())) { points.erase(points.begin()+i); base_rel->setPoints(points); this->configureLine(); pnt_rem=true; break; } } //Create a point when the user press SHIFT and clicks the line count=lines.size(); for(i=0; i < count && !pnt_rem; i++) { /* Creates a auxiliary line based upon the cursor position. This * line is used to calculate the exact point (intersection) where the new one * must be inserted */ lin.setP1(QPointF(event->pos().x() - 50, event->pos().y() - 50)); lin.setP2(QPointF(event->pos().x() + 50, event->pos().y() + 50)); //Case the auxiliary line intercepts one relationship line if((!use_curved_lines && lines[i]->line().intersect(lin, &p) == QLineF::BoundedIntersection) || (use_curved_lines && curves[i]->contains(event->pos()))) { //Inserts the point to the line if(i >= points.size()) points.push_back(event->pos()); else points.insert(points.begin() + i, event->pos()); base_rel->setPoints(points); this->configureLine(); break; } } } } } //Clicking only with the left button, checks if some child object can be selected else if(event->button()==Qt::LeftButton) { QRectF rect; unsigned count, i; //Checks if there is some point selected count=graph_points.size(); for(i=0; i < count && !sel_object; i++) { rect.setTopLeft(graph_points[i]->pos()); rect.setSize(graph_points[i]->boundingRect().size()); if(rect.contains(event->pos())) { sel_object=graph_points[i]; sel_object_idx=i; } } //Checks if there is some label selected for(i=0; i < 3 && !sel_object; i++) { if(labels[i]) { rect.setTopLeft(labels[i]->pos()); rect.setSize(labels[i]->boundingRect().size()); if(rect.contains(event->pos())) { sel_object=labels[i]; sel_object_idx=i; } } } } } } void RelationshipView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if(this->isSelected() && event->buttons()==Qt::LeftButton && !this->getUnderlyingObject()->isProtected()) { if(dynamic_cast(sel_object)) { QRectF brect = QRectF(tables[0]->pos() - QPointF(20,20), tables[0]->pos() + QPointF(tables[0]->boundingRect().width() + 20, tables[0]->boundingRect().height() + 20)), brect1 = QRectF(tables[1]->pos() - QPointF(20,20), tables[1]->pos() + QPointF(tables[1]->boundingRect().width() + 20, tables[1]->boundingRect().height() + 20)); //We only include the point if it is not inside the tables' bounding rect if(!brect.contains(event->pos()) && !brect1.contains(event->pos())) { BaseRelationship *rel_base=this->getUnderlyingObject(); vector points=rel_base->getPoints(); points[sel_object_idx]=event->pos(); rel_base->setPoints(points); this->configureLine(); } } else if(dynamic_cast(sel_object)) sel_object->setPos(event->pos()); } BaseObjectView::mouseMoveEvent(event); } void RelationshipView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { BaseRelationship *base_rel=this->getUnderlyingObject(); if(event->button()==Qt::LeftButton) { if(dynamic_cast(sel_object)) { //Calculates the displacement of the label from the initial pos to the current base_rel->setLabelDistance(sel_object_idx, QPointF(sel_object->pos() - labels_ini_pos[sel_object_idx])); } sel_object_idx=-1; sel_object=nullptr; } BaseObjectView::mouseReleaseEvent(event); } void RelationshipView::disconnectTables(void) { if(tables[0] && tables[1]) { BaseRelationship *rel_base=this->getUnderlyingObject(); tables[0]->removeConnectedRelationship(rel_base); if(!rel_base->isSelfRelationship()) tables[1]->removeConnectedRelationship(rel_base); for(unsigned i=0; i < 2; i++) { tables[i]->disconnect(this); tables[i]=nullptr; } } } void RelationshipView::connectTables(void) { if(tables[0] && tables[1]) { for(unsigned i=0; i < 2; i++) { tables[i]->disconnect(this); if(BaseObjectView::isPlaceholderEnabled()) connect(tables[i], SIGNAL(s_relUpdateRequest(void)), this, SLOT(configureLine(void))); else connect(tables[i], SIGNAL(s_objectMoved(void)), this, SLOT(configureLine(void))); connect(tables[i], SIGNAL(s_objectDimensionChanged(void)), this, SLOT(configureLine(void))); } } } void RelationshipView::configureObject(void) { BaseRelationship *rel_base=this->getUnderlyingObject(); tables[0]=dynamic_cast(rel_base->getTable(BaseRelationship::SrcTable)->getOverlyingObject()); tables[1]=dynamic_cast(rel_base->getTable(BaseRelationship::DstTable)->getOverlyingObject()); tables[0]->addConnectedRelationship(rel_base); if(!rel_base->isSelfRelationship()) tables[1]->addConnectedRelationship(rel_base); configureLine(); connectTables(); connect(rel_base, SIGNAL(s_objectModified()), this, SLOT(configureLine(void))); } void RelationshipView::configurePositionInfo(void) { if(this->isSelected()) { BaseObjectView::configurePositionInfo(descriptor->pos()); pos_info_item->setPos(descriptor->pos().x(), descriptor->pos().y() - pos_info_item->boundingRect().height()); } } void RelationshipView::configureLine(void) { //Reconnect the tables is the placeholder usage changes if(using_placeholders!=BaseObjectView::isPlaceholderEnabled()) { connectTables(); using_placeholders=BaseObjectView::isPlaceholderEnabled(); } if(!configuring_line) { BaseRelationship *base_rel=this->getUnderlyingObject(); Relationship *rel=dynamic_cast(base_rel); vector points, fk_points, pk_points; QGraphicsLineItem *lin=nullptr; QPointF pos, p_int, p_central[2], pk_pnt, fk_pnt; QRectF rect; QPen pen; QGraphicsPolygonItem *pol=nullptr; QPolygonF pol_aux; QString tool_tip; QGraphicsItem *item=nullptr; int i, i1, count, idx_lin_desc=0; bool conn_same_sides = false, conn_horiz_sides[2] = { false, false }, conn_vert_sides[2] = { false, false }; unsigned rel_type = base_rel->getRelationshipType(); configuring_line=true; pen.setCapStyle(Qt::RoundCap); if(base_rel->isSelfRelationship()) { double fnt_factor=font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize, pos_factor = 0, offset = 0; unsigned rel_cnt = tables[0]->getConnectedRelsCount(base_rel->getTable(BaseRelationship::SrcTable), base_rel->getTable(BaseRelationship::DstTable)); /* Sefl-relationshihp line format: +----<> | | ---------- | | Table |---+ ---------- This line cannot be moved or have points added */ pos=tables[0]->pos(); rect=tables[0]->boundingRect(); if(rel_cnt > 1) { int idx = tables[0]->getConnectedRelationshipIndex(base_rel, true); double min_val = min(rect.width(), rect.height()); if(idx < 0) idx =0; pos_factor = min_val * 0.08 * idx; } p_central[0].setX(pos.x() + rect.width()); p_central[0].setY(pos.y() + (rect.height() / 3.0) + pos_factor); p_central[1].setX(pos.x() + (rect.width() / 1.5) - pos_factor); p_central[1].setY(pos.y()); if(p_central[0].y() > pos.y() + rect.height()) p_central[0].setY(pos.y() + rect.height()); if(p_central[1].x() < pos.x()) p_central[1].setX(pos.x()); offset = use_crows_foot ? 23 : 11; points.push_back(QPointF(p_central[0].x() + (offset * fnt_factor) + pos_factor, p_central[0].y())); points.push_back(QPointF(p_central[0].x() + (offset * fnt_factor) + pos_factor, p_central[1].y() - (offset * fnt_factor) - pos_factor)); points.push_back(QPointF(p_central[1].x(), p_central[1].y() - (offset * fnt_factor) - pos_factor)); base_rel->setPoints(points); } else { Relationship *rel=dynamic_cast(base_rel); bool rel_1n= (rel_type==Relationship::Relationship11 || rel_type==Relationship::Relationship1n || rel_type==Relationship::RelationshipFk); if(rel && rel->getRelationshipType()==Relationship::Relationship11 && rel->isIdentifier()) { tables[0]=dynamic_cast(rel->getReferenceTable()->getOverlyingObject()); tables[1]=dynamic_cast(rel->getReceiverTable()->getOverlyingObject()); } if(line_conn_mode==ConnectCenterPoints || line_conn_mode==ConnectTableEdges || !rel_1n) { vector *> ref_lines={ &fk_lines, &pk_lines }; for(i=0; i < 2; i++) p_central[i]=tables[i]->getCenter(); //Destroying the fk and pk connection lines when the line mode changes for(i=0; i < 2; i++) { while(!ref_lines[i]->empty()) { item=ref_lines[i]->back(); ref_lines[i]->pop_back(); this->removeFromGroup(item); delete(item); } } } else if(line_conn_mode==ConnectFkToPk && rel_1n) { QPointF pnt; QRectF rec_tab_rect, ref_tab_rect; double fk_py=0, pk_py=0, fk_px=0, pk_px=0; vector fks; Table *ref_tab=nullptr, *rec_tab=nullptr; TableView *ref_tab_view=nullptr, *rec_tab_view=nullptr; unsigned cnt=0, i=0, pk_pnt_type=0, fk_pnt_type=0; if(!rel) { ref_tab=dynamic_cast(base_rel->getTable(BaseRelationship::DstTable)); rec_tab=dynamic_cast
(base_rel->getTable(BaseRelationship::SrcTable)); } else { ref_tab=dynamic_cast
(rel->getReferenceTable()); rec_tab=dynamic_cast
(rel->getReceiverTable()); } rec_tab->getForeignKeys(fks, true, ref_tab); ref_tab_view=dynamic_cast(ref_tab->getOverlyingObject()); rec_tab_view=dynamic_cast(rec_tab->getOverlyingObject()); //Create the table's rectangles to detect where to connect the relationship ref_tab_rect=QRectF(ref_tab_view->pos(), ref_tab_view->boundingRect().size()); //In this case the receiver table rect Y must be equal to reference table Y in order to do the correct comparison rec_tab_rect=QRectF(QPointF(rec_tab_view->pos().x(), ref_tab_view->pos().y()), rec_tab_view->boundingRect().size()); if(ref_tab_rect.intersects(rec_tab_rect)) { //Connects the rectangle at the same sides on both tables conn_same_sides = true; if(rec_tab_rect.center().x() >= ref_tab_rect.center().x()) pk_pnt_type=fk_pnt_type=BaseTableView::LeftConnPoint; else if(rec_tab_rect.center().x() < ref_tab_rect.center().x()) pk_pnt_type=fk_pnt_type=BaseTableView::RightConnPoint; } else { //Connecting the relationship on the opposite sides depending on the tables' position if(ref_tab_rect.right() <= rec_tab_rect.left()) { pk_pnt_type=BaseTableView::RightConnPoint; fk_pnt_type=BaseTableView::LeftConnPoint; } else { pk_pnt_type=BaseTableView::LeftConnPoint; fk_pnt_type=BaseTableView::RightConnPoint; } } for(auto &constr : fks) { cnt=constr->getColumnCount(Constraint::SourceCols); for(i=0; i < cnt; i++) { pnt=rec_tab_view->getConnectionPoints(constr->getColumn(i, Constraint::SourceCols), fk_pnt_type); fk_py+=pnt.y(); fk_px=pnt.x(); fk_points.push_back(this->mapFromItem(rec_tab_view, pnt)); pnt=ref_tab_view->getConnectionPoints(constr->getColumn(i, Constraint::ReferencedCols), pk_pnt_type); pk_py+=pnt.y(); pk_px=pnt.x(); pk_points.push_back(this->mapFromItem(ref_tab_view, pnt)); } } if(!fks.empty()) { double pk_dx=(pk_pnt_type==BaseTableView::LeftConnPoint ? -ConnLineLength : ConnLineLength), fk_dx=(fk_pnt_type==BaseTableView::LeftConnPoint ? -ConnLineLength : ConnLineLength); pk_pnt=this->mapFromItem(ref_tab_view, QPointF(pk_px + pk_dx, pk_py/pk_points.size())); fk_pnt=this->mapFromItem(rec_tab_view, QPointF(fk_px + fk_dx, fk_py/fk_points.size())); if(rel_type==Relationship::RelationshipFk) { p_central[1]=pk_pnt; p_central[0]=fk_pnt; } else { p_central[0]=pk_pnt; p_central[1]=fk_pnt; } } else { /* Fallback configuration: If no fk was found in the receiver table uses * the tables' center points to configure the line in order to avoid glitched lines. * This situation may happen when the relationship is being validated and the needed fks was not * created yet. In a second interaction of the rel. validation they are created * and the relationship is properly configured */ if(rel_type==Relationship::RelationshipFk) { p_central[1]=pk_pnt=ref_tab_view->getCenter(); p_central[0]=fk_pnt=rec_tab_view->getCenter(); } else { p_central[0]=pk_pnt=ref_tab_view->getCenter(); p_central[1]=fk_pnt=rec_tab_view->getCenter(); } } } points=base_rel->getPoints(); count=points.size(); pol_aux.append(QPointF(0,0)); pol_aux.append(QPointF(6,0)); pol_aux.append(QPointF(6,6)); pol_aux.append(QPointF(0,6)); for(i=0; i < count; i++) { if(i >= static_cast(graph_points.size())) { pol=new QGraphicsPolygonItem; graph_points.push_back(pol); pol->setZValue(0); pol->setPolygon(pol_aux); pol->setBrush(BaseObjectView::getFillStyle(Attributes::ObjSelection)); pol->setPen(BaseObjectView::getBorderStyle(Attributes::ObjSelection)); this->addToGroup(pol); } else pol=graph_points[i]; pol->setPos(points[i]); pol->moveBy(-GraphicPointRadius/2, -GraphicPointRadius/2); pol->setVisible(this->isSelected()); } //Destroy the graphical points not used i=graph_points.size()-1; while(i > count-1) { item=graph_points.back(); graph_points.pop_back(); this->removeFromGroup(item); delete(item); i--; } } if(base_rel->isSelfRelationship() || line_conn_mode != ConnectTableEdges) { conn_points[0]=p_central[0]; conn_points[1]=p_central[1]; points.insert(points.begin(),p_central[0]); points.push_back(p_central[1]); } else if(line_conn_mode == ConnectTableEdges) { QRectF brect; QPolygonF pol; QLineF edge, line = QLineF(tables[0]->getCenter(), tables[1]->getCenter()); QPointF pi, center, p_aux[2]; double font_factor=(font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize) * BaseObjectView::getScreenDpiFactor(), size_factor = 1, border_factor = ConnLineLength * 0.30, min_lim = 0, max_lim = 0, conn_rels_factors[2] = { 0, 0 }; unsigned conn_rels_cnt[2] = { 0, 0 }; for(int tab_idx = 0; tab_idx < 2; tab_idx++) { conn_rels_cnt[tab_idx] = tables[tab_idx]->getConnectedRelsCount(base_rel->getTable(BaseRelationship::SrcTable), base_rel->getTable(BaseRelationship::DstTable)); conn_rels_factors[tab_idx] = conn_rels_cnt[tab_idx] == 1 ? 1 : 0.08 * (tables[tab_idx]->getConnectedRelationshipIndex(base_rel)); if(!points.empty()) { if(tab_idx == 0) line = QLineF(tables[0]->getCenter(), points[0]); else line = QLineF(tables[1]->getCenter(), points[points.size() - 1]); } if(rel_type==BaseRelationship::RelationshipGen || rel_type==BaseRelationship::RelationshipDep || rel_type==BaseRelationship::RelationshipPart) size_factor = 0.40; else if(use_crows_foot) { if(rel_type==BaseRelationship::RelationshipNn || (tab_idx == 1 && rel_type==BaseRelationship::RelationshipFk) || (tab_idx == 0 && rel_type==BaseRelationship::Relationship1n && base_rel->isTableMandatory(BaseRelationship::SrcTable)) || (tab_idx == 0 && rel_type==BaseRelationship::Relationship11 && base_rel->isTableMandatory(BaseRelationship::SrcTable)) || (tab_idx == 1 && rel_type==BaseRelationship::Relationship11 && base_rel->isTableMandatory(BaseRelationship::DstTable))) size_factor = 1 * font_factor; else size_factor = 1.5 * font_factor; if(rel_type == BaseRelationship::RelationshipPart || rel_type == BaseRelationship::RelationshipGen || rel_type == BaseRelationship::RelationshipDep || rel_type == BaseRelationship::Relationship11 || (tab_idx == 0 && rel_type == BaseRelationship::Relationship1n) || (tab_idx == 1 && rel_type == BaseRelationship::RelationshipFk)) border_factor = ConnLineLength * 0.30; else border_factor = ConnLineLength * 0.75; } else size_factor = 0.65 * font_factor; brect = QRectF(tables[tab_idx]->pos(), tables[tab_idx]->boundingRect().size()); pol = QPolygonF(brect); center = tables[tab_idx]->getCenter(); for(int idx = 0; idx < pol.size() - 1; idx++) { edge.setP1(pol.at(idx)); edge.setP2(pol.at(idx + 1)); if(line.intersect(edge, &pi)==QLineF::BoundedIntersection) { /* Adjusting the intersection point if there're more than one relationship connected the current table * this will cause all relationships to be aligned together */ if(conn_rels_cnt[tab_idx] > 1) { double max_dim = max(brect.height(), brect.width()); int signal = 0; if(edge.dx() == 0) { signal = edge.dy()/fabs(edge.dy()) * (tab_idx == 0 ? 1 : -1); pi.setY(pi.y() - (conn_rels_factors[tab_idx] * max_dim) * signal); // Adjusting the position of the interesection point to make is as close to the center of the edge as possible pi.setY(pi.y() + (max_dim * 0.05) * signal); } if(edge.dy() == 0) { signal = edge.dx()/fabs(edge.dx()) * (tab_idx == 0 ? 1 : -1); pi.setX(pi.x() - (conn_rels_factors[tab_idx] * max_dim) * signal); // Adjusting the position of the interesection point to make is as close to the center of the edge as possible pi.setX(pi.x() + (max_dim * 0.05) * signal); } } //Avoiding the line to be exposed in the rounded corners of the tables if(edge.dx() == 0) { min_lim = brect.top() + border_factor; max_lim = brect.bottom() - border_factor; if(pi.y() < min_lim) pi.setY(min_lim); else if(pi.y() > max_lim) pi.setY(max_lim); } else { min_lim = brect.left() + border_factor; max_lim = brect.right() - border_factor; if(pi.x() < min_lim) pi.setX(min_lim); else if(pi.x() > max_lim) pi.setX(max_lim); } conn_points[tab_idx] = p_central[tab_idx] = pi; if(edge.dx() == 0) { if(pi.x() < center.x()) pi.setX(pi.x() - ConnLineLength * size_factor); else pi.setX(pi.x() + ConnLineLength * size_factor); conn_vert_sides[tab_idx] = true; } else { if(pi.y() < center.y()) pi.setY(pi.y() - ConnLineLength * size_factor); else pi.setY(pi.y() + ConnLineLength * size_factor); conn_horiz_sides[tab_idx] = true; } p_aux[tab_idx] = pi; break; } else { p_aux[tab_idx] = p_central[tab_idx]; } } } points.insert(points.begin(), p_central[0]); points.insert(points.begin() + 1, p_aux[0]); points.push_back(p_aux[1]); points.push_back(p_central[1]); } //If the relationship is selected we do not change the lines colors if(this->isSelected() && !lines.empty()) pen = lines[0]->pen(); else { //Configuring the relationship line color if(base_rel->getCustomColor()!=Qt::transparent) //Using custom color pen.setColor(base_rel->getCustomColor()); else //Using the default color pen=BaseObjectView::getBorderStyle(Attributes::Relationship); } //For dependency/partition relationships the line is dashed if(rel_type==BaseRelationship::RelationshipDep || rel_type == BaseRelationship::RelationshipPart) pen.setStyle(Qt::DashLine); /* For identifier relationships an additional point is created on the center of the line that supports the descriptor in order to modify the line thickness on the weak entity side */ if(rel && rel->isIdentifier()) { //Calculates the index of the initial point, on the line that supports the descriptor idx_lin_desc=(points.size()/2); p_central[0]=points[idx_lin_desc]; //Gets the second line point if(idx_lin_desc + 1 > static_cast(points.size())) p_central[1]=points[idx_lin_desc+1]; else p_central[1]=points[idx_lin_desc-1]; //Calculates the middle point and inserts it on the point vector p_int.setX((p_central[0].x() + p_central[1].x())/2.0); p_int.setY((p_central[0].y() + p_central[1].y())/2.0); points.insert(points.begin() + idx_lin_desc, p_int); } if(line_conn_mode==ConnectFkToPk) { vector ref_points={ fk_pnt, pk_pnt }; vector *> ref_pnt_vects={ &fk_points, &pk_points }; vector *> ref_lines={ &fk_lines, &pk_lines }; vector *ref_pnt=nullptr; vector *ref_lin=nullptr; for(unsigned vet_idx=0; vet_idx < 2; vet_idx++) { ref_pnt=ref_pnt_vects[vet_idx]; ref_lin=ref_lines[vet_idx]; count=ref_pnt->size(); for(i=0; i < count; i++) { if(i >= static_cast(ref_lin->size())) { lin=new QGraphicsLineItem; lin->setZValue(-1); ref_lin->push_back(lin); this->addToGroup(lin); } else lin=ref_lin->at(i); //If the relationship is identifier or bidirectional, the line has its thickness modified if(rel && (rel->isIdentifier() && vet_idx==0)) pen.setWidthF(ObjectBorderWidth * 1.90); else pen.setWidthF(ObjectBorderWidth * 1.45); lin->setLine(QLineF(ref_pnt->at(i), ref_points[vet_idx])); lin->setPen(pen); } //Destroy the unused pk or fk lines i=ref_lin->size()-1; while(i > static_cast(count-1)) { item=ref_lin->back(); ref_lin->pop_back(); this->removeFromGroup(item); delete(item); i--; } } } //Create the relationship lines count=points.size(); for(i=0; i < count-1; i++) { if(i >= static_cast(lines.size())) { lin=new QGraphicsLineItem; lin->setZValue(-1); lines.push_back(lin); this->addToGroup(lin); } else lin=lines[i]; //If the relationship is identifier or bidirectional, the line has its thickness modified if(rel && (rel->isIdentifier() && i >= idx_lin_desc)) pen.setWidthF(ObjectBorderWidth * 1.90); else pen.setWidthF(ObjectBorderWidth * 1.45); lin->setLine(QLineF(points[i], points[i+1])); lin->setPen(pen); } //Removing unused lines if(!base_rel->isSelfRelationship()) { i=points.size()-1; i1=lines.size(); while(i1 > i) { item=lines.back(); lines.pop_back(); this->removeFromGroup(item); delete(item); i1--; } } //Exposing the line ending circles if((!base_rel->isSelfRelationship() && line_conn_mode==ConnectCenterPoints && !use_crows_foot) || (!base_rel->isSelfRelationship() && ((line_conn_mode != ConnectTableEdges && rel_type==BaseRelationship::RelationshipDep) || (line_conn_mode != ConnectTableEdges && rel_type==BaseRelationship::RelationshipGen) || (line_conn_mode != ConnectTableEdges && rel_type==BaseRelationship::RelationshipPart) || (line_conn_mode != ConnectTableEdges && rel_type==BaseRelationship::RelationshipNn && !use_crows_foot)))) { for(i=0; i < 2; i++) { line_circles[i]->setVisible(true); line_circles[i]->setPen(pen); line_circles[i]->setBrush(pen.color()); line_circles[i]->setPos(p_central[i]-QPointF(GraphicPointRadius/2, GraphicPointRadius/2)); } } else { line_circles[0]->setVisible(false); line_circles[1]->setVisible(false); } //Using bezier curves instead of straight lines to denote the relationship line if(use_curved_lines && !base_rel->isSelfRelationship()) { BezierCurveItem * curve = nullptr; bool invert_cpoints = false, simple_curve = false; i = 0; for(auto &line : lines) { if(i >= static_cast(curves.size())) { curve = new BezierCurveItem; curve->setZValue(line->zValue()); this->addToGroup(curve); curves.push_back(curve); } else curve = curves[i]; i++; /* Creates simple a curved line in the following situations: * 1) The crow's foot is not enabled but the relationship connects in the same sides on tables (conn_same_sides) * 2) The crow's foot is enabled and one of the connection point is not in the horizontal edges of one of the tables (conn_horiz_sides) */ /* We invert the curve's bounding rect when crow's foot is enabled and the relationship connects * at the top/bottom edges of both tables */ simple_curve = (conn_same_sides && lines.size() == 1) || (conn_horiz_sides[0] != conn_horiz_sides[1] && lines.size() == 3); if(!simple_curve) invert_cpoints = (conn_horiz_sides[0] && conn_horiz_sides[1] && lines.size() == 3); else invert_cpoints = (!conn_horiz_sides[0] && conn_horiz_sides[1] && conn_vert_sides[0] && !conn_vert_sides[1]); curve->setLine(line->line(), simple_curve, invert_cpoints); curve->setPen(line->pen()); line->setVisible(false); } //Removing unused curves i=lines.size(); i1=curves.size(); while(i1 > i) { curve=curves.back(); curves.pop_back(); this->removeFromGroup(curve); delete(curve); i1--; } } else if(!use_curved_lines && !lines.empty() && !curves.empty()) { BezierCurveItem *curve = nullptr; for(auto &line : lines) line->setVisible(true); while(!curves.empty()) { curve=curves.back(); curves.pop_back(); this->removeFromGroup(curve); delete(curve); } } this->configureDescriptor(); this->configureCrowsFootDescriptors(); this->configureLabels(); this->configureProtectedIcon(); configuring_line=false; /* Making a little tweak on the foreign key type name. Despite being of class BaseRelationship, for semantics purposes shows the type of this relationship as "Relationship" unlike "Link" */ if(rel_type==BaseRelationship::RelationshipFk) tool_tip=base_rel->getName(true) + QString(" (") + BaseObject::getTypeName(ObjectType::Relationship) + QString(")"); else tool_tip=base_rel->getName(true) + QString(" (") + base_rel->getTypeName() + QString(")"); tool_tip += QString("\nId: %1\n").arg(base_rel->getObjectId()) + TableObjectView::ConstrDelimStart + QString(" %1 ").arg(base_rel->getRelationshipTypeName()) + TableObjectView::ConstrDelimEnd; if(!base_rel->getAlias().isEmpty()) tool_tip += QString("\nAlias: %1").arg(base_rel->getAlias()); this->setToolTip(tool_tip); for(i=0; i < 3; i++) { if(labels[i]) labels[i]->setToolTip(tool_tip); } descriptor->setToolTip(tool_tip); for(auto &curve : curves) curve->setToolTip(tool_tip); for(int i = 0; i < 2; i++) { if(cf_descriptors[i]) cf_descriptors[i]->setToolTip(tool_tip); if(round_cf_descriptors[i]) round_cf_descriptors[i]->setToolTip(tool_tip); } } } void RelationshipView::configureDescriptor(void) { QLineF lin; QPolygonF pol; BaseRelationship *base_rel=this->getUnderlyingObject(); Relationship *rel=dynamic_cast(base_rel); unsigned rel_type=base_rel->getRelationshipType(); double x, y, x1, y1, angle = 0, factor=(font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize) * BaseObjectView::getScreenDpiFactor(); QPen pen; QPointF pnt; vector points=base_rel->getPoints(); QColor line_color=base_rel->getCustomColor(); QGraphicsPolygonItem *pol_item=nullptr; //Configuring the relationship descriptor color if(base_rel->getCustomColor()!=Qt::transparent) //Using custom color pen.setColor(base_rel->getCustomColor()); else //Using the default color pen=BaseObjectView::getBorderStyle(Attributes::Relationship); if(rel_type==BaseRelationship::RelationshipDep || rel_type == BaseRelationship::RelationshipPart) pen.setStyle(Qt::DashLine); descriptor->setPen(pen); if(line_color!=Qt::transparent) { QColor colors[2]; QLinearGradient grad; BaseObjectView::getFillStyle(Attributes::Relationship, colors[0], colors[1]); for(unsigned i=0; i < 2; i++) { colors[i].setRed((colors[i].red() + line_color.red() + 255)/3); colors[i].setGreen((colors[i].green() + line_color.green() + 255)/3); colors[i].setBlue((colors[i].blue() + line_color.blue() + 255)/3); grad.setColorAt(i, colors[i]); } grad.setCoordinateMode(QGradient::ObjectBoundingMode); descriptor->setBrush(grad); } else descriptor->setBrush(BaseObjectView::getFillStyle(Attributes::Relationship)); if(rel_type==BaseRelationship::RelationshipDep || rel_type==BaseRelationship::RelationshipGen) { pol.append(QPointF(0,0)); pol.append(QPointF(18,10)); pol.append(QPointF(0,20)); pol.append(QPointF(0,10)); } else if(rel_type==BaseRelationship::RelationshipPart) { pol.append(QPointF(0,4)); pol.append(QPointF(4,0)); pol.append(QPointF(18,12)); pol.append(QPointF(4,24)); pol.append(QPointF(0,20)); pol.append(QPointF(10,12)); } else { pol.append(QPointF(11,0)); pol.append(QPointF(22,11)); pol.append(QPointF(11,22)); pol.append(QPointF(0,11)); } //Resizes the polygon according the font factor if(factor!=1.0) TextPolygonItem::resizePolygon(pol, pol.boundingRect().width() * factor , pol.boundingRect().height() * factor); if(base_rel->isSelfRelationship()) pnt=points.at(points.size()/2); else { if(!curves.empty()) { int idx = curves.size()/2; BezierCurveItem *curve = curves.at(idx); QPainterPath path = curve->path(); if(rel && rel->isIdentifier()) { BezierCurveItem *curve_aux = curves.at(idx - 1); QLineF lin_aux = QLineF(path.pointAtPercent(0.10), curve_aux->path().pointAtPercent(0.90)); angle = -lin_aux.angle(); pnt = path.pointAtPercent(0); } else { /* Workaround to avoid the inheritance / dependency relationship to get the descriptor rotated to the wrong side * We create and auxiliary line with points from the position at 65% of the curve to the 45% and use the * angle of that line instead of the angle at 50% of the curve */ if((rel_type == BaseRelationship::RelationshipDep || rel_type == BaseRelationship::RelationshipGen || rel_type == BaseRelationship::RelationshipPart) && curve->isControlPointsInverted() && !curve->isSimpleCurve() && !curve->isStraightLine()) { QLineF lin_aux = QLineF(path.pointAtPercent(0.65), path.pointAtPercent(0.45)); angle = -lin_aux.angle(); pnt = path.pointAtPercent(0.5); } else { double percent = path.percentAtLength(path.length()/2); angle = -path.angleAtPercent(percent); pnt = path.pointAtPercent(percent); } } } else { lin=lines.at(lines.size()/2)->line(); if(rel && rel->isIdentifier()) pnt=lin.p1(); else { pnt.setX((lin.p1().x() + lin.p2().x()) / 2.0); pnt.setY((lin.p1().y() + lin.p2().y()) / 2.0); } angle = -lin.angle(); } descriptor->setRotation(angle); obj_selection->setRotation(angle); obj_shadow->setRotation(angle); } x=x1=pnt.x() - (pol.boundingRect().width()/2.0); y=y1=pnt.y() - (pol.boundingRect().height()/2.0); protected_icon->setPos(x + ((pol.boundingRect().width()/2.0) * 0.60), y + ((pol.boundingRect().height()/2.0) * 0.55)); configureSQLDisabledInfo(); x1+=6 * HorizSpacing; y1-=3 * VertSpacing; sql_disabled_item->setPos(x1, y1); descriptor->setPolygon(pol); descriptor->setTransformOriginPoint(descriptor->boundingRect().center()); descriptor->setPos(x, y); pol_item=dynamic_cast(obj_selection); pol_item->setPolygon(pol); pol_item->setTransformOriginPoint(obj_selection->boundingRect().center()); pol_item->setPos(x,y); pol_item->setBrush(this->getFillStyle(Attributes::ObjSelection)); pol_item->setPen(this->getBorderStyle(Attributes::ObjSelection)); pol_item=dynamic_cast(obj_shadow); pol_item->setPolygon(pol); pol_item->setTransformOriginPoint(obj_shadow->boundingRect().center()); pol_item->setPos(x + 2.5, y + 3.5); pol_item->setPen(Qt::NoPen); pol_item->setBrush(QColor(50,50,50,60)); this->configureAttributes(); this->configurePositionInfo(); /* If the crow's feet is enabled the relationship descriptor is hidden * for 1:1, 1:n, n:n and fk relationship. For generalization, dependency and partitioning * relationships the descriptor is still displayed. */ descriptor->setVisible(!use_crows_foot || (use_crows_foot && ( rel_type == BaseRelationship::RelationshipDep || rel_type == BaseRelationship::RelationshipGen || rel_type == BaseRelationship::RelationshipPart))); obj_shadow->setVisible(descriptor->isVisible()); } void RelationshipView::configureCrowsFootDescriptors(void) { BaseRelationship * base_rel = dynamic_cast(this->getUnderlyingObject()); Relationship *rel=dynamic_cast(base_rel); //Hiding all descriptors related to crow's foot when the notation is not being used if(!use_crows_foot && cf_descriptors[BaseRelationship::SrcTable]) { for(unsigned tab_id = BaseRelationship::SrcTable; tab_id <= BaseRelationship::DstTable; tab_id++) { for(auto &item : cf_descriptors[tab_id]->childItems()) { cf_descriptors[tab_id]->setRotation(0); cf_descriptors[tab_id]->removeFromGroup(item); this->removeFromGroup(item); item->setVisible(false); cf_descriptors[tab_id]->setVisible(false); } } } else if(use_crows_foot && base_rel && (base_rel->getRelationshipType() == BaseRelationship::Relationship11 || base_rel->getRelationshipType() == BaseRelationship::Relationship1n || base_rel->getRelationshipType() == BaseRelationship::RelationshipNn || base_rel->getRelationshipType() == BaseRelationship::RelationshipFk)) { QGraphicsLineItem *line_item = nullptr; QGraphicsEllipseItem *circle_item = nullptr; unsigned rel_type = base_rel->getRelationshipType(); double factor=(font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize) * BaseObjectView::getScreenDpiFactor(); int signal = 1; BaseTableView *tables[2] = { nullptr, nullptr }; bool mandatory[2] = { false, false }; if(rel_type == BaseRelationship::RelationshipNn || rel_type == BaseRelationship::RelationshipFk) { tables[BaseRelationship::SrcTable] = dynamic_cast(base_rel->getTable(BaseRelationship::SrcTable)->getOverlyingObject()); tables[BaseRelationship::DstTable] = dynamic_cast(base_rel->getTable(BaseRelationship::DstTable)->getOverlyingObject()); mandatory[BaseRelationship::SrcTable] = base_rel->isTableMandatory(BaseRelationship::SrcTable); mandatory[BaseRelationship::DstTable] = base_rel->isTableMandatory(BaseRelationship::DstTable); } else { tables[BaseRelationship::SrcTable] = dynamic_cast(rel->getReferenceTable()->getOverlyingObject()); tables[BaseRelationship::DstTable] = dynamic_cast(rel->getReceiverTable()->getOverlyingObject()); mandatory[BaseRelationship::SrcTable] = rel->isReferenceTableMandatory(); mandatory[BaseRelationship::DstTable] = rel->isReceiverTableMandatory(); /* There's a special case for one-to-one relationships that will cause the crow's foot * descriptors to be positioned in the oposite sides when compared to other relationships. * This because pgModeler switches automatically the receiver table to be the destination one * when the mandatory table of the relationship is the destination. So we use and auxiliary (signal inverter) * variable to alter the descriptors position */ if(mandatory[BaseRelationship::SrcTable] && rel_type == BaseRelationship::Relationship11 && rel->getTable(BaseRelationship::DstTable) == rel->getReferenceTable()) signal = -1; } //Allocatting all objects related to the crow's foot descriptors if(cf_descriptors[BaseRelationship::SrcTable] == nullptr) { int src_zvalue = lines.front()->zValue() + 1, dst_zvalue = lines.back()->zValue() + 1; QGraphicsLineItem *line_item = nullptr; for(int idx = 0; idx < 2; idx++) { cf_descriptors[idx] = new QGraphicsItemGroup; round_cf_descriptors[idx] = new QGraphicsEllipseItem; this->addToGroup(cf_descriptors[idx]); } for(int idx = 0; idx < 4; idx++) { line_item = new QGraphicsLineItem; src_cf_lines.push_back(line_item); cf_descriptors[BaseRelationship::SrcTable]->setZValue(src_zvalue); line_item = new QGraphicsLineItem; dst_cf_lines.push_back(line_item); cf_descriptors[BaseRelationship::DstTable]->setZValue(dst_zvalue); } } else { cf_descriptors[BaseRelationship::SrcTable]->setVisible(true); cf_descriptors[BaseRelationship::DstTable]->setVisible(true); } QPointF pi; QRectF brect; QPen pen, pens[2] = { lines.front()->pen(), lines.back()->pen() }; QLineF line, line1, edge, rel_lines[2] = {(signal < 0 ? lines.back()->line() : lines.front()->line()), (signal < 0 ? lines.front()->line() : lines.back()->line())}; QPolygonF pol; vector *> cf_lines = { &src_cf_lines, &dst_cf_lines }; unsigned lin_idx = 0; double px = 0, py = 0, min_x = 0, max_x = 0, min_y = 0, max_y = 0; for(unsigned tab_id = BaseRelationship::SrcTable; tab_id <= BaseRelationship::DstTable; tab_id++) { cf_descriptors[tab_id]->setRotation(0); for(auto &line : *cf_lines[tab_id]) { cf_descriptors[tab_id]->removeFromGroup(line); this->removeFromGroup(line); line->setVisible(false); } //Configuring the minimum cardinality descriptor if((tab_id == BaseRelationship::SrcTable && rel_type != BaseRelationship::RelationshipNn && rel_type != BaseRelationship::RelationshipFk) || (tab_id == BaseRelationship::DstTable && (rel_type == BaseRelationship::Relationship11 || rel_type == BaseRelationship::RelationshipFk))) { line_item = cf_lines[tab_id]->at(lin_idx++); cf_descriptors[tab_id]->addToGroup(line_item); line_item->setVisible(true); line_item->setLine(QLineF(QPointF(0, -8 * factor), QPointF(0, 8 * factor))); line_item->setPos((10 * signal) * (tab_id == BaseRelationship::DstTable ? -1 : 1), 0); line_item->setPen(pens[tab_id]); } else { //Configuring the crow's foot descriptor if(tab_id == BaseRelationship::SrcTable) { px = 0; line = QLineF(QPointF(14, 0), QPointF(0, - 10 * factor)); line1 = QLineF(QPointF(14, 0), QPointF(0, 10 * factor)); } else { line = QLineF(QPointF(0, 0), QPointF(14, - 10 * factor)); line1 = QLineF(QPointF(0, 0), QPointF(14, 10 * factor)); px = -line.dx(); } line_item = cf_lines[tab_id]->at(lin_idx++); cf_descriptors[tab_id]->addToGroup(line_item); line_item->setVisible(true); line_item->setLine(line); line_item->setPos(px, 0); line_item->setPen(pens[tab_id]); line_item = cf_lines[tab_id]->at(lin_idx++); cf_descriptors[tab_id]->addToGroup(line_item); line_item->setVisible(true); line_item->setLine(line1); line_item->setPos(px, 0); line_item->setPen(pens[tab_id]); } cf_descriptors[tab_id]->removeFromGroup(round_cf_descriptors[tab_id]); this->removeFromGroup(round_cf_descriptors[tab_id]); round_cf_descriptors[tab_id]->setVisible(false); //Configuring the maximum cardinality descriptor if((tab_id == BaseRelationship::SrcTable && mandatory[tab_id]) || rel_type == BaseRelationship::RelationshipNn) { line_item = cf_lines[tab_id]->at(lin_idx++); cf_descriptors[tab_id]->addToGroup(line_item); line_item->setVisible(true); line_item->setLine(QLineF(QPointF(0, -8 * factor), QPointF(0, 8 * factor))); line_item->setPos(15 * signal * (tab_id == BaseRelationship::DstTable ? -1 : 1), 0); line_item->setPen(pens[tab_id]); } else if(!mandatory[tab_id] && ((rel_type != BaseRelationship::RelationshipFk) || (tab_id == BaseRelationship::SrcTable && rel_type == BaseRelationship::RelationshipFk))) { //Configuring the circle which describes the optional cardinality circle_item = round_cf_descriptors[tab_id]; cf_descriptors[tab_id]->addToGroup(circle_item); circle_item->setVisible(true); circle_item->setRect(QRectF(0, 0, GraphicPointRadius * 2.20 * factor, GraphicPointRadius * 2.20 * factor)); py = -(circle_item->boundingRect().height()/2.20); if(tab_id == BaseRelationship::SrcTable) { if(base_rel->isSelfRelationship() || rel_type != BaseRelationship::RelationshipNn) px = 15; else px = 11; } else { if(rel_type == BaseRelationship::Relationship11) { if(signal < 0) px = 15; else px = -13 - circle_item->boundingRect().width(); } else px = -15 - circle_item->boundingRect().width(); } pen = pens[tab_id]; if(rel_type == BaseRelationship::RelationshipFk) pen.setStyle(Qt::DashLine); circle_item->setPos(px, py); circle_item->setPen(pen); circle_item->setBrush(descriptor->brush()); } lin_idx = 0; brect = QRectF(tables[tab_id]->pos(), tables[tab_id]->boundingRect().size()); pol = QPolygonF(brect); /* Configuring the position of the descriptor based upon the intersection * point of the relationship line and the edge of the bounding rect of the table */ cf_descriptors[tab_id]->setRotation(-rel_lines[tab_id].angle()); for(int idx = 0; idx < pol.size() - 1; idx++) { edge.setP1(pol.at(idx)); edge.setP2(pol.at(idx + 1)); if(rel_lines[tab_id].intersect(edge, &pi)==QLineF::BoundedIntersection) { cf_descriptors[tab_id]->setPos(pi); break; } else { /* There some cases in which the intersection point can't be determined in BoundedIntersection mode * so as a fallback we check if one of the coordinates of the identified intersection point * is between one of the coordinates of the relationship line used in the operation. * * If it matches we'll use the use one of the extremes of the relationship line in the matching coordinate */ min_x = qMin(rel_lines[tab_id].p1().x(), rel_lines[tab_id].p2().x()); max_x = qMax(rel_lines[tab_id].p1().x(), rel_lines[tab_id].p2().x()); min_y = qMin(rel_lines[tab_id].p1().y(), rel_lines[tab_id].p2().y()); max_y = qMax(rel_lines[tab_id].p1().y(), rel_lines[tab_id].p2().y()); if(pi.x() >= min_x && pi.x() <= max_x) cf_descriptors[tab_id]->setPos(QPointF(pi.x(), (rel_lines[tab_id].dy() >= 0 ? max_y : min_y))); else if(pi.y() >= min_y && pi.y() <= max_y) cf_descriptors[tab_id]->setPos(QPointF((rel_lines[tab_id].dx() >= 0 ? max_x : min_x), pi.y())); } } } } } void RelationshipView::configureAttributes(void) { Relationship *rel=dynamic_cast(this->getUnderlyingObject()); if(rel) { int i, count; Column *col=nullptr; QGraphicsItemGroup *attrib=nullptr; QGraphicsLineItem *lin=nullptr; QGraphicsEllipseItem *desc=nullptr; QGraphicsPolygonItem *sel_attrib=nullptr; QGraphicsSimpleTextItem *text=nullptr; QGraphicsItemGroup *item=nullptr; QPointF p_aux; QTextCharFormat fmt; QFont font; QRectF rect; QPolygonF pol; double py, px, factor=font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize; fmt=font_config[Attributes::Attribute]; font=fmt.font(); font.setPointSizeF(font.pointSizeF() * 0.80); //Configures the rectangle used as base for creation of attribute descriptor rect.setTopLeft(QPointF(0,0)); rect.setSize(QSizeF(8 * factor, 8 * factor)); //Calculates the first attribute position based upon the attribute count and descriptor size count=rel->getAttributeCount(); px=descriptor->pos().x() + descriptor->boundingRect().width() + ((3 * HorizSpacing) * factor); py=descriptor->pos().y() - (count * rect.height()/(4.0 * factor)); for(i=0; i < count; i++) { col=rel->getAttribute(i); if(i >= static_cast(attributes.size())) { attrib=new QGraphicsItemGroup; attrib->setZValue(-1); //Creates the line that connects the attribute to the relationship descriptor lin=new QGraphicsLineItem; lin->setZValue(-1); attrib->addToGroup(lin); //Creates the attribute descriptor desc=new QGraphicsEllipseItem; desc->setZValue(0); attrib->addToGroup(desc); //Creates the attribute text text=new QGraphicsSimpleTextItem; text->setZValue(0); attrib->addToGroup(text); sel_attrib=new QGraphicsPolygonItem; sel_attrib->setZValue(1); sel_attrib->setVisible(false); attrib->addToGroup(sel_attrib); this->addToGroup(attrib); attributes.push_back(attrib); } else { attrib=attributes[i]; lin=dynamic_cast(attrib->childItems().at(0)); desc=dynamic_cast(attrib->childItems().at(1)); text=dynamic_cast(attrib->childItems().at(2)); sel_attrib=dynamic_cast(attrib->childItems().at(3)); } desc->setRect(rect); desc->setPen(BaseObjectView::getBorderStyle(Attributes::Attribute)); desc->setBrush(BaseObjectView::getFillStyle(Attributes::Attribute)); lin->setPen(descriptor->pen()); text->setBrush(fmt.foreground()); text->setFont(font); sel_attrib->setPen(BaseObjectView::getBorderStyle(Attributes::ObjSelection)); sel_attrib->setBrush(BaseObjectView::getFillStyle(Attributes::ObjSelection)); attrib->setPos(px, py); text->setText(compact_view && !col->getAlias().isEmpty() ? col->getAlias() : col->getName()); text->setPos(QPointF(desc->pos().x() + desc->boundingRect().width() + (HorizSpacing * factor), 0)); desc->setPos(0, VertSpacing * factor); pol.clear(); pol.append(text->boundingRect().topLeft()); pol.append(text->boundingRect().topRight() + QPointF(desc->boundingRect().width() + (HorizSpacing * factor), 0)); pol.append(text->boundingRect().bottomRight() + QPointF(desc->boundingRect().width() + (HorizSpacing * factor), 0)); pol.append(text->boundingRect().bottomLeft()); sel_attrib->setPolygon(pol); p_aux=this->mapToItem(attrib, descriptor->pos().x() + (descriptor->boundingRect().width()/2.0), descriptor->pos().y() + (descriptor->boundingRect().height()/2.0)); lin->setLine(QLineF(p_aux, desc->boundingRect().center())); py+=desc->boundingRect().height() + (2 * VertSpacing); } i=attributes.size()-1; while(i > count-1) { item=attributes.back(); attributes.pop_back(); this->removeFromGroup(item); delete(item); i--; } } } void RelationshipView::configureLabels(void) { double x=0,y=0; QPointF pnt; BaseRelationship *base_rel=this->getUnderlyingObject(); unsigned rel_type=base_rel->getRelationshipType(); QPointF label_dist; label_dist=base_rel->getLabelDistance(BaseRelationship::RelNameLabel); pnt=descriptor->pos(); x=pnt.x() - ((labels[BaseRelationship::RelNameLabel]->boundingRect().width() - descriptor->boundingRect().width())/2.0); if(base_rel->isSelfRelationship()) y=pnt.y() - labels[BaseRelationship::RelNameLabel]->boundingRect().height() - (2 * VertSpacing); else y=pnt.y() + descriptor->boundingRect().height() + VertSpacing; labels[BaseRelationship::RelNameLabel]->setVisible(!hide_name_label); configureLabelPosition(BaseRelationship::RelNameLabel, x, y); if(!hide_name_label) { Textbox *txtbox = dynamic_cast(labels[BaseRelationship::RelNameLabel]->getUnderlyingObject()); if(compact_view && !base_rel->getAlias().isEmpty()) { txtbox->setComment(base_rel->getAlias()); txtbox->setModified(true); } else if(txtbox->getComment() != base_rel->getName(true)) { txtbox->setComment(base_rel->getName(true)); txtbox->setModified(true); } } //Hides the cardinality labels when crow's feet is enabled if(labels[BaseRelationship::SrcCardLabel] && labels[BaseRelationship::DstCardLabel]) { labels[BaseRelationship::SrcCardLabel]->setVisible(!use_crows_foot); labels[BaseRelationship::DstCardLabel]->setVisible(!use_crows_foot); } if(!use_crows_foot && rel_type!=BaseRelationship::RelationshipGen && rel_type!=BaseRelationship::RelationshipDep && rel_type!=BaseRelationship::RelationshipPart) { QPointF pi, pf, p_int, pos; unsigned idx, i1; double dl, da, factor, v_space=VertSpacing * 2.5, h_space=HorizSpacing * 2.5; QLineF lins[2], borders[2][4]; QRectF tab_rect, rect; unsigned label_ids[2]={ BaseRelationship::SrcCardLabel, BaseRelationship::DstCardLabel }; if(!base_rel->isSelfRelationship() && line_conn_mode==ConnectFkToPk && rel_type!=BaseRelationship::RelationshipNn) { for(idx=0; idx < 2; idx++) { pos=conn_points[idx]; da=labels[idx]->boundingRect().height()/2.0; if((rel_type!=BaseRelationship::RelationshipFk && pos.x() < tables[idx]->pos().x()) || (rel_type==BaseRelationship::RelationshipFk && pos.x() >= tables[idx]->pos().x())) { factor=(rel_type==BaseRelationship::RelationshipFk ? 0.80 : 0.55); x=pos.x() - (labels[idx]->boundingRect().width() * factor); } else { factor=(rel_type==BaseRelationship::RelationshipFk ? 0.05 : 0.45); x=pos.x() - (labels[idx]->boundingRect().width() * factor); } configureLabelPosition(label_ids[idx], x, pos.y() - da); } } else { lins[0]=lines[0]->line(); lins[1]=lines[lines.size()-1]->line(); /* Creating lines that represents the tables border in order to calculate the position of the cardinality labels via intersection point */ for(idx=0; idx < 2; idx++) { rect=tables[idx]->boundingRect(); pos=tables[idx]->pos(); borders[idx][0].setPoints(pos, QPointF(pos.x(), pos.y() + rect.height())); borders[idx][1].setPoints(QPointF(pos.x(), pos.y() + rect.height()), QPointF(pos.x() + rect.width(), pos.y() + rect.height())); borders[idx][2].setPoints(QPointF(pos.x() + rect.width(), pos.y()), QPointF(pos.x() + rect.width(), pos.y() + rect.height())); borders[idx][3].setPoints(pos, QPointF(pos.x() + rect.width(), pos.y())); } for(idx=0; idx < 2; idx++) { for(i1=0; i1 < 4; i1++) { if(lins[idx].intersect(borders[idx][i1], &p_int)==QLineF::BoundedIntersection) { if(idx==0) lins[idx].setP1(p_int); else lins[idx].setP2(p_int); break; } } } for(idx=0; idx < 2; idx++) { if(idx==0) { pi=lins[idx].p1(); pf=lins[idx].p2(); } else { pi=lins[idx].p2(); pf=lins[idx].p1(); } dl=labels[label_ids[idx]]->boundingRect().width()/2.0; da=labels[label_ids[idx]]->boundingRect().height()/2.0; x=pi.x() - dl; y=pi.y() - da; tab_rect.setTopLeft(tables[idx]->pos()); tab_rect.setSize(tables[idx]->boundingRect().size()); rect.setTopLeft(QPointF(x,y)); rect.setSize(labels[idx]->boundingRect().size()); if(rect.contains(tab_rect.bottomRight())) { x+=dl + h_space; y+=da + v_space; } else if(rect.contains(tab_rect.bottomLeft())) { x-=dl + h_space; y+=da + v_space; } else if(rect.contains(tab_rect.topLeft())) { x-=dl + h_space; y-=da + v_space; } else if(rect.contains(tab_rect.topRight())) { x+=dl + h_space; y-=da + v_space; } else { if(tab_rect.contains(rect.bottomLeft()) && tab_rect.contains(rect.bottomRight())) y-=da + v_space; else if(tab_rect.contains(rect.topLeft()) && tab_rect.contains(rect.topRight())) y+=da + v_space; if(tab_rect.contains(rect.topRight()) && tab_rect.contains(rect.bottomRight())) x-=dl + h_space; else if(tab_rect.contains(rect.topLeft()) && tab_rect.contains(rect.bottomLeft())) x+=dl + h_space; } configureLabelPosition(label_ids[idx], x, y); } } } } void RelationshipView::configureLabelPosition(unsigned label_id, double x, double y) { if(label_id > BaseRelationship::RelNameLabel) throw Exception(ErrorCode::RefObjectInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(labels[label_id]) { BaseRelationship *base_rel=this->getUnderlyingObject(); QTextCharFormat char_fmt; QPointF label_dist; labels_ini_pos[label_id]=QPointF(x,y); label_dist=base_rel->getLabelDistance(label_id); if(!std::isnan(label_dist.x())) { x+=label_dist.x(); y+=label_dist.y(); } labels[label_id]->setPos(x,y); labels[label_id]->setToolTip(this->toolTip()); char_fmt=BaseObjectView::getFontStyle(Attributes::Label); char_fmt.setFontPointSize(char_fmt.fontPointSize() * 0.90); labels[label_id]->setFontStyle(char_fmt); labels[label_id]->setColorStyle(BaseObjectView::getFillStyle(Attributes::Label), BaseObjectView::getBorderStyle(Attributes::Label)); dynamic_cast(labels[label_id]->getUnderlyingObject())->setModified(true); } } QRectF RelationshipView::__boundingRect(void) { double x1=0, y1=0, x2=0, y2=0; unsigned i, count; QPointF p; QRectF rect; vector points=dynamic_cast(this->getUnderlyingObject())->getPoints(); //The reference size will be the relationship descriptor dimension x1=descriptor->pos().x(); y1=descriptor->pos().y(); x2=descriptor->pos().x() + descriptor->boundingRect().width(); y2=descriptor->pos().y() + descriptor->boundingRect().height(); //Checks if some point is out of reference dimension count=points.size(); for(i=0; i < count; i++) { p=points[i]; if(x1 > p.x()) x1=p.x() - GraphicPointRadius; if(y1 > p.y()) y1=p.y() - GraphicPointRadius; if(x2 < p.x()) x2=p.x() + GraphicPointRadius; if(y2 < p.y()) y2=p.y() + GraphicPointRadius; } //Checks if some label is out of reference dimension for(i=0; i < 3; i++) { if(labels[i] && labels[i]->isVisible()) { rect.setTopLeft(labels[i]->scenePos()); rect.setSize(labels[i]->boundingRect().size()); if(x1 > rect.left()) x1=rect.left(); if(y1 > rect.top()) y1=rect.top(); if(x2 < rect.right()) x2=rect.right(); if(y2 < rect.bottom()) y2=rect.bottom(); } } return(QRectF(x1, y1, x2, y2)); } pgmodeler-0.9.2/libobjrenderer/src/relationshipview.h000066400000000000000000000173151360462764600230510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class RelationshipView \brief Implements the graphical representation for relationships */ #ifndef RELATIONSHIP_VIEW_H #define RELATIONSHIP_VIEW_H #include "textboxview.h" #include "tableview.h" #include "relationship.h" #include "beziercurveitem.h" class RelationshipView: public BaseObjectView { private: Q_OBJECT //! \brief Graphical point radius static constexpr double GraphicPointRadius=6.0; //! \brief Length of the lines linked to fk/pk columns static constexpr double ConnLineLength=20.0; //! \brief Indicates that the relationship labels must be hidden static bool hide_name_label; //! \brief Indicates that the relationship lines should be curved static bool use_curved_lines; //! \brief Indicates that the relationship should be drawn in Crow's foot notation static bool use_crows_foot; /*! \brief Specify the type of connection used by the lines. The first (classical) is to connect the line to tables through their central points. The second (better semantics) makes the line start from the fk columns on receiver table and connecting to the pk columns on reference table */ static unsigned line_conn_mode; /*! \brief Indicate that the line is being configured/updated. This flag is used to evict that the configureLine() method is exceedingly called during the table moving. */ bool configuring_line, //! \brief Indicates if the instance is configured to use placeholders using_placeholders; //! \brief Stores the graphical representation for labels TextboxView *labels[3]; //! \brief Stores the graphical representation for the participant tables BaseTableView *tables[2]; /*! \brief Stores the points on tables where the relationship line is connected. This attribute is updated every time the configureLine() method is called. When the relationship uses the classical link mode (center points) this attribute contains the table's center points. Now, when the new line mode is used this attribute stores the middle point between the connection points of each table */ QPointF conn_points[2]; //! \brief Graphical representation for the user added points vector graph_points; //! \brief Lines that represent the relationship vector lines, //! \brief Lines that are connected to the reference table (only on CONNECT_FK_TO_PK mode) pk_lines, //! \brief Lines that are connected to the receiver table (only on CONNECT_FK_TO_PK mode) fk_lines; //! \brief Stores the graphical representation for relationship attributes vector attributes; //! \brief Relationship descriptor (lozenge -> (1,n)-(1,n) relationship, triangle -> inheritance) QGraphicsPolygonItem *descriptor; //! \brief Stores the current hovered child object QGraphicsItem *sel_object; //! \brief Stores the initial (default) labels position QPointF labels_ini_pos[3]; QGraphicsEllipseItem *line_circles[2]; //! \brief Stores the curved lines representing the relationship vector curves; //! \brief Stores the crow's foot notation descriptors QGraphicsItemGroup * cf_descriptors[2]; vector src_cf_lines, dst_cf_lines; QGraphicsEllipseItem *round_cf_descriptors[2]; //! \brief Stores the selected child object index int sel_object_idx; //! \brief Configures the labels positioning void configureLabels(void); //! \brief Configures the descriptor form and positioning void configureDescriptor(void); //! \brief Configures the crow's feet descriptors form and positioning void configureCrowsFootDescriptors(void); //! \brief Configures the attributes positioning void configureAttributes(void); //! \brief Configures the position info object void configurePositionInfo(void); //! \brief Configures the specified label's position based as well some styles for it void configureLabelPosition(unsigned label_id, double x, double y); protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value); void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *){} /*! \brief (Re)connects the tables to the relationship changing the signals captured. This method is called whenever the placeholder usage is toggled. If the placeholders are on the the table's signal s_relUpdateRequested() is used otherwise the s_objectMoved() is used */ void connectTables(void); //! \brief Disconnects the signal handled by the relationship which senders are the tables void disconnectTables(void); public slots: //! \brief Configures the relationship line void configureLine(void); //! \brief Returns the label through its index TextboxView *getLabel(unsigned lab_idx); private slots: //! \brief Makes the comple relationship configuration void configureObject(void); public: static constexpr unsigned ConnectCenterPoints=0, ConnectFkToPk=1, ConnectTableEdges=2; RelationshipView(BaseRelationship *rel); ~RelationshipView(void); //! \brief Calculates the relationship bounding rect considering all the children objects dimension QRectF __boundingRect(void); //! \brief Returns the relationship that generates the graphical representation BaseRelationship *getUnderlyingObject(void); //! \brief Hides the relationship's name label. This applies to all relationship instances static void setHideNameLabel(bool value); //! \brief Returns the current visibility state of name label static bool isNameLabelHidden(void); //! \brief Enables the usage of curved lines for all relationships static void setCurvedLines(bool value); //! \brief Returns the current state of curved lines usage static bool isCurvedLines(void); //! \brief Enables the usage of Crow's foot notation for all relationships static void setCrowsFoot(bool value); //! \brief Returns the current state of Crow's foot notation usage static bool isCrowsFoot(void); /*! \brief Configures the mode in which the lines are connected on tables. The first one is the CONNECT_CENTER_PNTS (the classical one) which connects the two tables through the center points. The CONNECT_FK_TO_PK is the one with a better semantics and connects the fk columns of receiver table to pk columns on reference table */ static void setLineConnectionMode(unsigned mode); //! \brief Returns the line connection mode used for the relationships static unsigned getLineConnectinMode(void); /*! \brief Returns the connection point for the specified table. The connection point is where the relationship is connected on envolved tables. The point returned deffers depending on the line connection mode used. */ QPointF getConnectionPoint(unsigned table_idx); void configureObjectShadow(void) = delete; void configureObjectSelection(void) = delete; signals: void s_relationshipModified(BaseGraphicObject *rel); friend class ObjectsScene; }; #endif pgmodeler-0.9.2/libobjrenderer/src/roundedrectitem.cpp000066400000000000000000000061641360462764600232050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "roundedrectitem.h" RoundedRectItem::RoundedRectItem(QGraphicsItem *parent) : QGraphicsRectItem(parent) { radius=5; corners=AllCorners; } void RoundedRectItem::setBorderRadius(double radius) { this->radius=radius; createPolygon(); } double RoundedRectItem::getBorderRadius(void) { return(radius); } void RoundedRectItem::setRoundedCorners(unsigned corners) { if(corners > AllCorners) corners=AllCorners; this->corners=corners; createPolygon(); } unsigned RoundedRectItem::getRoundedCorners(void) { return(corners); } bool RoundedRectItem::isCornerRounded(unsigned corner) { return((corners & corner)==corner); } void RoundedRectItem::setRect(const QRectF &rect) { QGraphicsRectItem::setRect(rect); createPolygon(); } void RoundedRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->setPen(this->pen()); painter->setBrush(this->brush()); if(corners==NoCorners) painter->drawRect(this->rect()); else if(corners==AllCorners) painter->drawRoundedRect(this->rect(), radius, radius); else painter->drawPolygon(polygon); } void RoundedRectItem::createPolygon(void) { polygon.clear(); if(corners!=NoCorners && corners!=AllCorners && this->rect().isValid()) { QRectF rect=this->rect(); if(isCornerRounded(TopLeftCorner)) polygon << calculatePoints(rect.topLeft() + QPointF(radius, radius), 180, 90); else polygon.append(this->rect().topLeft()); if(isCornerRounded(TopRightCorner)) polygon << calculatePoints(this->rect().topRight() + QPointF(-radius, radius), 90, 0); else polygon.append(this->rect().topRight()); if(isCornerRounded(BottomRightCorner)) polygon << calculatePoints(this->rect().bottomRight() + QPointF(-radius, -radius), 360, 270); else polygon.append(this->rect().bottomRight()); if(isCornerRounded(BottomLeftCorner)) polygon << calculatePoints(this->rect().bottomLeft() + QPointF(radius, -radius), 270, 180); else polygon.append(this->rect().bottomLeft()); } } QVector RoundedRectItem::calculatePoints(QPointF start_pnt, double start_angle, double end_angle) { QVector points; QLineF lin; double inc=(start_angle > end_angle ? -10 : 10), ang=start_angle; bool end=false; while(!end) { lin.setP1(start_pnt); lin.setLength(radius); lin.setAngle(ang); points.append(lin.p2()); ang+=inc; end=((inc > 0 && ang > end_angle) || (inc < 0 && ang < end_angle)); } return(points); } pgmodeler-0.9.2/libobjrenderer/src/roundedrectitem.h000066400000000000000000000052151360462764600226460ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class RoundedRectItem \brief Represents a rounded rectangle item */ #ifndef ROUNDED_RECT_ITEM_H #define ROUNDED_RECT_ITEM_H #include #include class RoundedRectItem: public QGraphicsRectItem { private: //! \brief Rect border radius double radius; //! \brief Polygon used to simulate the rounded rectangle with custom rounded corners QPolygonF polygon; //! \brief Stores which corners of the rectangle must be rounded unsigned corners; //! \brief Creates the polygon that represents the rounded rectangle void createPolygon(void); /*! \brief Calculates the points to simulate the rounded border. It must be informed the starting point and start/end angles. Based upon those parameters a line is configured and rotated from start_angle to end_angle and its final point (the rounded border point) is detected. The method returns all the calculated points which forms the rounded border. */ QVector calculatePoints(QPointF start_pnt, double start_angle, double end_angle); public: //! \brief Implies a normal rectangle (no rounded corner) static constexpr unsigned NoCorners=0, //! \brief The top-left corner will be rounded TopLeftCorner=2, //! \brief The top-right corner will be rounded TopRightCorner=4, //! \brief The Bottom-left corner will be rounded BottomLeftCorner=8, //! \brief The Bottom-right corner will be rounded BottomRightCorner=16, //! \brief All corners will be rounded AllCorners=32; explicit RoundedRectItem(QGraphicsItem *parent = 0); void setBorderRadius(double radius); double getBorderRadius(void); void setRoundedCorners(unsigned corners); unsigned getRoundedCorners(void); //! \brief Test if a corners is configured to be rounded bool isCornerRounded(unsigned corner); void setRect(const QRectF &rect); void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); }; #endif pgmodeler-0.9.2/libobjrenderer/src/schemaview.cpp000066400000000000000000000160061360462764600221370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "schemaview.h" #include "objectsscene.h" SchemaView::SchemaView(Schema *schema) : BaseObjectView(schema) { connect(schema, SIGNAL(s_objectModified(void)), this, SLOT(configureObject(void))); sch_name=new QGraphicsSimpleTextItem; sch_name->setZValue(1); box=new RoundedRectItem; box->setZValue(0); obj_selection=new RoundedRectItem; obj_selection->setVisible(false); obj_selection->setZValue(4); this->addToGroup(obj_selection); this->addToGroup(box); this->addToGroup(sch_name); this->setZValue(-5); this->configureObject(); all_selected=false; this->setFlag(ItemSendsGeometryChanges, true); } SchemaView::~SchemaView(void) { this->removeFromGroup(box); this->removeFromGroup(sch_name); delete(box); delete(sch_name); } void SchemaView::mousePressEvent(QGraphicsSceneMouseEvent *event) { //If the user press SHIFT + left-click select all the schema children if(event->modifiers()==Qt::ShiftModifier && event->buttons()==Qt::LeftButton && !all_selected) this->selectChildren(); else BaseObjectView::mousePressEvent(event); } void SchemaView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if(event->modifiers()==Qt::ShiftModifier && all_selected) event->ignore(); else BaseObjectView::mouseReleaseEvent(event); } void SchemaView::fetchChildren(void) { Schema *schema=dynamic_cast(this->getUnderlyingObject()); DatabaseModel *model=dynamic_cast(schema->getDatabase()); vector objs, list; vector types = { ObjectType::Table, ObjectType::ForeignTable, ObjectType::View }; //Gets all tables and views that belongs to the schema for(auto &type : types) { list = model->getObjects(type, schema); objs.insert(objs.end(), list.begin(), list.end()); } children.clear(); while(!objs.empty()) { children.push_front(dynamic_cast(dynamic_cast(objs.back())->getOverlyingObject())); objs.pop_back(); } } void SchemaView::selectChildren(void) { QList::Iterator itr=children.begin(); //Clears the current scene selection because only one schema and its children can be selected at once this->scene()->clearSelection(); all_selected=true; while(itr!=children.end()) { (*itr)->setSelected(true); itr++; } this->setSelected(true); } bool SchemaView::isChildrenSelected(void) { QList::Iterator itr=children.begin(); bool selected=true; while(itr!=children.end() && selected) { selected=(*itr)->isSelected(); itr++; } return(selected); } QVariant SchemaView::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if(change==ItemPositionChange) last_pos=this->pos(); else if(change==ItemPositionHasChanged && this->isSelected()) { double dx=pos().x() - last_pos.x(), dy=pos().y() - last_pos.y(); for(auto &child : children) child->moveBy(dx, dy); } return(BaseObjectView::itemChange(change, value)); } unsigned SchemaView::getChildrenCount() { return(children.size()); } QList SchemaView::getChildren(void) { return(children); } void SchemaView::togglePlaceholder(bool visible) { for(auto &obj : getChildren()) obj->togglePlaceholder(visible); } void SchemaView::moveTo(QPointF new_pos) { double dx=new_pos.x() - pos().x(), dy=new_pos.y() - pos().y(); this->setPos(new_pos); for(auto &child : children) child->moveBy(dx, dy); } void SchemaView::configureObject(void) { Schema *schema=dynamic_cast(this->getUnderlyingObject()); this->fetchChildren(); /* Only configures the schema view if the rectangle is visible and there are children objects. Otherwise the schema view is hidden */ if(schema->isRectVisible() && !children.isEmpty()) { QColor color; QRectF rect; QFont font; double sp_h=0, sp_v=0, txt_h=0; double x1=1000000, y1=1000000, x2=-1000000, y2=-1000000, width=0; QList::Iterator itr=children.begin(); //Configures the bounding rect based upon the children dimension while(itr!=children.end()) { rect.setTopLeft((*itr)->pos()); rect.setSize((*itr)->boundingRect().size()); if(rect.left() < x1) x1 = rect.left(); if(rect.right() > x2) x2 = rect.right(); if(rect.top() < y1) y1 = rect.top(); if(rect.bottom() > y2) y2 = rect.bottom(); itr++; } //Configures the schema name at the top sch_name->setText(compact_view && !schema->getAlias().isEmpty() ? schema->getAlias() : schema->getName()); font=BaseObjectView::getFontStyle(Attributes::Global).font(); font.setItalic(true); font.setBold(true); font.setPointSizeF(font.pointSizeF() * 1.3); sch_name->setFont(font); sch_name->setPos(HorizSpacing, VertSpacing); txt_h=sch_name->boundingRect().height() + (2 * VertSpacing); //Configures the box with the points calculated above sp_h=(3 * HorizSpacing); sp_v=(3 * VertSpacing) + txt_h; width=(x2-x1) + 1; if(width < sch_name->boundingRect().width()) width=sch_name->boundingRect().width(); rect.setTopLeft(QPointF(-sp_h, 0)); rect.setTopRight(QPointF(width + sp_h, 0)); rect.setBottomRight(QPointF(width + sp_h, y2-y1 + sp_v)); rect.setBottomLeft(QPointF(-sp_h, y2-y1 + sp_v)); box->setRect(rect); //Sets the schema view position this->setFlag(ItemSendsGeometryChanges, false); this->moveBy(-this->pos().x(),-this->pos().y()); this->setPos(QPointF(x1, y1 - txt_h)); schema->setPosition(this->mapToScene(rect.topLeft())); this->setFlag(ItemSendsGeometryChanges, true); color=schema->getFillColor(); color.setAlpha(ObjectAlphaChannel * 0.80); box->setBrush(color); color=QColor(color.red()/3,color.green()/3,color.blue()/3, 80); box->setPen(QPen(color, 1, Qt::SolidLine)); this->bounding_rect=rect; ObjectsScene *scene = dynamic_cast(this->scene()); this->setVisible(scene && scene->isLayerActive(schema->getLayer())); this->setToolTip(schema->getName(true) + QString(" (") + schema->getTypeName() + QString(")") + QString("\nId: %1").arg(schema->getObjectId())); sch_name->setToolTip(this->toolTip()); this->protected_icon->setPos(QPointF( sch_name->boundingRect().width() + sp_h, sch_name->pos().y() + VertSpacing )); this->configureObjectSelection(); this->configureProtectedIcon(); this->configurePositionInfo(this->pos()); this->configureSQLDisabledInfo(); } else this->setVisible(false); } pgmodeler-0.9.2/libobjrenderer/src/schemaview.h000066400000000000000000000040201360462764600215750ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class SchemaView \brief Represents the schema in a graphical way on the object scene */ #ifndef SCHEMA_VIEW_H #define SCHEMA_VIEW_H #include "schema.h" #include "databasemodel.h" #include "baseobjectview.h" #include "textboxview.h" #include "roundedrectitem.h" class SchemaView: public BaseObjectView { private: Q_OBJECT QGraphicsSimpleTextItem *sch_name; RoundedRectItem *box; QPointF last_pos; //! \brief Indicates if all children objects are selected bool all_selected; //! \brief Stores the views and tables that belongs to this schema QList children; void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); //! \brief Fills the children vector void fetchChildren(void); //! \brief Returns if all children are selected bool isChildrenSelected(void); QVariant itemChange(GraphicsItemChange change, const QVariant &value); public: SchemaView(Schema *schema); ~SchemaView(void); //! \brief Visually selects all the schema children void selectChildren(void); unsigned getChildrenCount(void); QList getChildren(void); virtual void togglePlaceholder(bool visible); void moveTo(QPointF new_pos); public slots: void configureObject(void); }; #endif pgmodeler-0.9.2/libobjrenderer/src/styledtextboxview.cpp000066400000000000000000000026141360462764600236210ustar00rootroot00000000000000#include "styledtextboxview.h" StyledTextboxView::StyledTextboxView(Textbox *txtbox, bool override_style) : TextboxView(txtbox, override_style) { QPolygonF pol; pol.append(QPointF(0,0)); pol.append(QPointF(20,0)); pol.append(QPointF(0,20)); fold=new QGraphicsPolygonItem; fold->setPolygon(pol); this->addToGroup(fold); this->configureObject(); } StyledTextboxView::~StyledTextboxView(void) { this->removeFromGroup(fold); delete(fold); } void StyledTextboxView::configureObject(void) { QRectF rect; QPolygonF pol; QPointF pnt; this->__configureObject(); fold->setBrush(text_item->brush()); fold->setPen(text_item->pen()); rect = text_item->boundingRect(); pol = text_item->polygon(); if(rect.height() < fold->boundingRect().height()) rect.setHeight(fold->boundingRect().height() + (2 * VertSpacing)); TextPolygonItem::resizePolygon(pol, rect.width() + fold->boundingRect().width(), rect.height()); pnt=pol.at(2); pol.remove(2); pol.insert(2, QPointF(pnt.x(), round(pnt.y() - fold->boundingRect().height()))); pol.insert(3, QPointF(round(pnt.x() - fold->boundingRect().width()), pnt.y())); text_item->setPolygon(pol); rect = text_item->boundingRect(); fold->setPos(rect.width() - fold->boundingRect().width(), rect.height() - fold->boundingRect().height()); bounding_rect = text_item->boundingRect(); this->configureObjectShadow(); this->configureObjectSelection(); } pgmodeler-0.9.2/libobjrenderer/src/styledtextboxview.h000066400000000000000000000024011360462764600232600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class StyledTextboxView \brief This class is only a styled representation of the TextboxView class */ #ifndef STYLED_TEXTBOX_VIEW_H #define STYLED_TEXTBOX_VIEW_H #include "textboxview.h" class StyledTextboxView: public TextboxView { private: Q_OBJECT //! \brief Fold indicator appended at bottom-right corner of the object QGraphicsPolygonItem *fold; public: StyledTextboxView(Textbox *txtbox, bool override_style=false); ~StyledTextboxView(void); protected slots: void configureObject(void); }; #endif pgmodeler-0.9.2/libobjrenderer/src/tableobjectview.cpp000066400000000000000000000525221360462764600231600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tableobjectview.h" const QString TableObjectView::TypeSeparator=QString(" "); const QString TableObjectView::ConstrSeparator=QString(" "); const QString TableObjectView::TextUnique=QString("uq"); const QString TableObjectView::TextExclude=QString("ex"); const QString TableObjectView::TextCheck=QString("ck"); const QString TableObjectView::TextPrimaryKey=QString("pk"); const QString TableObjectView::TextForeignKey=QString("fk"); const QString TableObjectView::TextNotNull=QString("nn"); const QString TableObjectView::ConstrDelimStart=QString("«"); const QString TableObjectView::ConstrDelimEnd=QString("»"); TableObjectView::TableObjectView(TableObject *object) : BaseObjectView(object) { descriptor=nullptr; fake_selection=false; for(unsigned i=0; i < 3; i++) lables[i]=new QGraphicsSimpleTextItem; if(obj_selection) delete(obj_selection); } TableObjectView::~TableObjectView(void) { delete(descriptor); for(unsigned i=0; i < 3; i++) delete(lables[i]); delete(obj_selection); } void TableObjectView::configureDescriptor(ConstraintType constr_type) { ObjectType obj_type=ObjectType::BaseObject; Column *column=dynamic_cast(this->getUnderlyingObject()); bool ellipse_desc=false; double factor=(font_config[Attributes::Global].font().pointSizeF()/DefaultFontSize) * BaseObjectView::getScreenDpiFactor(); QPen pen; //Based upon the source object type the descriptor is allocated if(this->getUnderlyingObject()) obj_type=this->getUnderlyingObject()->getObjectType(); /* Elliptical descriptor is used to columns (with or without not-null constraint), for other object types, polygonal descriptor is usded */ ellipse_desc=((column && constr_type==BaseType::Null) || (!TableObject::isTableObject(obj_type))); if(descriptor && ((ellipse_desc && !dynamic_cast(descriptor)) || (!ellipse_desc && dynamic_cast(descriptor)))) { delete(descriptor); descriptor=nullptr; } if(!descriptor) { if(ellipse_desc) descriptor=new QGraphicsEllipseItem; else descriptor=new QGraphicsPolygonItem; } if(column) { QString attrib; QPolygonF pol; if(constr_type==BaseType::Null) { QGraphicsEllipseItem *desc=dynamic_cast(descriptor); desc->setRect(QRectF(QPointF(0,0), QSizeF(9.0 * factor, 9.0 * factor))); if(column->isNotNull()) attrib=Attributes::NnColumn; else attrib=Attributes::Column; desc->setBrush(this->getFillStyle(attrib)); pen = this->getBorderStyle(attrib); pen.setWidthF(ObjectBorderWidth * 1.15); desc->setPen(pen); } else { QGraphicsPolygonItem *desc=dynamic_cast(descriptor); if(constr_type==ConstraintType::PrimaryKey) { attrib=Attributes::PkColumn; pol.append(QPointF(2,0)); pol.append(QPointF(0,2)); pol.append(QPointF(0,7)); pol.append(QPointF(2,9)); pol.append(QPointF(3,8)); pol.append(QPointF(3,6)); pol.append(QPointF(4,6)); pol.append(QPointF(5,7)); pol.append(QPointF(6,6)); pol.append(QPointF(7,5)); pol.append(QPointF(9,7)); pol.append(QPointF(9,3)); pol.append(QPointF(3,3)); pol.append(QPointF(3,1)); } else if(constr_type==ConstraintType::ForeignKey) { attrib=Attributes::FkColumn; pol.append(QPointF(0,3)); pol.append(QPointF(0,6)); pol.append(QPointF(4,6)); pol.append(QPointF(4,9)); pol.append(QPointF(5,9)); pol.append(QPointF(9,5)); pol.append(QPointF(9,4)); pol.append(QPointF(5,0)); pol.append(QPointF(4,0)); pol.append(QPointF(4,3)); } else if(constr_type==ConstraintType::Unique) { attrib=Attributes::UqColumn; pol.append(QPointF(4,0)); pol.append(QPointF(0,4)); pol.append(QPointF(0,5)); pol.append(QPointF(4,9)); pol.append(QPointF(5,9)); pol.append(QPointF(9,5)); pol.append(QPointF(9,4)); pol.append(QPointF(5,0)); } if(factor!=1.0) TextPolygonItem::resizePolygon(pol, pol.boundingRect().width() * factor, pol.boundingRect().height() * factor); desc->setPolygon(pol); desc->setBrush(this->getFillStyle(attrib)); pen = this->getBorderStyle(attrib); pen.setWidthF(ObjectBorderWidth * 1.15); desc->setPen(pen); } } else if(obj_type != ObjectType::BaseObject) { TableObject *tab_obj=dynamic_cast(this->getUnderlyingObject()); QGraphicsPolygonItem *desc=dynamic_cast(descriptor); QPolygonF pol; pol.append(QPointF(5,0)); pol.append(QPointF(0,5)); pol.append(QPointF(4,9)); pol.append(QPointF(9,9)); pol.append(QPointF(9,4)); if(factor!=1.0) TextPolygonItem::resizePolygon(pol, pol.boundingRect().width() * factor , pol.boundingRect().height() * factor); desc->setPolygon(pol); desc->setBrush(this->getFillStyle(tab_obj->getSchemaName())); pen = this->getBorderStyle(tab_obj->getSchemaName()); pen.setWidthF(ObjectBorderWidth * 1.15); desc->setPen(pen); } else { QGraphicsEllipseItem *desc=dynamic_cast(descriptor); desc->setRect(QRectF(QPointF(0,0), QSizeF(9.0 * factor, 9.0 * factor))); desc->setBrush(this->getFillStyle(Attributes::Reference)); pen = this->getBorderStyle(Attributes::Reference); pen.setWidthF(ObjectBorderWidth * 1.15); desc->setPen(pen); } } void TableObjectView::configureObject(void) { if(this->getUnderlyingObject()) { QTextCharFormat fmt; double px = 0; QString str_constr, tooltip, atribs_tip; TableObject *tab_obj=dynamic_cast(this->getUnderlyingObject()); Column *column=dynamic_cast(tab_obj); ConstraintType constr_type=ConstraintType::Null; bool sql_disabled=false; tooltip=tab_obj->getName() + QString(" (") + tab_obj->getTypeName() + QString(")"); tooltip+=QString("\nId: %1").arg(tab_obj->getObjectId()); sql_disabled=tab_obj->isSQLDisabled(); fake_selection=false; if(column) { if(column->isAddedByRelationship()) tooltip+=trUtf8("\nRelationship: %1").arg(column->getParentRelationship()->getName()); str_constr=this->getConstraintString(column); if(str_constr.indexOf(TextPrimaryKey)>=0) { fmt=font_config[Attributes::PkColumn]; constr_type=ConstraintType::PrimaryKey; } else if(str_constr.indexOf(TextForeignKey)>=0) { fmt=font_config[Attributes::FkColumn]; constr_type=ConstraintType::ForeignKey; } else if(str_constr.indexOf(TextUnique)>=0) { fmt=font_config[Attributes::UqColumn]; constr_type=ConstraintType::Unique; } else if(str_constr.indexOf(TextNotNull)>=0) fmt=font_config[Attributes::NnColumn]; else fmt=font_config[Attributes::Column]; if(column->isAddedByRelationship()) fmt=font_config[Attributes::InhColumn]; else if(column->isProtected()) fmt=font_config[Attributes::ProtColumn]; if(str_constr.indexOf(TextPrimaryKey)>=0) atribs_tip+=(~ConstraintType(ConstraintType::PrimaryKey)).toLower() + QString(", "); if(str_constr.indexOf(TextForeignKey)>=0) atribs_tip+=(~ConstraintType(ConstraintType::ForeignKey)).toLower() + QString(", "); if(str_constr.indexOf(TextUnique)>=0) atribs_tip+=(~ConstraintType(ConstraintType::Unique)).toLower() + QString(", "); if(str_constr.indexOf(TextExclude)>=0) atribs_tip+=(~ConstraintType(ConstraintType::Exclude)).toLower() + QString(", "); if(str_constr.indexOf(TextNotNull)>=0) atribs_tip+=QString("not null"); } else { if(tab_obj->isAddedByRelationship()) fmt=font_config[Attributes::InhColumn]; else if(tab_obj->isProtected()) fmt=font_config[Attributes::ProtColumn]; else fmt=font_config[tab_obj->getSchemaName()]; } configureDescriptor(constr_type); descriptor->setPos(HorizSpacing, 0); px=HorizSpacing + descriptor->boundingRect().width() + (2 * HorizSpacing); //Configuring the labels as follow: [object name] [type] [constraints] lables[0]->setText(compact_view && !tab_obj->getAlias().isEmpty() ? tab_obj->getAlias() : tab_obj->getName()); //Strikeout the column name when its SQL is disabled QFont font=fmt.font(); font.setStrikeOut(sql_disabled); fmt.setFont(font); lables[0]->setFont(fmt.font()); lables[0]->setBrush(fmt.foreground()); lables[0]->setPos(px, 0); px+=lables[0]->boundingRect().width(); //Configuring the type label fmt=font_config[Attributes::ObjectType]; if(compact_view) lables[1]->setText(QString()); else { if(column) lables[1]->setText(TypeSeparator + (*column->getType())); else lables[1]->setText(TypeSeparator + tab_obj->getSchemaName()); } lables[1]->setFont(fmt.font()); lables[1]->setBrush(fmt.foreground()); lables[1]->setPos(px, 0); px+=lables[1]->boundingRect().width() + (3 * HorizSpacing); //Configuring the constraints label fmt=font_config[Attributes::Constraints]; if(compact_view) lables[2]->setText(QString()); else if(column) lables[2]->setText(!str_constr.isEmpty() ? str_constr : QString(" ")); else { Rule *rule=dynamic_cast(tab_obj); Trigger *trigger=dynamic_cast(tab_obj); Index *index=dynamic_cast(tab_obj); Constraint *constr=dynamic_cast(tab_obj); Policy *policy = dynamic_cast(tab_obj); if(rule) { str_constr+=(~rule->getExecutionType()).mid(0,1); atribs_tip+=(~rule->getExecutionType()).toLower() + QString(", "); str_constr+=ConstrSeparator; str_constr+=(~rule->getEventType()).mid(3,1); atribs_tip+=(~rule->getEventType()).toLower(); str_constr=str_constr.toLower(); } else if(trigger) { str_constr+=(~trigger->getFiringType()).mid(0,1); str_constr+=ConstrSeparator; atribs_tip+=(~trigger->getFiringType()).toLower() + QString(", "); for(unsigned i=EventType::OnInsert; i <= EventType::OnTruncate; i++) { if(trigger->isExecuteOnEvent(EventType(i))) { str_constr+=(~EventType(i)).mid(3,1); atribs_tip+=(~EventType(i)).toLower() + QString(", "); } } str_constr=str_constr.toLower(); } else if(index) { if(index->getIndexAttribute(Index::Unique)) { str_constr+=QString("u"); atribs_tip += QString("unique") + QString(", "); } if(index->getIndexAttribute(Index::Concurrent)) { str_constr+=QString("c"); atribs_tip += QString("concurrent") + QString(", "); } if(index->getIndexAttribute(Index::FastUpdate)) { str_constr+=QString("f"); atribs_tip += QString("fast updated"); } if(index->getIndexAttribute(Index::Buffering)) { str_constr+=QString("b"); atribs_tip += QString("buffering"); } } else if(constr) { ConstraintType type = constr->getConstraintType(); if(type == ConstraintType::PrimaryKey) str_constr = TextPrimaryKey; else if(type == ConstraintType::ForeignKey) str_constr = TextForeignKey; else if(type == ConstraintType::Unique) str_constr = TextUnique; else if(type == ConstraintType::Exclude) str_constr = TextExclude; else if(type == ConstraintType::Check) str_constr = TextCheck; atribs_tip = (~type).toLower(); } else if(policy) { if(policy->isPermissive()) { str_constr += QString("p"); atribs_tip += QString("permissive"); } else { str_constr += QString("r"); atribs_tip += QString("restrictive"); } atribs_tip += QString(", "); str_constr += (~policy->getPolicyCommand()).toLower().at(0); atribs_tip += (~policy->getPolicyCommand()).toLower(); } if(!str_constr.isEmpty()) lables[2]->setText(ConstrDelimStart + QString(" ") + str_constr + QString(" ") + ConstrDelimEnd); else lables[2]->setText(QString()); } if(!atribs_tip.isEmpty()) { if(atribs_tip.at(atribs_tip.length()-1)==' ') atribs_tip.remove(atribs_tip.length()-2, 2); atribs_tip=QString("\n") + ConstrDelimStart + QString(" ") + atribs_tip + QString(" ") + ConstrDelimEnd; } if(!tab_obj->getComment().isEmpty()) atribs_tip += QString("\n---\n%1").arg(tab_obj->getComment()); lables[2]->setFont(fmt.font()); lables[2]->setBrush(fmt.foreground()); lables[2]->setPos(px, 0); calculateBoundingRect(); this->setToolTip(tooltip + atribs_tip); } } void TableObjectView::configureObject(Reference reference) { QTextCharFormat fmt; double px; QString str_aux; configureDescriptor(); descriptor->setPos(HorizSpacing, 0); px=descriptor->pos().x() + descriptor->boundingRect().width() + (2 * HorizSpacing); if(reference.getReferenceType()==Reference::ReferColumn) { //Configures the name label as: [table].[column] fmt=font_config[Attributes::RefTable]; if(compact_view && !reference.getReferenceAlias().isEmpty()) lables[0]->setText(reference.getReferenceAlias()); else lables[0]->setText(reference.getTable()->getName() + "."); lables[0]->setFont(fmt.font()); lables[0]->setBrush(fmt.foreground()); lables[0]->setPos(px, 0); px+=lables[0]->boundingRect().width(); fmt=font_config[Attributes::RefColumn]; if(compact_view && !reference.getReferenceAlias().isEmpty()) lables[1]->setText(QString()); else { if(reference.getColumn()) lables[1]->setText(reference.getColumn()->getName()); else lables[1]->setText("*"); } lables[1]->setFont(fmt.font()); lables[1]->setBrush(fmt.foreground()); lables[1]->setPos(px, 0); px+=lables[1]->boundingRect().width(); } else { fmt=font_config[Attributes::RefTable]; str_aux = compact_view && !reference.getReferenceAlias().isEmpty() ? reference.getReferenceAlias() : QString(); if(str_aux.isEmpty()) { str_aux=reference.getExpression().simplified().mid(0,25); if(reference.getExpression().size() > 25) str_aux+=QString("..."); str_aux.replace(QString("\n"), QString(" ")); } lables[0]->setText(str_aux); lables[0]->setFont(fmt.font()); lables[0]->setBrush(fmt.foreground()); lables[1]->setText(QString()); lables[0]->setPos(px, 0); px+=lables[0]->boundingRect().width(); } //Configures a label for the alias (if there is one) if(!compact_view && ((reference.getColumn() && !reference.getColumnAlias().isEmpty()) || (!reference.getAlias().isEmpty() && reference.getReferenceType()==Reference::ReferExpression))) { if(reference.getReferenceType()==Reference::ReferExpression) str_aux=reference.getAlias(); else str_aux=reference.getColumnAlias(); str_aux=QString(" (") + str_aux + QString(") "); fmt=font_config[Attributes::Alias]; lables[2]->setText(str_aux); lables[2]->setFont(fmt.font()); lables[2]->setBrush(fmt.foreground()); lables[2]->setPos(px, 0); } else lables[2]->setText(QString()); calculateBoundingRect(); } void TableObjectView::configureObject(const SimpleColumn &col) { QTextCharFormat fmt; double px; configureDescriptor(); descriptor->setPos(HorizSpacing, 0); px=descriptor->pos().x() + descriptor->boundingRect().width() + (2 * HorizSpacing); fmt = font_config[Attributes::Column]; if(compact_view && !col.alias.isEmpty()) lables[0]->setText(col.alias); else lables[0]->setText(col.name); lables[0]->setFont(fmt.font()); lables[0]->setBrush(fmt.foreground()); lables[0]->setPos(px, 0); px+=lables[0]->boundingRect().width() + (4 * HorizSpacing); if(!compact_view && !col.type.isEmpty()) { fmt=font_config[Attributes::ObjectType]; lables[1]->setText(col.type); lables[1]->setFont(fmt.font()); lables[1]->setBrush(fmt.foreground()); lables[1]->setPos(px, 0); px+=lables[1]->boundingRect().width() + (4 * HorizSpacing); } else lables[1]->setText(QString()); lables[2]->setText(QString()); calculateBoundingRect(); } void TableObjectView::setChildObjectXPos(unsigned obj_idx, double px) { if(obj_idx >= 4) throw Exception(ErrorCode::RefObjectInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); if(obj_idx==0) descriptor->setPos(px, descriptor->pos().y()); else lables[obj_idx-1]->setPos(px, lables[obj_idx-1]->pos().y()); calculateBoundingRect(); } void TableObjectView::calculateBoundingRect(void) { double width = 0, height = 0, curr_w = 0, py = 0; width = descriptor->pos().x() + descriptor->boundingRect().width(); height = lables[0]->boundingRect().height(); for(int i = 0; i < 3; i++) { if(lables[i]->text().isEmpty()) continue; curr_w = lables[i]->pos().x() + lables[i]->boundingRect().width(); if(width < curr_w) width = lables[i]->pos().x() + lables[i]->boundingRect().width(); } bounding_rect = QRectF(QPointF(0,0), QSizeF(width + (4 * HorizSpacing), height + VertSpacing * 0.80)); //Adjusting the Y position of the objects in order to center them on the new bouding rect descriptor->setPos(descriptor->pos().x(), (bounding_rect.height() - descriptor->boundingRect().height() + (VertSpacing * 0.4))/2); py = (bounding_rect.height() - lables[0]->boundingRect().height())/2; for(unsigned i = 0; i < 3; i++) lables[i]->setPos(lables[i]->pos().x(), py); } QGraphicsItem *TableObjectView::getChildObject(unsigned obj_idx) { if(obj_idx > ConstrAliasLabel) throw Exception(ErrorCode::RefObjectInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); if(obj_idx == ObjDescriptor) return(descriptor); else return(lables[obj_idx - 1]); } QString TableObjectView::getConstraintString(Column *column) { if(column && column->getParentTable()) { PhysicalTable *table=dynamic_cast(column->getParentTable()); QString str_constr; Constraint *constr=nullptr; vector::iterator itr,itr_end; ConstraintType constr_type; itr=table->getObjectList(ObjectType::Constraint)->begin(); itr_end=table->getObjectList(ObjectType::Constraint)->end(); while(itr!=itr_end) { constr=dynamic_cast(*itr); itr++; //Check if the column is referecend by the constraint if((constr->getConstraintType()!=ConstraintType::Exclude && constr->isColumnExists(column, Constraint::SourceCols)) || (constr->getConstraintType()==ConstraintType::Exclude && constr->isColumnReferenced(column, false))) { constr_type=constr->getConstraintType(); if(constr_type==ConstraintType::PrimaryKey) str_constr=TextPrimaryKey + ConstrSeparator + str_constr; if(constr_type==ConstraintType::ForeignKey && str_constr.indexOf(TextForeignKey) < 0) str_constr+=TextForeignKey + ConstrSeparator; if(constr_type==ConstraintType::Unique && str_constr.indexOf(TextUnique) < 0) str_constr+=TextUnique + ConstrSeparator; if(constr_type==ConstraintType::Exclude && str_constr.indexOf(TextExclude) < 0) str_constr+=TextExclude + ConstrSeparator; } } if(column->isNotNull() && !str_constr.contains(TextPrimaryKey)) str_constr+=TextNotNull + ConstrSeparator; if(!str_constr.isEmpty()) str_constr= ConstrDelimStart + ConstrSeparator + str_constr + ConstrDelimEnd; return(str_constr); } else return(QString()); } void TableObjectView::setFakeSelection(bool value) { // Fake selection is used only by instances that own and underlying object (column, constratin, trigger,etc) if(!this->getUnderlyingObject()) return; fake_selection = value; if(value) { configureObjectSelection(); sel_order=++BaseObjectView::global_sel_order; } else sel_order = 0; update(); } bool TableObjectView::hasFakeSelection(void) { return(fake_selection); } void TableObjectView::configureObjectSelection(void) { QGraphicsItem *parent = this->parentItem(); RoundedRectItem *rect_item=nullptr; QRectF rect = this->boundingRect(); /* In order to avoid unnecessary memory usage by items that eventually will * get selection we allocate the object selection rectangle only if the object * itself is selected by the user, and it'll be allocated until the object's destruction */ if(!obj_selection) obj_selection=new RoundedRectItem; rect_item = dynamic_cast(obj_selection); rect.setX(0); rect.setY(0); rect.setHeight(rect.height() - VertSpacing); // An small hack to capture the width of the table in which the item is child of if(parent->parentItem()) rect.setWidth(parent->parentItem()->boundingRect().width() - (2.5 * HorizSpacing)); else rect.setWidth(rect.width() - (3.5 * HorizSpacing)); rect_item->setBorderRadius(2); rect_item->setRect(rect); rect_item->setPos(0, VertSpacing/2); rect_item->setBrush(this->getFillStyle(Attributes::ObjSelection)); rect_item->setPen(this->getBorderStyle(Attributes::ObjSelection)); } void TableObjectView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->save(); painter->translate(descriptor->pos()); descriptor->paint(painter, option, widget); painter->restore(); for(int i = 0 ; i < 3; i++) { if(lables[i]->text().isEmpty()) continue; painter->save(); painter->translate(lables[i]->pos()); lables[i]->paint(painter, option, widget); painter->restore(); } if(fake_selection) { painter->translate(obj_selection->pos()); obj_selection->paint(painter, option, widget); } } QRectF TableObjectView::boundingRect(void) const { return(bounding_rect); } pgmodeler-0.9.2/libobjrenderer/src/tableobjectview.h000066400000000000000000000062251360462764600226240ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class TableObjectView \brief implements the graphical representation for table objects (columns, constraints, triggers, rules, indexes) as well the view references */ #ifndef TABLE_OBJECT_VIEW_H #define TABLE_OBJECT_VIEW_H #include "view.h" #include "table.h" #include "baseobjectview.h" class TableObjectView: public BaseObjectView { private: Q_OBJECT //! \brief Table object descriptor QGraphicsItem *descriptor; bool fake_selection; //! \brief Labels used to show objects informatoni (name, type, constraints/aliases) QGraphicsSimpleTextItem *lables[3]; /*! \brief Configures the descriptor object according to the source object. The constraint type parameter is only used when the source object is a column and is used to format the descriptor indication that the column has a constraint */ void configureDescriptor(ConstraintType constr_type=BaseType::Null); QVariant itemChange(GraphicsItemChange, const QVariant &value) { return(value); } void calculateBoundingRect(void); public: static const QString ConstrDelimEnd, ConstrDelimStart, TypeSeparator, ConstrSeparator, TextForeignKey, TextNotNull, TextPrimaryKey, TextUnique, TextCheck, TextExclude; static constexpr unsigned ObjDescriptor = 0, NameLabel = 1, TypeLabel = 2, ConstrAliasLabel = 3; TableObjectView(TableObject *object=nullptr); ~TableObjectView(void); //! \brief Configures the object as a view reference void configureObject(Reference reference); //! \brief Configures a item from a SimpleColumn instance void configureObject(const SimpleColumn &col); //! \brief Configures the object as a table object void configureObject(void); //! \brief Sets the horizontal position of the specified child object (index) void setChildObjectXPos(unsigned obj_idx, double px); //! \brief Returns the child object at the specified index QGraphicsItem *getChildObject(unsigned obj_idx); /*! \brief Returns a formatted string containing the keywords indicating the constraints that is applyed to the passed column */ static QString getConstraintString(Column *column); void setFakeSelection(bool value); bool hasFakeSelection(void); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr); virtual QRectF boundingRect(void) const; virtual void configureObjectSelection(void); void configureObjectShadow(void) = delete; }; #endif pgmodeler-0.9.2/libobjrenderer/src/tabletitleview.cpp000066400000000000000000000120221360462764600230220ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tabletitleview.h" TableTitleView::TableTitleView(void) : BaseObjectView(nullptr) { schema_name=new QGraphicsSimpleTextItem; schema_name->setZValue(1); obj_name=new QGraphicsSimpleTextItem; obj_name->setZValue(1); box=new RoundedRectItem; box->setRoundedCorners(RoundedRectItem::TopLeftCorner | RoundedRectItem::TopRightCorner); box->setZValue(0); } TableTitleView::~TableTitleView(void) { delete(schema_name); delete(obj_name); delete(box); } void TableTitleView::configureObject(BaseGraphicObject *object) { QTextCharFormat fmt; QString name_attrib, schema_name_attrib, title_color_attrib; QPen pen; Schema *schema=nullptr; QFont font; Tag *tag=nullptr; PhysicalTable *table = dynamic_cast(object); //Raises an error if the object related to the title is not allocated if(!object) throw Exception(ErrorCode::OprNotAllocatedObject, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Raises an error if the object is invalid else if(!BaseTable::isBaseTable(object->getObjectType())) throw Exception(ErrorCode::OprObjectInvalidType, __PRETTY_FUNCTION__, __FILE__, __LINE__); schema=dynamic_cast(object->getSchema()); tag=dynamic_cast(object)->getTag(); if(object->getObjectType()==ObjectType::View && !tag) { name_attrib=Attributes::ViewName; schema_name_attrib=Attributes::ViewSchemaName; title_color_attrib=Attributes::ViewTitle; } else if(object->getObjectType()==ObjectType::ForeignTable && !tag) { name_attrib=Attributes::ForeignTableName; schema_name_attrib=Attributes::ForeignTableSchemaName; title_color_attrib=Attributes::ForeignTableTitle; } else { name_attrib=Attributes::TableName; schema_name_attrib=Attributes::TableSchemaName; title_color_attrib=Attributes::TableTitle; } fmt=font_config[schema_name_attrib]; font=fmt.font(); schema_name->setFont(font); if(!tag) schema_name->setBrush(fmt.foreground()); else schema_name->setBrush(tag->getElementColor(schema_name_attrib, Tag::FillColor1)); if(schema->isRectVisible()) schema_name->setText(QString(" ")); else { if(compact_view && !schema->getAlias().isEmpty()) schema_name->setText(schema->getAlias() + QString(".")); else schema_name->setText(schema->getName() + QString(".")); } fmt=font_config[name_attrib]; font=fmt.font(); obj_name->setFont(font); obj_name->setText(compact_view && !object->getAlias().isEmpty() ? object->getAlias() : object->getName()); if(!tag) { obj_name->setBrush(fmt.foreground()); box->setBrush(this->getFillStyle(title_color_attrib)); } else { obj_name->setBrush(tag->getElementColor(name_attrib, Tag::FillColor1)); box->setBrush(tag->getFillStyle(title_color_attrib)); } pen=this->getBorderStyle(title_color_attrib); if(tag) pen.setColor(tag->getElementColor(title_color_attrib, Tag::BorderColor)); if(object->getObjectType()==ObjectType::View || (table && table->isPartition())) pen.setStyle(Qt::DashLine); box->setPen(pen); if(schema->isRectVisible()) this->resizeTitle(obj_name->boundingRect().width() + (2 * HorizSpacing), obj_name->boundingRect().height() + (2 * VertSpacing)); else this->resizeTitle(obj_name->boundingRect().width() + schema_name->boundingRect().width() + (2 * HorizSpacing), schema_name->boundingRect().height() + (2 * VertSpacing)); } void TableTitleView::resizeTitle(double width, double height) { double py = height / 1.5; box->setPos(0,0); box->setRect(QRectF(0,0, width, height)); if(schema_name->text()==QString(" ")) obj_name->setPos((box->boundingRect().width() - obj_name->boundingRect().width())/2.0, py); else { schema_name->setPos((box->boundingRect().width() - (schema_name->boundingRect().width() + obj_name->boundingRect().width()))/2.0, py); obj_name->setPos(schema_name->pos().x() + schema_name->boundingRect().width(), py); } this->bounding_rect.setSize(QSizeF(box->boundingRect().width(), box->boundingRect().height())); } void TableTitleView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { box->paint(painter, option, widget); painter->setFont(schema_name->font()); painter->setPen(schema_name->brush().color()); painter->drawText(schema_name->pos(), schema_name->text()); painter->setFont(obj_name->font()); painter->setPen(obj_name->brush().color()); painter->drawText(obj_name->pos(), obj_name->text()); } pgmodeler-0.9.2/libobjrenderer/src/tabletitleview.h000066400000000000000000000031341360462764600224730ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class TableTitleView \brief Implements the graphical representation for table title */ #ifndef TABLE_TITLE_VIEW_H #define TABLE_TITLE_VIEW_H #include "view.h" #include "table.h" #include "baseobjectview.h" #include "textboxview.h" #include "roundedrectitem.h" class TableTitleView: public BaseObjectView { private: Q_OBJECT //! \brief Rounded rectangle object that defines the title border RoundedRectItem *box; //! \brief Graphical texts that is used to store the object name and schema name QGraphicsSimpleTextItem *obj_name, *schema_name; void configureObject(void){} public: TableTitleView(void); ~TableTitleView(void); void configureObject(BaseGraphicObject *object); void resizeTitle(double width, double height); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr); }; #endif pgmodeler-0.9.2/libobjrenderer/src/tableview.cpp000066400000000000000000000226161360462764600217720ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tableview.h" TableView::TableView(PhysicalTable *table) : BaseTableView(table) { connect(table, SIGNAL(s_objectModified(void)), this, SLOT(configureObject(void))); this->configureObject(); } void TableView::configureObject(void) { /* If the table isn't visible we abort the current configuration * and mark its geometry update as pending so in the next call to * setVisible(true) the geometry can be updated (see BaseObjectView::itemChange()) */ if(!this->isVisible()) { pending_geom_update = true; return; } PhysicalTable *table=dynamic_cast(this->getUnderlyingObject()); int i, count, obj_idx; double width=0, px=0, cy=0, old_width=0, old_height=0; unsigned start_col = 0, end_col = 0, start_ext = 0, end_ext = 0; QPen pen; TableObjectView *col_item=nullptr; QList subitems; QList col_items; TableObject *tab_obj=nullptr; QGraphicsItemGroup *groups[]={ columns, ext_attribs }; RoundedRectItem *bodies[]={ body, ext_attribs_body }; vector tab_objs, columns, ext_tab_objs; QStringList atribs, tag_attribs = { Attributes::TableBody, Attributes::TableExtBody }; Tag *tag=table->getTag(); CollapseMode collapse_mode = table->getCollapseMode(); vector ext_types = BaseObject::getChildObjectTypes(table->getObjectType()); bool has_col_pag = false, has_ext_pag = false; if(table->getObjectType() == ObjectType::Table) atribs.append({ Attributes::TableBody, Attributes::TableExtBody }); else atribs.append({ Attributes::ForeignTableBody, Attributes::ForeignTableExtBody }); // Clear the selected children objects vector since we'll (re)configure the whole table sel_child_objs.clear(); //Configures the table title title->configureObject(table); // We store the columns in a separated vector in order to paginate them (if enabled) columns.assign(table->getObjectList(ObjectType::Column)->begin(), table->getObjectList(ObjectType::Column)->end()); // We store the extended attributes in a separated vector in order to paginate them (if enabled) for(auto &type : ext_types) { if(type == ObjectType::Column) continue; ext_tab_objs.insert(ext_tab_objs.end(), table->getObjectList(type)->begin(), table->getObjectList(type)->end()); } has_col_pag = configurePaginationParams(BaseTable::AttribsSection, columns.size(), start_col, end_col); has_ext_pag = configurePaginationParams(BaseTable::ExtAttribsSection, collapse_mode != CollapseMode::ExtAttribsCollapsed ? ext_tab_objs.size() : 0, start_ext, end_ext); attribs_toggler->setHasExtAttributes(!hide_ext_attribs && !ext_tab_objs.empty()); px=0; old_width=this->bounding_rect.width(); old_height=this->bounding_rect.height(); for(obj_idx=0; obj_idx < 2; obj_idx++) { tab_objs.clear(); if(obj_idx==0) { if(collapse_mode != CollapseMode::AllAttribsCollapsed) { if(table->isPaginationEnabled() && has_col_pag) tab_objs.assign(columns.begin() + start_col, columns.begin() + end_col); else tab_objs.assign(columns.begin(), columns.end()); } } else { if(!hide_ext_attribs && collapse_mode == CollapseMode::NotCollapsed) { if(table->isPaginationEnabled() && has_ext_pag) tab_objs.assign(ext_tab_objs.begin() + start_ext, ext_tab_objs.begin() + end_ext); else tab_objs.assign(ext_tab_objs.begin(), ext_tab_objs.end()); } } //Gets the subitems of the current group subitems=groups[obj_idx]->childItems(); groups[obj_idx]->moveBy(-groups[obj_idx]->scenePos().x(), -groups[obj_idx]->scenePos().y()); count=tab_objs.size(); groups[obj_idx]->setVisible(count > 0); bodies[obj_idx]->setVisible(count > 0); for(i=0; i < count; i++) { tab_obj=tab_objs.at(i); //Reusing the subitem if it was allocated before if(!subitems.isEmpty() && i < subitems.size()) { col_item=dynamic_cast(subitems[i]); col_item->setSourceObject(tab_obj); col_item->configureObject(); col_item->moveBy(-col_item->scenePos().x(),-col_item->scenePos().y()); } else col_item=new TableObjectView(tab_obj); //Configures the item and set its position col_item->configureObject(); col_item->moveBy(HorizSpacing, (i * col_item->boundingRect().height()) + VertSpacing); /* Calculates the width of the name + type of the object. This is used to align all the constraint labels on table */ width=col_item->getChildObject(TableObjectView::ObjDescriptor)->boundingRect().width() + col_item->getChildObject(TableObjectView::NameLabel)->boundingRect().width() + (5 * HorizSpacing); if(px < width) px=width; col_items.push_back(col_item); } //Destroy the unused items i=subitems.size()-1; while(i > count-1) { col_item=dynamic_cast(subitems[i]); groups[obj_idx]->removeFromGroup(col_item); delete(col_item); i--; } //Set all items position while(!col_items.isEmpty()) { col_item=dynamic_cast(col_items.front()); groups[obj_idx]->removeFromGroup(col_item); col_items.pop_front(); //Positioning the type label col_item->setChildObjectXPos(TableObjectView::TypeLabel, px); //Positioning the constraints label col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel, px + (col_item->getChildObject(TableObjectView::TypeLabel)->boundingRect().width() * 1.05)); groups[obj_idx]->addToGroup(col_item); } } width = calculateWidth(); //Resizes the title using the new width title->resizeTitle(width, title->boundingRect().height()); //Resizes the columns/extended attributes using the new width for(obj_idx=0; obj_idx < 2; obj_idx++) { bodies[obj_idx]->setRect(QRectF(0,0, width, groups[obj_idx]->boundingRect().height() + (2 * VertSpacing))); pen=this->getBorderStyle(atribs[obj_idx]); if(table->isPartition()) pen.setStyle(Qt::DashLine); if(!tag) bodies[obj_idx]->setBrush(this->getFillStyle(atribs[obj_idx])); else { pen.setColor(tag->getElementColor(tag_attribs[obj_idx], Tag::BorderColor)); bodies[obj_idx]->setBrush(tag->getFillStyle(tag_attribs[obj_idx])); } bodies[obj_idx]->setPen(pen); if(obj_idx==0) bodies[obj_idx]->setPos(title->pos().x(), title->boundingRect().height()-1); else { if(bodies[0]->isVisible()) bodies[obj_idx]->setPos(title->pos().x(), title->boundingRect().height() + bodies[0]->boundingRect().height() - 2); else bodies[obj_idx]->setPos(title->pos().x(), title->boundingRect().height()-1); } groups[obj_idx]->setPos(bodies[obj_idx]->pos()); subitems=groups[obj_idx]->childItems(); while(!subitems.isEmpty()) { col_item=dynamic_cast(subitems.front()); subitems.pop_front(); col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel, width - col_item->getChildObject(TableObjectView::ConstrAliasLabel)->boundingRect().width() - (2 * HorizSpacing) - 1); //Generating the connection points of the columns if(obj_idx==0) { tab_obj=dynamic_cast(col_item->getUnderlyingObject()); cy=title->boundingRect().height() + col_item->pos().y() + (col_item->boundingRect().height()/2); conn_points[tab_obj].resize(2); conn_points[tab_obj][LeftConnPoint]=QPointF(col_item->pos().x() - 1.5, cy); conn_points[tab_obj][RightConnPoint]=QPointF(col_item->pos().x() + width - 1.5 , cy); } } } BaseTableView::__configureObject(width); if(table->isPartitioned()) table_tooltip += QString("\n%1 (%2)").arg(trUtf8("Partitioned")).arg(~table->getPartitioningType()); if(table->isPartition()) table_tooltip += QString("\n%1 of %2").arg(trUtf8("Partition")).arg(table->getPartitionedTable()->getSignature(true)); if(!table->getAlias().isEmpty()) table_tooltip += QString("\nAlias: %1").arg(table->getAlias()); if(!table->getComment().isEmpty()) table_tooltip += QString("\n---\n%1").arg(table->getComment()); BaseObjectView::__configureObject(); configureTag(); configureSQLDisabledInfo(); if((old_width!=0 && this->bounding_rect.width()!=old_width) || (old_height!=0 && this->bounding_rect.height()!=old_height)) emit s_objectDimensionChanged(); else requestRelationshipsUpdate(); } QPointF TableView::getConnectionPoints(TableObject *tab_obj, unsigned pnt_type) { if(!tab_obj) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(pnt_type > RightConnPoint) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(conn_points.count(tab_obj)==0) //Returns the center point in case of the connection point of the table object wasn't calculated already return(this->getCenter()); return(conn_points[tab_obj][pnt_type]); } pgmodeler-0.9.2/libobjrenderer/src/tableview.h000066400000000000000000000023761360462764600214400ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class TableView \brief Implements the graphical representation for tables. */ #ifndef TABLE_VIEW_H #define TABLE_VIEW_H #include "physicaltable.h" #include "basetableview.h" #include "tabletitleview.h" #include "tableobjectview.h" class TableView: public BaseTableView { private: Q_OBJECT map> conn_points; public: TableView(PhysicalTable *table); QPointF getConnectionPoints(TableObject *tab_obj, unsigned pnt_type); private slots: void configureObject(void); }; #endif pgmodeler-0.9.2/libobjrenderer/src/textboxview.cpp000066400000000000000000000104721360462764600223750ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "textboxview.h" #include "roundedrectitem.h" TextboxView::TextboxView(Textbox *txtbox, bool override_style) : BaseObjectView(txtbox) { connect(txtbox, SIGNAL(s_objectModified(void)), this, SLOT(configureObject(void))); box=new QGraphicsPolygonItem; text=new QGraphicsSimpleTextItem; text_item = new TextPolygonItem; this->addToGroup(text_item); obj_shadow=new QGraphicsPolygonItem; obj_shadow->setZValue(-1); this->addToGroup(obj_shadow); obj_selection=new QGraphicsPolygonItem; obj_selection->setVisible(false); obj_selection->setZValue(4); this->addToGroup(obj_selection); this->override_style=override_style; this->configureObject(); } TextboxView::~TextboxView(void) { this->removeFromGroup(text_item); delete(text_item); } void TextboxView::setColorStyle(const QBrush &fill_style, const QPen &border_style) { if(override_style) { text_item->setBrush(fill_style); text_item->setPen(border_style); } } void TextboxView::setFontStyle(const QTextCharFormat &fmt) { if(override_style) { text_item->setFont(fmt.font()); text_item->setTextBrush(fmt.foreground()); } } void TextboxView::setToolTip(const QString &tooltip) { txtbox_tooltip = tooltip; } void TextboxView::__configureObject(void) { Textbox *txtbox=dynamic_cast(this->getUnderlyingObject()); QTextCharFormat fmt=font_config[Attributes::Global]; QPolygonF polygon; polygon.append(QPointF(0.0,0.0)); polygon.append(QPointF(1.0,0.0)); polygon.append(QPointF(1.0,1.0)); polygon.append(QPointF(0.0,1.0)); if(!override_style) { QFont font; text_item->setBrush(this->getFillStyle(BaseObject::getSchemaName(ObjectType::Textbox))); text_item->setPen(this->getBorderStyle(BaseObject::getSchemaName(ObjectType::Textbox))); font=fmt.font(); font.setItalic(txtbox->getTextAttribute(Textbox::ItalicText)); font.setBold(txtbox->getTextAttribute(Textbox::BoldText)); font.setUnderline(txtbox->getTextAttribute(Textbox::UnderlineText)); font.setPointSizeF(txtbox->getFontSize()); text_item->setFont(font); text_item->setTextBrush(txtbox->getTextColor()); } text_item->setText(txtbox->getComment()); text_item->setTextPos(HorizSpacing * 2, VertSpacing * (text_item->getFont().italic() ? 0.90 : 0.50)); TextPolygonItem::resizePolygon(polygon, round(text_item->getTextBoundingRect().width() + (2.5 * HorizSpacing)), round(text_item->getTextBoundingRect().height() + (1.5 * VertSpacing))); text_item->setPos(0,0); text_item->setPolygon(polygon); protected_icon->setPos(text_item->boundingRect().width() + 2 * HorizSpacing, text_item->boundingRect().height() * 0.70); this->bounding_rect.setTopLeft(text_item->boundingRect().topLeft()); this->bounding_rect.setBottomRight(text_item->boundingRect().bottomRight()); BaseObjectView::__configureObject(); if(!txtbox_tooltip.isEmpty()) this->BaseObjectView::setToolTip(txtbox_tooltip); } void TextboxView::configureObject(void) { this->__configureObject(); this->configureObjectShadow(); this->configureObjectSelection(); } void TextboxView::configureObjectShadow(void) { QGraphicsPolygonItem *pol_item=dynamic_cast(obj_shadow); pol_item->setPen(Qt::NoPen); pol_item->setBrush(QColor(50,50,50,60)); pol_item->setPolygon(text_item->polygon()); pol_item->setPos(3.5,3.5); } void TextboxView::configureObjectSelection(void) { QGraphicsPolygonItem *pol_item=dynamic_cast(obj_selection); pol_item->setPolygon(text_item->polygon()); pol_item->setPos(0,0); pol_item->setBrush(this->getFillStyle(Attributes::ObjSelection)); pol_item->setPen(this->getBorderStyle(Attributes::ObjSelection)); } pgmodeler-0.9.2/libobjrenderer/src/textboxview.h000066400000000000000000000044301360462764600220370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class TextboxView \brief Represents the textbox in a graphical way on the object scene */ #ifndef TEXTBOX_VIEW_H #define TEXTBOX_VIEW_H #include "textbox.h" #include "baseobjectview.h" #include "roundedrectitem.h" #include "textpolygonitem.h" class TextboxView: public BaseObjectView { private: Q_OBJECT //! \brief Indicates the the font / color styles will be overriden (need to call setColorStyle, setFontStyle) bool override_style; QString txtbox_tooltip; protected: //! \brief Graphical item that represent the box QGraphicsPolygonItem *box; //! \brief Graphical item that represent the text QGraphicsSimpleTextItem *text; TextPolygonItem *text_item; //! \brief Configures the shadow for the textbox void configureObjectShadow(void); //! \brief Configures the selection for the textbox void configureObjectSelection(void); //! \brief Configures the basic attributes for textbox void __configureObject(void); public: TextboxView(Textbox *txtbox, bool override_style=false); virtual ~TextboxView(void); /*! \brief Sets the fill and border color for the text box. This method has effect only when the style can be overriden (via constructor) */ void setColorStyle(const QBrush &fill_style, const QPen &border_style); /*! \brief Sets the font style for the text box. This method has effect only when the style can be overriden (via constructor) */ void setFontStyle(const QTextCharFormat &fmt); void setToolTip(const QString &tooltip); protected slots: virtual void configureObject(void); }; #endif pgmodeler-0.9.2/libobjrenderer/src/textpolygonitem.cpp000066400000000000000000000044301360462764600232550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "textpolygonitem.h" TextPolygonItem::TextPolygonItem(QGraphicsItem *parent) : QGraphicsPolygonItem(parent) { text_item = new QGraphicsSimpleTextItem; } TextPolygonItem::~TextPolygonItem(void) { delete(text_item); } void TextPolygonItem::setText(const QString &text) { text_item->setText(text); } void TextPolygonItem::setTextPen(const QPen &pen) { text_item->setPen(pen); } void TextPolygonItem::setTextBrush(const QBrush &brush) { text_item->setBrush(brush); } QRectF TextPolygonItem::getTextBoundingRect(void) { return(text_item->boundingRect()); } void TextPolygonItem::setTextPos(const QPointF &pos) { text_item->setPos(pos); } void TextPolygonItem::setTextPos(double x, double y) { text_item->setPos(x, y); } void TextPolygonItem::setFont(const QFont &fnt) { text_item->setFont(fnt); } QFont TextPolygonItem::getFont() { return(text_item->font()); } void TextPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QGraphicsPolygonItem::paint(painter, option, widget); painter->translate(text_item->pos()); text_item->paint(painter, option, widget); } void TextPolygonItem::resizePolygon(QPolygonF &pol, double width, double height) { QVector::iterator itr,itr_end; double coef_a, coef_b; itr=pol.begin(); itr_end=pol.end(); //Calculates the resize factor coef_a=width / pol.boundingRect().width(); coef_b=height / pol.boundingRect().height(); //Applies the resize factor to all the polygon points while(itr!=itr_end) { itr->setX(itr->x() * coef_a); itr->setY(itr->y() * coef_b); itr++; } } pgmodeler-0.9.2/libobjrenderer/src/textpolygonitem.h000066400000000000000000000041271360462764600227250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libobjrenderer \class TextPolygonItem \brief This specialization of QGraphicsPolygonItem allows a text to be drawn over a polygonal element */ #ifndef TEXT_POLYGON_ITEM_H #define TEXT_POLYGON_ITEM_H #include #include #include #include class TextPolygonItem : public QGraphicsPolygonItem { private: QGraphicsSimpleTextItem *text_item; public: TextPolygonItem(QGraphicsItem *parent = nullptr); ~TextPolygonItem(void); //! \brief Defines the text displayed by the item void setText(const QString &text); //! \brief Defines the position of the text element (in local coordinate) void setTextPos(const QPointF &pos); void setTextPos(double x, double y); //! \brief Defines the pen used by the text element void setTextPen(const QPen &pen); //! \brief Defines the brush used by the text element void setTextBrush(const QBrush &brush); //! \brief Returns the bounding rect of the text item QRectF getTextBoundingRect(void); //! \brief Sets the font used by the text item void setFont(const QFont &fnt); QFont getFont(void); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr); //! \brief Resizes to the specified dimension the passed polygon static void resizePolygon(QPolygonF &pol, double width, double height); }; #endif pgmodeler-0.9.2/libparsers/000077500000000000000000000000001360462764600156645ustar00rootroot00000000000000pgmodeler-0.9.2/libparsers/libparsers.pro000066400000000000000000000016051360462764600205560ustar00rootroot00000000000000# libparsers.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = lib TARGET = parsers windows: DESTDIR = $$PWD HEADERS += src/schemaparser.h \ src/xmlparser.h \ src/attribsmap.h \ src/attributes.h SOURCES += src/schemaparser.cpp \ src/xmlparser.cpp \ src/attributes.cpp unix|windows: LIBS += -L$$OUT_PWD/../libutils/ -lutils $$XML_LIB INCLUDEPATH += $$PWD/../libutils/src DEPENDPATH += $$PWD/../libutils # Deployment settings target.path = $$PRIVATELIBDIR INSTALLS = target pgmodeler-0.9.2/libparsers/src/000077500000000000000000000000001360462764600164535ustar00rootroot00000000000000pgmodeler-0.9.2/libparsers/src/attribsmap.h000066400000000000000000000021101360462764600207640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libparsers \typedef attribs_map \brief This typedef is used to replace maps with the signature map commonly used to store objects attributes and used by SchemaParser, XMLParser and several other classes */ #ifndef ATTRIBSMAP_H #define ATTRIBSMAP_H #include #include using attribs_map = std::map; #endif pgmodeler-0.9.2/libparsers/src/attributes.cpp000066400000000000000000000541401360462764600213510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful), # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also), you can get the complete GNU General Public License at */ #include "attributes.h" namespace Attributes { const QString ActiveLayers=QString("active-layers"), AdminOption=QString("admin-option"), AdminRoles=QString("admin-roles"), Alias=QString("alias"), Alignment=QString("alignment"), AlignObjsToGrid=QString("align-objs-to-grid"), AllowConns=QString("allow-conns"), AlterCmds=QString("alter-cmds"), AnalyzeFunc=QString("analyze"), AncestorTable=QString("ancestor-table"), AppendAtEod=QString("append-at-eod"), AppendedSql=QString("appended-sql"), Application=QString("application"), ApplyOnServer="apply-on-server", ArgCount=QString("arg-count"), ArgDefaults=QString("arg-defaults"), ArgDefCount=QString("arg-def-count"), ArgModes=QString("arg-modes"), ArgNames=QString("arg-names"), ArgTypes=QString("arg-types"), Arguments=QString("arguments"), AscOrder=QString("asc-order"), Assignment=QString("assignment"), AttribsPage=QString("attribs-page"), AttribsPerPage=QString("attribs-per-page"), Attribute=QString("attribute"), AutoBrowseDb=QString("auto-browse-db"), AutoSaveInterval=QString("autosave-interval"), BackgroundColor=QString("background-color"), BaseType=QString("base"), Before=QString("before"), BehaviorType=QString("behavior-type"), Bold=QString("bold"), BorderColor=QString("border-color"), Bottom=QString("bottom"), Buffering=QString("buffering"), BypassRls=QString("bypassrls"), ByValue=QString("by-value"), Cache=QString("cache"), CanonicalFunc=QString("canonical"), CanvasCornerMove=QString("canvas-corner-move"), Cascade=QString("cascade"), CaseSensitive=QString("case-sensitive"), CastType=QString("cast-type"), Category=QString("category"), Change=QString("change"), Changelog=QString("changelog"), CheckExp=QString("check-exp"), CheckUpdate=QString("check-update"), CkConstr=QString("ck-constr"), ClientEncoding=QString("client-encoding"), CodeCompletion=QString("code-completion"), CodeFont=QString("code-font"), CodeFontSize=QString("code-font-size"), CodeTabWidth=QString("code-tab-width"), ColIndexes=QString("col-indexes"), ColIsIdentity=QString("col-is-identity"), CollapseMode=QString("collapse-mode"), Collatable=QString("collatable"), Collation=QString("collation"), Collations=QString("collations"), Color=QString("color"), Colors=QString("colors"), ColsComment=QString("cols-comment"), Column=QString("column"), ColumnAlias=QString("column-alias"), Columns=QString("columns"), Command=QString("command"), Commands=QString("commands"), Comment=QString("comment"), CommutatorOp=QString("commutator-op"), CompactView=QString("compact-view"), CompareToDatabase="compare-to-db", ComparisonType=QString("comparison-type"), CompletionTrigger=QString("completion-trigger"), CompositeType=QString("composite"), Concurrent=QString("concurrent"), Condition=QString("condition"), ConfigFile=QString("config-file"), Configuration=QString("configuration"), ConfirmValidation=QString("confirm-validation"), ConnectCenterPnts=QString("center-pnts"), ConnectFkToPk=QString("fk-to-pk"), Connection=QString("connection"), Connections=QString("connections"), ConnectionTimeout=QString("connection-timeout"), ConnectPriv=QString("connect"), ConnectTableEdges=QString("table-edges"), ConnLimit=QString("connlimit"), Constraint=QString("constraint"), Constraints=QString("constraints"), ConstrDefs=QString("constr-defs"), ConstrIndexes=QString("constr-indexes"), ConstrSqlDisabled=QString("constr-sql-disabled"), Contents=QString("contents"), CopyMode=QString("copy-mode"), CopyOptions=QString("copy-options"), CopyTable=QString("copy-table"), Create=QString("create"), CreateCmds=QString("create-cmds"), CreateDb=QString("createdb"), CreatePriv=QString("create"), CreateRole=QString("createrole"), CrowsFoot=QString("crows-foot"), CteExpression=QString("cte-exp"), CurIdentityType=QString("cur-identity-type"), CurrentModel="current-model", CurVersion=QString("cur-version"), CustomColor=QString("custom-color"), CustomFilter=QString("custom-filter"), CustomIdxs=QString("customidxs"), Cycle=QString("cycle"), Database=QString("database"), DataDirectory=QString("data-directory"), Date=QString("date"), DbModel=QString("dbmodel"), DdlEndToken=QString("-- ddl-end --"), DeadRowsAmount=QString("dead-rows-amount"), Declaration=QString("declaration"), DeclInTable=QString("decl-in-table"), Default=QString("default"), DefaultCollation=QString("default-collation"), DefaultForOps=QString("default-for-ops"), DefaultOwner=QString("default-owner"), DefaultSchema=QString("default-schema"), DefaultTablespace=QString("default-tablespace"), DefaultValue=QString("default-value"), Deferrable=QString("deferrable"), DeferType=QString("defer-type"), Definition=QString("definition"), DelAction=QString("del-action"), DeletePriv=QString("delete"), DelEvent=QString("del-event"), Delimiter=QString("delimiter"), DestType=QString("destiny-type"), Diff=QString("diff"), Dimension=QString("dimension"), Directory=QString("directory"), DisableSmoothness=QString("disable-smoothness"), DisplayLineNumbers=QString("display-line-numbers"), DockWidgets=QString("dock-widgets"), DomConstraint=QString("domconstraint"), DontDropMissingObjs="dont-drop-missing-objs", Drop=QString("drop"), DropCmds=QString("drop-cmds"), DropMissingColsConstrs="drop-missing-cols-constrs", DropTruncCascade="drop-trunc-cascade", DstColPattern=QString("dst-col-pattern"), DstColumns=QString("dst-columns"), DstEncoding=QString("dst-encoding"), DstFkPattern=QString("dst-fk-pattern"), DstLabel=QString("dst-label"), DstRequired=QString("dst-required"), DstTable=QString("dst-table"), DstType=QString("dst-type"), DynamicLibraryPath=QString("dynamic-library-path"), DynamicSharedMemory=QString("dynamic-shared-memory-type"), Element=QString("element"), Elements=QString("elements"), EmptyPassword=QString("empty-password"), Encoding=QString("encoding"), Encrypted=QString("encrypted"), EndExp=QString("end-exp"), Enumerations=QString("enumerations"), EnumType=QString("enumeration"), EscapeComment=QString("escape-comment"), Event=QString("event"), Events=QString("events"), EventType=QString("event-type"), ExactMatch=QString("exact-match"), ExcBuiltinArrays=QString("exc-builtin-arrays"), ExcludeElement=QString("excelement"), ExConstr=QString("ex-constr"), ExecType=QString("exec-type"), ExecutionCost=QString("execution-cost"), ExecutPriv=QString("execute"), ExistingValue=QString("existing-value"), Explicit=QString("explicit"), Export=QString("export"), ExportToFile=QString("export-to-file"), Expression=QString("expression"), Expressions=QString("expressions"), ExtAttribsPage=QString("ext-attribs-page"), ExtAttribsPerPage=QString("ext-attribs-per-page"), ExtObjOids=QString("ext-obj-oids"), Factor=QString("factor"), FadedOut=QString("faded-out"), FadeInObjects=QString("fadein-objects"), False=QString("false"), Family=QString("family"), FastUpdate=QString("fast-update"), Fdw=QString("fdw"), File=QString("file"), FileAssociated=QString("file-associated"), FillColor=QString("fill-color"), Filter=QString("filter"), FilterOids=QString("filter-oids"), FilterTableTypes=QString("filter-tab-types"), FinalFunc=QString("final"), FiringType=QString("firing-type"), FkColumn=QString("fk-column"), FkConstr=QString("fk-constr"), FkDefs=QString("fk-defs"), Font=QString("font"), FontSize=QString("font-size"), ForceObjsRecreation="force-objs-recreation", ForegroundColor=QString("foreground-color"), ForeignKeys=QString("foreign-keys"), ForeignTableBody=QString("foreigntable-body"), ForeignTableExtBody=QString("foreigntable-ext-body"), ForeignTableName=QString("foreigntable-name"), ForeignTableSchemaName=QString("foreigntable-schema-name"), ForeignTableTitle=QString("foreigntable-title"), FormatName=QString("format-name"), FromExp=QString("from-exp"), Function=QString("function"), FunctionType=QString("function-type"), GenAlterCmds=QString("gen-alter-cmds"), General=QString("general"), Global=QString("global"), GrantOp=QString("grant-op"), GridSize=QString("grid-size"), Group=QString("group"), HandlerFunc=QString("handler"), HandlesType=QString("handles-type"), HasChanges=QString("has-changes"), Hashes=QString("hashes"), HbaFile=QString("hba-file"), Height=QString("height"), HideExtAttribs=QString("hide-ext-attribs"), HideRelName=QString("hide-rel-name"), HideTableTags=QString("hide-table-tags"), HighlightLines=QString("highlight-lines"), HighlightOrder=QString("highlight-order"), HistoryMaxLength=QString("history-max-length"), Icon=QString("icon"), Id=QString("id"), IdentFile=QString("ident-file"), Identifier=QString("identifier"), IdentityType=QString("identity-type"), IgnoredChars=QString("ignored-chars"), IgnoreDuplicErrors="ignore-duplic-errors", IgnoreErrorCodes="ignore-error-codes", IgnoreImportErrors="ignore-import-errors", Implicit=QString("implicit"), Import=QString("import"), ImportExtObjs="import-ext-objs", ImportSysObjs="import-sys-objs", Increment=QString("increment"), Index=QString("index"), IndexElement=QString("idxelement"), Indexes=QString("indexes"), IndexType=QString("index-type"), Info=QString("info"), InhColumn=QString("inh-column"), InhColumns=QString("inh-columns"), Inherit=QString("inherit"), Inherited=QString("inherited"), InitialCond=QString("initial-cond"), InitialData=QString("initial-data"), InitialExp=QString("initial-exp"), InlineFunc=QString("inline"), InputDatabase="input-db", InputFunc=QString("input"), InsertPriv=QString("insert"), InsEvent=QString("ins-event"), InternalLength=QString("internal-length"), IntervalType=QString("interval-type"), InvertRangeSelTrigger=QString("invert-rangesel-trigger"), IoCast=QString("io-cast"), IsPartitioned=QString("is-partitioned"), IsTemplate=QString("is-template"), Italic=QString("italic"), Item=QString("item"), Items=QString("items"), JoinFunc=QString("join"), KeepClusterObjs="keep-cluster-objs", KeepObjsPerms="keep-objs-perms", Label=QString("label"), LabelsPos=QString("labels-pos"), Landscape=QString("landscape"), Language=QString("language"), LastAnalyze=QString("last-analyze"), LastAutovacuum=QString("last-autovacuum"), LastPosition=QString("last-position"), LastSysOid=QString("last-sys-oid"), LastVacuum=QString("last-vacuum"), LastValue=QString("last-value"), LastZoom=QString("last-zoom"), Layer=QString("layer"), Layers=QString("layers"), LcCollate=QString("lc-collate"), LcCtype=QString("lc-ctype"), LeakProof=QString("leakproof"), Left=QString("left"), LeftType=QString("left-type"), Length=QString("length"), Library=QString("library"), LikeType=QString("like-type"), Line=QString("line"), LineHighlightColor=QString("line-highlight-color"), LineNumbersBgColor=QString("line-numbers-bg-color"), LineNumbersColor=QString("line-numbers-color"), Link=QString("link"), ListenAddresses=QString("listen-addresses"), Locale=QString("locale"), LockerArc=QString("locker-arc"), LockerBody=QString("locker-body"), Login=QString("login"), LookaheadChar=QString("lookahead-char"), LowVerbosity=QString("low-verbosity"), Materialized=QString("materialized"), MaxConnections=QString("max-connections"), Maximized=QString("maximized"), MaxObjCount=QString("max-obj-count"), MaxValue=QString("max-value"), Member=QString("member"), MemberRoles=QString("member-roles"), Merges=QString("merges"), Metadata=QString("metadata"), MinObjectOpacity=QString("min-object-opacity"), MinValue=QString("min-value"), Mode=QString("mode"), ModelAuthor=QString("author"), Name=QString("name"), NameLabel=QString("name-label"), NamePatterns=QString("name-patterns"), Names=QString("names"), NegatorOp=QString("negator-op"), NewIdentityType=QString("new-identity-type"), NewName=QString("new-name"), NewTableName=QString("new-table-name"), NewVersion=QString("new-version"), Next=QString("next"), NnColumn=QString("nn-column"), NoInherit=QString("no-inherit"), None=QString("none"), NotExtObject=QString("not-ext-object"), NotNull=QString("not-null"), NullsFirst=QString("nulls-first"), Object=QString("object"), ObjectFinder=QString("objectfinder"), ObjectId=QString("object-id"), Objects=QString("objects"), ObjectType=QString("object-type"), ObjSelection=QString("obj-selection"), Oid=QString("oid"), OidFilterOp=QString("oid-filter-op"), Oids=QString("oids"), OldName=QString("old-name"), OldTableName=QString("old-table-name"), OldVersion=QString("old-version"), OpClass=QString("opclass"), OpClasses=QString("opclasses"), Operator=QString("operator"), OperatorFunc=QString("operfunc"), Operators=QString("operators"), OpFamily=QString("opfamily"), OpListSize=QString("op-list-size"), Options=QString("options"), OriginalPk=QString("original-pk"), OutputFunc=QString("output"), Owner=QString("owner"), OwnerColumn=QString("owner-col"), Pagination=QString("pagination"), PaperCustomSize=QString("paper-custom-size"), PaperMargin=QString("paper-margin"), PaperOrientation=QString("paper-orientation"), PaperType=QString("paper-type"), Parameter=QString("parameter"), Parameters=QString("parameters"), ParamIn=QString("in"), ParamOut=QString("out"), ParamVariadic=QString("variadic"), Parent=QString("parent"), Parents=QString("parents"), Parsable=QString("parsable"), PartialMatch=QString("partial-match"), PartitionBoundExpr=QString("partition-bound-expr"), PartitionedTable=QString("partitioned-table"), PartitionTables=QString("partition-tables"), Partitioning=QString("partitioning"), PartitionKey=QString("partitionkey"), PartKeyColls=QString("part-key-colls"), PartKeyCols=QString("part-key-cols"), PartKeyExprs=QString("part-key-exprs"), PartKeyOpCls=QString("part-key-opcls"), Password=QString("password"), PasswordEncryption=QString("password-encryption"), Path=QString("path"), Patterns=QString("patterns"), Permission=QString("permission"), Permissive=QString("permissive"), PerRow=QString("per-line"), PgModelerVersion=QString("pgmodeler-ver"), PgSqlBaseType=QString("basetype"), PgSqlVersion=QString("pgsql-ver"), PkColPattern=QString("pk-col-pattern"), PkColumn=QString("pk-column"), PkConstr=QString("pk-constr"), PkPattern=QString("pk-pattern"), Placeholder=QString("placeholder"), Placeholders=QString("placeholders"), Points=QString("points"), Port=QString("port"), Portrait=QString("portrait"), Position=QString("position"), PositionInfo=QString("pos-info"), Precision=QString("precision"), Predicate=QString("predicate"), Preferred=QString("preferred"), PrependAtBod=QString("prepend-at-bod"), PrependedSql=QString("prepended-sql"), PreserveDbName=QString("preserve-db-name"), Preset=QString("preset"), Previous=QString("previous"), PrintGrid=QString("print-grid"), PrintPgNum=QString("print-pg-num"), Privileges=QString("privileges"), PrivilegesGop=QString("privileges-gop"), ProtColumn=QString("prot-column"), Protected=QString("protected"), RangeAttribs=QString("range-attribs"), RangeType=QString("range"), Recent=QString("recent"), RecentModels=QString("recent-models"), RecreateUnmodObjs="recreate-unmod-objs", RectVisible=QString("rect-visible"), Recursive=QString("recursive"), RecvFunc=QString("receive"), ReducedForm=QString("reduced-form"), RefAlias=QString("ref-alias"), RefColumn=QString("ref-column"), Refer=QString("refer"), Reference=QString("reference"), ReferenceFk=QString("reference-fk"), References=QString("references"), ReferencesPriv=QString("references"), Referrers=QString("referrers"), RefName=QString("ref-name"), RefRoles=QString("ref-roles"), RefTable=QString("ref-table"), RefTables=QString("ref-tables"), RefTableTag=QString("reftable"), RefType=QString("ref-type"), RegularExp=QString("regexp"), Relationship=QString("relationship"), Relationship11=QString("rel11"), Relationship1n=QString("rel1n"), RelationshipDep=QString("reldep"), RelationshipFk=QString("relfk"), RelationshipGen=QString("relgen"), RelationshipNn=QString("relnn"), RelationshipPart=QString("relpart"), RelationshipTabView=QString("reltv"), Rename=QString("rename"), Replication=QString("replication"), RestartSeq=QString("restart-seq"), RestrictionFunc=QString("restriction"), ReturnsSetOf=QString("returns-setof"), ReturnTable=QString("return-table"), ReturnType=QString("return-type"), ReuseSequences=QString("reuse-sequences"), Revoke=QString("revoke"), Right=QString("right"), RightType=QString("right-type"), RlsEnabled=QString("rls-enabled"), RlsForced=QString("rls-forced"), Role=QString("role"), Roles=QString("roles"), RoleType=QString("role-type"), RowAmount=QString("row-amount"), Rules=QString("rules"), SaveLastPosition=QString("save-last-position"), SaveRestoreGeometry=QString("save-restore-geometry"), Schema=QString("schema"), SchemaOid=QString("schema-oid"), SearchPath=QString("search-path"), SecurityType=QString("security-type"), SelectExp=QString("select-exp"), SelectObjects=QString("select-objects"), SelectPriv=QString("select"), SendFunc=QString("send"), Sequence=QString("sequence"), Server=QString("server"), ServerEncoding=QString("server-encoding"), ServerPid=QString("server-pid"), ServerProtocol=QString("server-protocol"), ServerVersion=QString("server-version"), SetPerms=QString("set-perms"), SharedObj=QString("shared-obj"), ShellTypes=QString("shell-types"), ShowAttributesGrid=QString("show-attributes-grid"), ShowCanvasGrid=QString("show-canvas-grid"), ShowMainMenu=QString("show-main-menu"), ShowPageDelimiters=QString("show-page-delimiters"), ShowSourcePane=QString("show-source-pane"), Signature=QString("signature"), SimpleExp=QString("simple-exp"), SimplifiedObjCreation=QString("simplified-obj-creation"), SinglePkColumn=QString("single-pk-col"), Size=QString("size"), Snippet=QString("snippet"), SortOp=QString("sort-op"), SourceEditorApp=QString("source-editor-app"), SourceEditorArgs=QString("source-editor-args"), SourceType=QString("source-type"), SpatialType=QString("spatial-type"), SpecialPkCols=QString("special-pk-cols"), Splitted=QString("splitted"), SqlDisabled=QString("sql-disabled"), SqlObject=QString("sql-object"), SqlTool=QString("sqltool"), SqlValidation=QString("sql-validation"), SrcColPattern=QString("src-col-pattern"), SrcColumns=QString("src-columns"), SrcEncoding=QString("src-encoding"), SrcFkPattern=QString("src-fk-pattern"), SrcLabel=QString("src-label"), SrcRequired=QString("src-required"), SrcTable=QString("src-table"), SrcType=QString("src-type"), Srid=QString("srid"), Ssl=QString("ssl"), SslCaFile=QString("ssl-ca-file"), SslCertFile=QString("ssl-cert-file"), SslCrlFile=QString("ssl-crl-file"), SslKeyFile=QString("ssl-key-file"), Start=QString("start"), StateType=QString("state-type"), Storage=QString("storage"), StorageParams=QString("stg-params"), StoreInFile="store-in-file", StrategyNum=QString("stg-number"), Style=QString("style"), Styles=QString("styles"), Subtype=QString("subtype"), SubtypeDiffFunc=QString("subtypediff"), Superuser=QString("superuser"), Symbol=QString("symbol"), Table=QString("table"), TableBody=QString("table-body"), TableExtBody=QString("table-ext-body"), TableName=QString("table-name"), TableObject=QString("table-obj"), TableSchemaName=QString("table-schema-name"), Tablespace=QString("tablespace"), TableTitle=QString("table-title"), TableType=QString("table-type"), Tag=QString("tag"), TemplateDb=QString("template"), TemporaryPriv=QString("temporary"), Top=QString("top"), TpmodInFunc=QString("tpmodin"), TpmodOutFunc=QString("tpmodout"), TransitionFunc=QString("transition"), TriggerFunc=QString("trigger-func"), TriggerPriv=QString("trigger"), Triggers=QString("triggers"), True=QString("true"), Truncate=QString("truncate"), TruncateCmds=QString("truncate-cmds"), TruncatePriv=QString("truncate"), TruncColsBeforeAlter="trunc-cols-before-alter", TruncEvent=QString("trunc-event"), Trusted=QString("trusted"), TuplesDel=QString("tuples-del"), TuplesIns=QString("tuples-ins"), Type=QString("type"), TypeAttribute=QString("typeattrib"), TypeClass=QString("type-class"), TypeOid=QString("type-oid"), Types=QString("types"), TyplesUpd=QString("tuples-upd"), UiLanguage=QString("ui-language"), Underline=QString("underline"), Unique=QString("unique"), Unlogged=QString("unlogged"), Unset=QString("unset"), UnsetPerms=QString("unset-perms"), UpdAction=QString("upd-action"), UpdatePriv=QString("update"), UpdEvent=QString("upd-event"), UqColumn=QString("uq-column"), UqConstr=QString("uq-constr"), UqPattern=QString("uq-pattern"), UsagePriv=QString("usage"), UseCurvedLines=QString("use-curved-lines"), UsePlaceholders=QString("use-placeholders"), UseSignature=QString("use-signature"), UseSorting=QString("use-sorting"), UseUniqueNames=QString("use-unique-names"), UsingExp=QString("using-exp"), Validation=QString("validation"), Validator=QString("validator"), ValidatorFunc=QString("validator"), Validity=QString("validity"), Value=QString("value"), Values=QString("values"), Variable=QString("variable"), Variation=QString("variation"), Version=QString("version"), ViewBody=QString("view-body"), ViewExtBody=QString("view-ext-body"), ViewName=QString("view-name"), ViewSchemaName=QString("view-schema-name"), ViewTitle=QString("view-title"), Visible=QString("visible"), Widget=QString("widget"), WidgetsGeometry=QString("widgets-geometry"), Width=QString("width"), Wildcard=QString("wildcard"), WindowFunc=QString("window-func"), WithNoData=QString("with-no-data"), WithoutOids=QString("without-oids"), WithTimezone=QString("with-timezone"), WordDelimiters=QString("word-delimiters"), WordSeparators=QString("word-separators"), WorkingDir=QString("working-dir"), XPos=QString("x"), YPos=QString("y"); } pgmodeler-0.9.2/libparsers/src/attributes.h000066400000000000000000000224511360462764600210160ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful), # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also), you can get the complete GNU General Public License at */ /** \ingroup libparsers \namespace Attributes \brief Definition of parsers attributes namespace which stores a series of static strings constants used to reference the attributes of objects in SQL/XML generation methods. Each string stores the name of the attribute used in the schema file "sch" of the respective objects. \note Creation date: 23/09/2008 */ #ifndef ATTRIBUTES_H #define ATTRIBUTES_H /* Including QByteArray due to 'QByteArray has no toStdString()' error on Qt 5.4 (Windows only) */ #include #include namespace Attributes { extern const QString ActiveLayers, AdminOption, AdminRoles, Alias, Alignment, AlignObjsToGrid, AllowConns, AlterCmds, AnalyzeFunc, AncestorTable, AppendAtEod, AppendedSql, Application, ApplyOnServer, ArgCount, ArgDefaults, ArgDefCount, ArgModes, ArgNames, ArgTypes, Arguments, AscOrder, Assignment, AttribsPage, AttribsPerPage, Attribute, AutoBrowseDb, AutoSaveInterval, BackgroundColor, BaseType, Before, BehaviorType, Bold, BorderColor, Bottom, Buffering, BypassRls, ByValue, Cache, CanonicalFunc, CanvasCornerMove, Cascade, CaseSensitive, CastType, Category, Change, Changelog, CheckExp, CheckUpdate, CkConstr, ClientEncoding, CodeCompletion, CodeFont, CodeFontSize, CodeTabWidth, ColIndexes, ColIsIdentity, CollapseMode, Collatable, Collation, Collations, Color, Colors, ColsComment, Column, ColumnAlias, Columns, Command, Commands, Comment, CommutatorOp, CompactView, CompareToDatabase, ComparisonType, CompletionTrigger, CompositeType, Concurrent, Condition, ConfigFile, Configuration, ConfirmValidation, ConnectCenterPnts, ConnectFkToPk, Connection, Connections, ConnectionTimeout, ConnectPriv, ConnectTableEdges, ConnLimit, Constraint, Constraints, ConstrDefs, ConstrIndexes, ConstrSqlDisabled, Contents, CopyMode, CopyOptions, CopyTable, Create, CreateCmds, CreateDb, CreatePriv, CreateRole, CrowsFoot, CteExpression, CurIdentityType, CurrentModel, CurrentModel, CurVersion, CustomColor, CustomFilter, CustomIdxs, Cycle, Database, DataDirectory, Date, DbModel, DdlEndToken, DeadRowsAmount, Declaration, DeclInTable, Default, DefaultCollation, DefaultForOps, DefaultOwner, DefaultSchema, DefaultTablespace, DefaultValue, Deferrable, DeferType, Definition, DelAction, DeletePriv, DelEvent, Delimiter, DestType, Diff, Dimension, Directory, DisableSmoothness, DisplayLineNumbers, DockWidgets, DomConstraint, DontDropMissingObjs, Drop, DropCmds, DropMissingColsConstrs, DropTruncCascade, DstColPattern, DstColumns, DstEncoding, DstFkPattern, DstLabel, DstRequired, DstTable, DstType, DynamicLibraryPath, DynamicSharedMemory, Element, Elements, EmptyPassword, Encoding, Encrypted, EndExp, Enumerations, EnumType, EscapeComment, Event, Events, EventType, ExactMatch, ExcBuiltinArrays, ExcludeElement, ExConstr, ExecType, ExecutionCost, ExecutPriv, ExistingValue, Explicit, Export, ExportToFile, Expression, Expressions, ExtAttribsPage, ExtAttribsPerPage, ExtObjOids, Factor, FadedOut, FadeInObjects, False, Family, FastUpdate, Fdw, File, FileAssociated, FillColor, Filter, FilterOids, FilterTableTypes, FinalFunc, FiringType, FkColumn, FkConstr, FkDefs, Font, FontSize, ForceObjsRecreation, ForegroundColor, ForeignKeys, ForeignTableBody, ForeignTableExtBody, ForeignTableName, ForeignTableSchemaName, ForeignTableTitle, FormatName, FromExp, Function, FunctionType, GenAlterCmds, General, Global, GrantOp, GridSize, Group, HandlerFunc, HandlesType, HasChanges, Hashes, HbaFile, Height, HideExtAttribs, HideRelName, HideTableTags, HighlightLines, HighlightOrder, HistoryMaxLength, Icon, Id, IdentFile, Identifier, IdentityType, IgnoredChars, IgnoreDuplicErrors, IgnoreErrorCodes, IgnoreImportErrors, Implicit, Import, ImportExtObjs, ImportSysObjs, Increment, Index, IndexElement, Indexes, IndexType, Info, InhColumn, InhColumns, Inherit, Inherited, InitialCond, InitialData, InitialExp, InlineFunc, InputDatabase, InputDatabase, InputFunc, InsertPriv, InsEvent, InternalLength, IntervalType, InvertRangeSelTrigger, IoCast, IsPartitioned, IsTemplate, Italic, Item, Items, JoinFunc, KeepClusterObjs, KeepObjsPerms, Label, LabelsPos, Landscape, Language, LastAnalyze, LastAutovacuum, LastPosition, LastSysOid, LastVacuum, LastValue, LastZoom, Layer, Layers, LcCollate, LcCtype, LeakProof, Left, LeftType, Length, Library, LikeType, Line, LineHighlightColor, LineNumbersBgColor, LineNumbersColor, Link, ListenAddresses, Locale, LockerArc, LockerBody, Login, LookaheadChar, LowVerbosity, Materialized, MaxConnections, Maximized, MaxObjCount, MaxValue, Member, MemberRoles, Merges, Metadata, MinObjectOpacity, MinValue, Mode, ModelAuthor, Name, NameLabel, NamePatterns, Names, NegatorOp, NewIdentityType, NewName, NewTableName, NewVersion, Next, NnColumn, NoInherit, None, NotExtObject, NotNull, NullsFirst, Object, ObjectFinder, ObjectId, Objects, ObjectType, ObjSelection, Oid, OidFilterOp, Oids, OldName, OldTableName, OldVersion, OpClass, OpClasses, Operator, OperatorFunc, Operators, OpFamily, OpListSize, Options, OriginalPk, OutputFunc, Owner, OwnerColumn, Pagination, PaperCustomSize, PaperMargin, PaperOrientation, PaperType, Parameter, Parameters, ParamIn, ParamOut, ParamVariadic, Parent, Parents, Parsable, PartialMatch, PartitionBoundExpr, PartitionedTable, PartitionTables, Partitioning, PartitionKey, PartKeyColls, PartKeyCols, PartKeyExprs, PartKeyOpCls, Password, PasswordEncryption, Path, Patterns, Permission, Permissive, PerRow, PgModelerVersion, PgSqlBaseType, PgSqlVersion, PkColPattern, PkColumn, PkConstr, PkPattern, Placeholder, Placeholders, Points, Port, Portrait, Position, PositionInfo, Precision, Predicate, Preferred, PrependAtBod, PrependedSql, PreserveDbName, Preset, Preset, Previous, PrintGrid, PrintPgNum, Privileges, PrivilegesGop, ProtColumn, Protected, RangeAttribs, RangeType, Recent, RecentModels, RecreateUnmodObjs, RectVisible, Recursive, RecvFunc, ReducedForm, RefAlias, RefColumn, Refer, Reference, ReferenceFk, References, ReferencesPriv, Referrers, RefName, RefRoles, RefTable, RefTables, RefTableTag, RefType, RegularExp, Relationship, Relationship11, Relationship1n, RelationshipDep, RelationshipFk, RelationshipGen, RelationshipNn, RelationshipPart, RelationshipTabView, Rename, Replication, RestartSeq, RestrictionFunc, ReturnsSetOf, ReturnTable, ReturnType, ReuseSequences, Revoke, Right, RightType, RlsEnabled, RlsForced, Role, Roles, RoleType, RowAmount, Rules, SaveLastPosition, SaveRestoreGeometry, Schema, SchemaOid, SearchPath, SecurityType, SelectExp, SelectObjects, SelectPriv, SendFunc, Sequence, Server, ServerEncoding, ServerPid, ServerProtocol, ServerVersion, SetPerms, SharedObj, ShellTypes, ShowAttributesGrid, ShowCanvasGrid, ShowMainMenu, ShowPageDelimiters, ShowSourcePane, Signature, SimpleExp, SimplifiedObjCreation, SinglePkColumn, Size, Snippet, SortOp, SourceEditorApp, SourceEditorArgs, SourceType, SpatialType, SpecialPkCols, Splitted, SqlDisabled, SqlObject, SqlTool, SqlValidation, SrcColPattern, SrcColumns, SrcEncoding, SrcFkPattern, SrcLabel, SrcRequired, SrcTable, SrcType, Srid, Ssl, SslCaFile, SslCertFile, SslCrlFile, SslKeyFile, Start, StateType, Storage, StorageParams, StoreInFile, StrategyNum, Style, Styles, Subtype, SubtypeDiffFunc, Superuser, Symbol, Table, TableBody, TableExtBody, TableName, TableObject, TableSchemaName, Tablespace, TableTitle, TableType, Tag, TemplateDb, TemporaryPriv, Top, TpmodInFunc, TpmodOutFunc, TransitionFunc, TriggerFunc, TriggerPriv, Triggers, True, Truncate, TruncateCmds, TruncatePriv, TruncColsBeforeAlter, TruncEvent, Trusted, TuplesDel, TuplesIns, Type, TypeAttribute, TypeClass, TypeOid, Types, TyplesUpd, UiLanguage, Underline, Unique, Unlogged, Unset, UnsetPerms, UpdAction, UpdatePriv, UpdEvent, UqColumn, UqConstr, UqPattern, UsagePriv, UseCurvedLines, UsePlaceholders, UseSignature, UseSorting, UseUniqueNames, UsingExp, Validation, Validator, ValidatorFunc, Validity, Value, Values, Variable, Variation, Version, ViewBody, ViewExtBody, ViewName, ViewSchemaName, ViewTitle, Visible, Widget, WidgetsGeometry, Width, Wildcard, WindowFunc, WithNoData, WithoutOids, WithTimezone, WordDelimiters, WordSeparators, WorkingDir, XPos, YPos; } #endif pgmodeler-0.9.2/libparsers/src/schemaparser.cpp000066400000000000000000001263751360462764600216520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "schemaparser.h" #include "attributes.h" const char SchemaParser::CharComment='#'; const char SchemaParser::CharLineEnd='\n'; const char SchemaParser::CharTabulation='\t'; const char SchemaParser::CharSpace=' '; const char SchemaParser::CharIniAttribute='{'; const char SchemaParser::CharEndAttribute='}'; const char SchemaParser::CharIniConditional='%'; const char SchemaParser::CharIniMetachar='$'; const char SchemaParser::CharIniPlainText='['; const char SchemaParser::CharEndPlainText=']'; const char SchemaParser::CharIniCompExpr='('; const char SchemaParser::CharEndCompExpr=')'; const char SchemaParser::CharValueDelim='"'; const char SchemaParser::CharValueOf='@'; const QString SchemaParser::TokenIf=QString("if"); const QString SchemaParser::TokenThen=QString("then"); const QString SchemaParser::TokenElse=QString("else"); const QString SchemaParser::TokenEnd=QString("end"); const QString SchemaParser::TokenOr=QString("or"); const QString SchemaParser::TokenAnd=QString("and"); const QString SchemaParser::TokenNot=QString("not"); const QString SchemaParser::TokenSet=QString("set"); const QString SchemaParser::TokenUnset=QString("unset"); const QString SchemaParser::TokenMetaSp=QString("sp"); const QString SchemaParser::TokenMetaBr=QString("br"); const QString SchemaParser::TokenMetaTb=QString("tb"); const QString SchemaParser::TokenMetaOb=QString("ob"); const QString SchemaParser::TokenMetaCb=QString("cb"); const QString SchemaParser::TokenMetaOc=QString("oc"); const QString SchemaParser::TokenMetaCc=QString("cc"); const QString SchemaParser::TokenEqOper=QString("=="); const QString SchemaParser::TokenNeOper=QString("!="); const QString SchemaParser::TokenGtOper=QString(">"); const QString SchemaParser::TokenLtOper=QString("<"); const QString SchemaParser::TokenGtEqOper=QString(">="); const QString SchemaParser::TokenLtEqOper=QString("<="); const QRegExp SchemaParser::AttribRegExp=QRegExp("^([a-z])([a-z]*|(\\d)*|(\\-)*|(_)*)+", Qt::CaseInsensitive); SchemaParser::SchemaParser(void) { line=column=comment_count=0; ignore_unk_atribs=ignore_empty_atribs=false; pgsql_version=PgSqlVersions::DefaulVersion; } void SchemaParser::setPgSQLVersion(const QString &pgsql_ver) { unsigned curr_ver = QString(pgsql_ver).remove('.').toUInt(), version90 = QString(PgSqlVersions::PgSqlVersion90).remove('.').toUInt(), default_ver = QString(PgSqlVersions::DefaulVersion).remove('.').toUInt(); if(curr_ver != 0 && (curr_ver < version90)) throw Exception(Exception::getErrorMessage(ErrorCode::InvPostgreSQLVersion) .arg(pgsql_ver) .arg(PgSqlVersions::PgSqlVersion90) .arg(PgSqlVersions::DefaulVersion), ErrorCode::InvPostgreSQLVersion,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(curr_ver > 0 && curr_ver <= default_ver) pgsql_version=pgsql_ver; else pgsql_version=PgSqlVersions::DefaulVersion; } QString SchemaParser::getPgSQLVersion(void) { return(pgsql_version); } QStringList SchemaParser::extractAttributes(void) { QStringList attribs; int start=0, end=0; for(QString line : buffer) { //Find the first occurrence of '{' in the line start=line.indexOf(CharIniAttribute, start); while(start >= 0 && start < line.size()) { end=line.indexOf(CharEndAttribute, start); if(end >= 0) { //Extract the name between {} and push it into the list attribs.push_back(line.mid(start + 1, end - start -1)); //Start searching new attribute start now from the last position start=line.indexOf(CharIniAttribute, end); } else break; } start=end=0; } attribs.removeDuplicates(); return(attribs); } void SchemaParser::restartParser(void) { /* Clears the buffer and resets the counters for line, column and amount of comments */ buffer.clear(); attributes.clear(); line=column=comment_count=0; } void SchemaParser::loadBuffer(const QString &buf) { QString buf_aux=buf, lin, escaped_comm_chr=QString("\\%1").arg(CharComment), placeholder = QString(QChar::ReplacementCharacter); QTextStream ts(&buf_aux); int pos=0; bool comm_holder_used = false; //Prepares the parser to do new reading restartParser(); filename="[memory buffer]"; //While the input file doesn't reach the end while(!ts.atEnd()) { //Get one line from stream (until the last char before \n) lin = ts.readLine(); /* Special treatment for escaped comment characters (e.g.: \#): * In order to avoid removing wrongly the # from the the line where it appear in the form \# * we need to replace it temporarily by a placeholder and remove other portions of the line * the is considered a real comment and then replace back that placeholder by the comment char again. * This is useful if the user intend to represent the hash (#) char in the schema code and not use it as comment. */ if(lin.indexOf(escaped_comm_chr) >= 0) { lin.replace(escaped_comm_chr, placeholder); comm_holder_used = true; } /* Since the method getline discards the \n when the line was just a line break its needed to treat it in order to not lost it */ if(lin.isEmpty()) lin+=CharLineEnd; //If the entire line is commented out increases the comment lines counter if(lin[0]==CharComment) comment_count++; //Looking for the position of other comment characters for deletion pos=lin.indexOf(CharComment); //Removes the characters from the found position if(pos >= 0) lin.remove(pos, lin.size()); //Replacing the comment placeholder by the comment char causing that character to be printed to the code if(comm_holder_used) { lin.replace(placeholder, QString(CharComment)); comm_holder_used = false; } if(!lin.isEmpty()) { //Add a line break in case the last character is not if(lin[lin.size()-1]!=CharLineEnd) lin+=CharLineEnd; //Add the treated line in the buffer buffer.push_back(lin); } } } void SchemaParser::loadFile(const QString &filename) { if(!filename.isEmpty()) { QFile input; QString buf; //Open the file for reading input.setFileName(filename); input.open(QFile::ReadOnly); if(!input.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(filename), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); buf=input.readAll(); input.close(); //Loads the parser buffer loadBuffer(buf); SchemaParser::filename=filename; } } QString SchemaParser::getAttribute(void) { QString atrib, current_line; bool start_attrib, end_attrib, error=false; //Get the current line from the buffer current_line=buffer[line]; /* Only start extracting an attribute if it starts with a { even if the current character is an attribute delimiter */ if(current_line[column]!=CharIniAttribute) error=true; else { //Step to the next column in the line column++; //Marks the flag indicating start of attribute start_attrib=true; //Unmarks the flag indicating end of attribute end_attrib=false; /* Attempt to extract an attribute until a space, end of line or attribute is encountered */ while(current_line[column]!=CharLineEnd && current_line[column]!=CharSpace && current_line[column]!=CharTabulation && !end_attrib && !error) { if(current_line[column]!=CharEndAttribute) atrib+=current_line[column]; else if(current_line[column]==CharEndAttribute && !atrib.isEmpty()) end_attrib=true; else error=true; column++; } /* If the attribute has been started but not finished ie absence of the } in its statement (ie. {attr), generates an error. */ if(start_attrib && !end_attrib) error=true; } if(error) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(!AttribRegExp.exactMatch(atrib)) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidAttribute) .arg(atrib).arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } return(atrib); } QString SchemaParser::getWord(void) { QString word, current_line; //Gets the current line buffer current_line=buffer[line]; /* Attempt to extract a word if the first character is not a special character. */ if(!isSpecialCharacter(current_line[column].toLatin1())) { /* Extract the word while it is not end of line, space or special character */ while(current_line[column]!=CharLineEnd && !isSpecialCharacter(current_line[column].toLatin1()) && current_line[column]!=CharSpace && current_line[column]!=CharTabulation) { word+=current_line[column]; column++; } } return(word); } QString SchemaParser::getPureText(void) { QString text, current_line; bool error=false; current_line=buffer[line]; //Attempt to extract a pure text if the first character is a [ if(current_line[column]==CharIniPlainText) { //Moves to the next character that contains the beginning of the text column++; /* Extracts the text while the end of pure text (]), end of buffer or beginning of other pure text ([) is reached */ while(current_line[column]!=CharEndPlainText && line < buffer.size() && current_line[column]!=CharIniPlainText) { text+=current_line[column]; /* Special case to end of line. Unlike other elements of language, a pure text can be extracted until the end of the buffer, thus, this method also controls the lines transitions */ if(current_line[column]==CharLineEnd) { //Step to the next line line++; column=0; if(line < buffer.size()) current_line=buffer[line]; } else column++; } if(current_line[column]==CharEndPlainText) column++; else error=true; } else error=true; if(error) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } return(text); } QString SchemaParser::getConditional(void) { QString conditional, current_line; bool error=false; current_line=buffer[line]; //Will initiate extraction if a % is found if(current_line[column]==CharIniConditional) { /* Passa para o próximo caractere que é o início do do nome da palavra condicional */ column++; /* Moves to the next character that is the beginning of the name of the conditional word */ while(current_line[column]!=CharLineEnd && current_line[column]!=CharSpace && current_line[column]!=CharTabulation) { conditional+=current_line[column]; column++; } //If no word was extracted an error is raised if(conditional.isEmpty()) error=true; } else error=true; if(error) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg(line + comment_count + 1).arg(column+1), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } return(conditional); } QString SchemaParser::getMetaCharacter(void) { QString meta, current_line; bool error=false; current_line=buffer[line]; //Begins the extraction in case of a $ is found if(current_line[column]==CharIniMetachar) { //Moves to the next character that is the beginning of the metacharacter column++; //Extracts the metacharacter until doesn't finds a space or end of line while(current_line[column]!=CharLineEnd && current_line[column]!=CharSpace && current_line[column]!=CharTabulation) { meta+=current_line[column]; column++; } //If no metacharacter was extracted an error is raised if(meta.isEmpty()) error=true; } else error=true; if(error) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg(line + comment_count + 1).arg(column+1), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } return(meta); } bool SchemaParser::isSpecialCharacter(char chr) { return(chr==CharIniAttribute || chr==CharEndAttribute || chr==CharIniConditional || chr==CharIniMetachar || chr==CharIniPlainText || chr==CharEndPlainText); } bool SchemaParser::evaluateComparisonExpr(void) { QString curr_line, attrib, value, oper, valid_op_chrs="=!<>fi"; bool error=false, end_eval=false, expr_is_true=true; static QStringList opers = { TokenEqOper, TokenNeOper, TokenGtOper, TokenLtOper, TokenGtEqOper, TokenLtEqOper }; try { curr_line=buffer[line]; column++; while(!end_eval && !error) { ignoreBlankChars(curr_line); /* If the scan reached the end of the line and the expression was not closed raises an syntax error Comparison expr must start and end in the same line */ if(curr_line[column]==CharLineEnd && !end_eval) error=true; switch(curr_line[column].toLatin1()) { case CharIniAttribute: /* Extract the attribute (the first element in the expression) only if the comparison operator and values aren't extracted */ if(attrib.isEmpty() && oper.isEmpty() && value.isEmpty()) attrib=getAttribute(); else error=true; break; case CharValueDelim: /* Extract the value (the last element in the expression) only if the attribute and operator were extracted */ if(value.isEmpty() && !attrib.isEmpty() && !oper.isEmpty()) { value+=curr_line[column++]; while(column < curr_line.size()) { value+=curr_line[column++]; if(curr_line[column]==CharValueDelim) { value+=CharValueDelim; column++; break; } } } else error=true; break; case CharEndCompExpr: column++; //If one of the elements are missing, raise an syntax error if(attrib.isEmpty() || oper.isEmpty() || value.isEmpty()) error=true; else if(!opers.contains(QString(oper).remove('f').remove('i'))) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidOperatorInExpression) .arg(oper).arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidOperatorInExpression,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(attributes.count(attrib)==0 && !ignore_unk_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UnkownAttribute) .arg(attrib).arg(filename).arg((line + comment_count +1)).arg((column+1)), ErrorCode::UnkownAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { QVariant left_val, right_val; value.remove(CharValueDelim); //Evaluating the attribute value against the one captured on the expression without casting if(oper.endsWith('f')) { left_val = QVariant(attributes[attrib].toFloat()); right_val = QVariant(value.toFloat()); oper.remove('f'); } else if(oper.endsWith('i')) { left_val = QVariant(attributes[attrib].toInt()); right_val = QVariant(value.toInt()); oper.remove('i'); } else { left_val = QVariant(attributes[attrib]); right_val = QVariant(value); } expr_is_true=((oper==TokenEqOper && (left_val == right_val)) || (oper==TokenNeOper && (left_val != right_val)) || (oper==TokenGtOper && (left_val > right_val)) || (oper==TokenLtOper && (left_val < right_val)) || (oper==TokenGtEqOper && (left_val >= right_val)) || (oper==TokenLtEqOper && (left_val <= right_val))); end_eval=true; } break; default: /* Extract the operator (the second element in the expression) only if the attribute was extracted and the value not */ if(oper.size() <= 3 && !attrib.isEmpty() && value.isEmpty()) { //If the current char is a valid operator capture it otherwise raise an error if(valid_op_chrs.indexOf(curr_line[column]) >= 0) oper+=curr_line[column++]; else error=true; } else error=true; break; } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } if(error) throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(expr_is_true); } void SchemaParser::defineAttribute(void) { QString curr_line, attrib, value, new_attrib; bool error=false, end_def=false, use_val_as_name=false; try { curr_line=buffer[line]; while(!end_def && !error) { ignoreBlankChars(curr_line); switch(curr_line[column].toLatin1()) { case CharLineEnd: end_def=true; break; case CharValueOf: if(!use_val_as_name) { use_val_as_name=true; column++; new_attrib=getAttribute(); } else error=true; break; case CharIniConditional: error=true; break; case CharIniAttribute: if(new_attrib.isEmpty()) new_attrib=getAttribute(); else { //Get the attribute in the middle of the value attrib=getAttribute(); if(attributes.count(attrib)==0 && !ignore_unk_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UnkownAttribute) .arg(attrib).arg(filename).arg((line + comment_count +1)).arg((column+1)), ErrorCode::UnkownAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } value+=attributes[attrib]; } break; case CharIniPlainText: value+=getPureText(); break; case CharIniMetachar: value+=translateMetaCharacter(getMetaCharacter()); break; default: value+=getWord(); break; } //If the attribute name was not extracted yet returns a error if(new_attrib.isEmpty()) error=true; } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } if(!error) { attrib=(use_val_as_name ? attributes[new_attrib] : new_attrib); //Checking if the attribute has a valid name if(!AttribRegExp.exactMatch(attrib)) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidAttribute) .arg(attrib).arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } /* Creates the attribute in the attribute map of the schema, making the attribute available on the rest of the script being parsed */ attributes[attrib]=value; } else throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } void SchemaParser::unsetAttribute(void) { QString curr_line, attrib; bool end_def=false; try { curr_line=buffer[line]; while(!end_def) { ignoreBlankChars(curr_line); switch(curr_line[column].toLatin1()) { case CharLineEnd: end_def=true; break; case CharIniAttribute: attrib=getAttribute(); if(attributes.count(attrib)==0 && !ignore_unk_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UnkownAttribute) .arg(attrib).arg(filename).arg((line + comment_count +1)).arg((column+1)), ErrorCode::UnkownAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(!AttribRegExp.exactMatch(attrib)) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidAttribute) .arg(attrib).arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } attributes[attrib]=QString(); break; default: throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } bool SchemaParser::evaluateExpression(void) { QString current_line, cond, attrib, prev_cond; bool error=false, end_eval=false, expr_is_true=true, attrib_true=true, comp_true=true; unsigned attrib_count=0, and_or_count=0; try { current_line=buffer[line]; while(!end_eval && !error) { ignoreBlankChars(current_line); if(current_line[column]==CharLineEnd) { line++; if(line < buffer.size()) { current_line=buffer[line]; column=0; ignoreBlankChars(current_line); } else if(!end_eval) error=true; } switch(current_line[column].toLatin1()) { //Extract the next conditional token case CharIniConditional: prev_cond=cond; cond=getConditional(); //Error 1: %if {a} %or %or %then error=(cond==prev_cond || //Error 2: %if {a} %and %or %then (cond==TokenAnd && prev_cond==TokenOr) || //Error 3: %if {a} %or %and %then (cond==TokenOr && prev_cond==TokenAnd) || //Error 4: %if %and {a} %then (attrib_count==0 && (cond==TokenAnd || cond==TokenOr))); if(cond==TokenThen) { /* Returns the parser to the token %then because additional operations is done whe this token is found */ column-=cond.length()+1; end_eval=true; //Error 1: %if {a} %not %then error=(prev_cond==TokenNot || //Error 2: %if %then attrib_count==0 || //Error 3: %if {a} %and %then (and_or_count!=attrib_count-1)); } else if(cond==TokenOr || cond==TokenAnd) and_or_count++; break; case CharIniAttribute: attrib=getAttribute(); //Raises an error if the attribute does is unknown if(attributes.count(attrib)==0 && !ignore_unk_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UnkownAttribute) .arg(attrib).arg(filename).arg((line + comment_count +1)).arg((column+1)), ErrorCode::UnkownAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Error 1: A conditional token other than %or %not %and if found on conditional expression error=(!cond.isEmpty() && cond!=TokenOr && cond!=TokenAnd && cond!=TokenNot) || //Error 2: A %not token if found after an attribute: %if {a} %not %then (attrib_count > 0 && cond==TokenNot && prev_cond.isEmpty()) || //Error 3: Two attributes not separated by any conditional token: %if {a} {b} %then (attrib_count > 0 && cond.isEmpty()); //Increments the extracted attribute counter attrib_count++; if(!error) { //Appliyng the NOT operator if found attrib_true=(cond==TokenNot ? attributes[attrib].isEmpty() : !attributes[attrib].isEmpty()); //Executing the AND operation if the token is found if(cond==TokenAnd || prev_cond==TokenAnd) expr_is_true=(expr_is_true && attrib_true); else if(cond==TokenOr || prev_cond==TokenOr) expr_is_true=(expr_is_true || attrib_true); else expr_is_true=attrib_true; cond.clear(); prev_cond.clear(); } break; case CharIniCompExpr: comp_true=evaluateComparisonExpr(); //Appliyng the NOT operator if found if(cond==TokenNot) comp_true=!comp_true; //Executing the AND operation if the token is found if(cond==TokenAnd || prev_cond==TokenAnd) expr_is_true=(expr_is_true && comp_true); else if(cond==TokenOr || prev_cond==TokenOr) expr_is_true=(expr_is_true || comp_true); else expr_is_true=comp_true; //Consider the comparison expression as an attribute evaluation attrib_count++; cond.clear(); prev_cond.clear(); break; default: error=true; break; } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } if(error) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg((line + comment_count + 1)).arg((column+1)), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } return(expr_is_true); } void SchemaParser::ignoreBlankChars(const QString &line) { while(column < line.size() && (line[column]==CharSpace || line[column]==CharTabulation)) column++; } char SchemaParser::translateMetaCharacter(const QString &meta) { static map metas={{ TokenMetaSp, CharSpace }, { TokenMetaTb, CharTabulation }, { TokenMetaBr, CharLineEnd }, { TokenMetaOb, CharIniPlainText }, { TokenMetaCb, CharEndPlainText }, { TokenMetaOc, CharIniAttribute }, { TokenMetaCc, CharEndAttribute }}; if(metas.count(meta)==0) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidMetacharacter) .arg(meta).arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::InvalidMetacharacter,__PRETTY_FUNCTION__,__FILE__,__LINE__); } return(metas.at(meta)); } QString SchemaParser::getCodeDefinition(const QString & obj_name, attribs_map &attribs, unsigned def_type) { try { QString filename; if(def_type==SqlDefinition) { //Formats the filename filename=GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::SQLSchemaDir + GlobalAttributes::DirSeparator + obj_name + GlobalAttributes::SchemaExt; attribs[Attributes::PgSqlVersion]=pgsql_version; //Try to get the object definitin from the specified path return(getCodeDefinition(filename, attribs)); } else { filename=GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + obj_name + GlobalAttributes::SchemaExt; return(convertCharsToXMLEntities(getCodeDefinition(filename, attribs))); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void SchemaParser::ignoreUnkownAttributes(bool ignore) { ignore_unk_atribs=ignore; } void SchemaParser::ignoreEmptyAttributes(bool ignore) { ignore_empty_atribs=ignore; } QString SchemaParser::convertCharsToXMLEntities(QString buf) { //Configures a text stream to read the entire buffer line by line QTextStream ts(&buf); QString lin, buf_aux; bool xml_header=false, in_comment=false; //Sets the text steam to detect UTF8 encoding ts.setAutoDetectUnicode(true); while(!ts.atEnd()) { lin=ts.readLine(); //Checks if the current line is a XML header (= 0); //Checks if the current line is a comment start tag if(!in_comment) in_comment=(lin.indexOf("") >=0) in_comment=false; //Case the line is empty, is a xml header or a comment line and does not treat XML entities on it if(lin.isEmpty() || xml_header || in_comment) lin+="\n"; else { QRegExp attr_regexp=QRegExp("(([a-z]+)|(\\-))+( )*(=\")"), next_attr_regexp=QRegExp(QString("(\")(( )|(\\t))+(%1)").arg(attr_regexp.pattern())); int attr_start=0, attr_end=0, count=0, next_attr=-1; QString str_aux; lin+="\n"; do { //Try to extract the values using regular expressions attr_start=attr_regexp.indexIn(lin, attr_start); attr_start+=attr_regexp.matchedLength(); next_attr=next_attr_regexp.indexIn(lin, attr_start); if(next_attr < 0) attr_end=lin.lastIndexOf(QChar('"')) - 1; else attr_end=next_attr - 1; //Calculates the amount of extracted characters count=(attr_start > 0 ? (attr_end - attr_start) + 1 : 0); if(attr_start >= 0 && count > 0) { //Gets the substring extracted using regexp str_aux=lin.mid(attr_start, count).trimmed(); if(str_aux.contains(QRegExp("(&|\\<|\\>|\")"))) { //Replaces the char by the XML entities if(!str_aux.contains(XmlParser::CharQuot) && !str_aux.contains(XmlParser::CharLt) && !str_aux.contains(XmlParser::CharGt) && !str_aux.contains(XmlParser::CharAmp) && !str_aux.contains(XmlParser::CharApos) && str_aux.contains('&')) str_aux.replace('&', XmlParser::CharAmp); str_aux.replace('"',XmlParser::CharQuot); str_aux.replace('<',XmlParser::CharLt); str_aux.replace('>',XmlParser::CharGt); //Puts on the original XML definition the modified string lin.replace(attr_start, count, str_aux); } attr_start+=str_aux.size() + 1; } } /* Iterates while the positions of the expressions found is valid. Positions less than 0 indicates that no regular expressions managed to find values */ while(attr_start >=0 && attr_end >=0 && attr_start < lin.size()); } buf_aux+=lin; lin.clear(); //Reseting the in_comment flag when the current line has a end comment tag if(in_comment && lin.indexOf("-->") >= 0) in_comment=false; } return(buf_aux); } QString SchemaParser::getCodeDefinition(attribs_map &attribs) { QString object_def; unsigned end_cnt, if_cnt; int if_level, prev_if_level; QString atrib, cond, prev_cond, word, meta; bool error, if_expr; char chr; vector vet_expif, vet_tk_if, vet_tk_then, vet_tk_else; map > if_map, else_map; vector::iterator itr, itr_end; vector vet_prev_level; vector *vet_aux; //In case the file was successfuly loaded if(buffer.size() > 0) { //Init the control variables attributes=attribs; error=if_expr=false; if_level=-1; end_cnt=if_cnt=0; while(line < buffer.size()) { chr=buffer[line][column].toLatin1(); switch(chr) { /* Increments the number of rows causing the parser to get the next line buffer for analysis */ case CharLineEnd: line++; column=0; break; case CharTabulation: case CharSpace: //The parser will ignore the spaces that are not within pure texts while(buffer[line][column]==CharSpace || buffer[line][column]==CharTabulation) column++; break; //Metacharacter extraction case CharIniMetachar: meta=getMetaCharacter(); //Checks whether the metacharacter is part of the 'if' expression (this is an error) if(if_level>=0 && vet_tk_if[if_level] && !vet_tk_then[if_level]) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { //Converting the metacharacter drawn to the character that represents this chr=translateMetaCharacter(meta); meta=QString(); meta+=chr; //If the parser is inside an 'if / else' extracting tokens if(if_level>=0) { /* If the parser is in 'if' section, places the metacharacter on the word map of the current 'if' */ if(vet_tk_if[if_level] && vet_tk_then[if_level] && !vet_tk_else[if_level]) if_map[if_level].push_back(meta); /* If the parser is in 'else' section, places the metacharacter on the word map of the current 'else'*/ else if(vet_tk_else[if_level]) else_map[if_level].push_back(meta); } else /* If the parsers is not in a 'if / else', puts the metacharacter in the definition sql */ object_def+=meta; } break; //Attribute extraction case CharIniAttribute: case CharEndAttribute: atrib=getAttribute(); //Checks if the attribute extracted belongs to the passed list of attributes if(attributes.count(atrib)==0) { if(!ignore_unk_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UnkownAttribute) .arg(atrib).arg(filename).arg((line + comment_count +1)).arg((column+1)), ErrorCode::UnkownAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else attributes[atrib]=QString(); } //If the parser is inside an 'if / else' extracting tokens if(if_level>=0) { //If the parser evaluated the 'if' conditional and is inside the current if block if(!(!if_expr && vet_tk_if[if_level] && !vet_tk_then[if_level])) { word=atrib; atrib=QString(); atrib+=CharIniAttribute; atrib+=word; atrib+=CharEndAttribute; //If the parser is in the 'if' section if(vet_tk_if[if_level] && vet_tk_then[if_level] && !vet_tk_else[if_level]) //Inserts the attribute value in the map of the words of current the 'if' section if_map[if_level].push_back(atrib); else if(vet_tk_else[if_level]) //Inserts the attribute value in the map of the words of current the 'else' section else_map[if_level].push_back(atrib); } } else { /* If the attribute has no value set and parser must not ignore empty values raises an exception */ if(attributes[atrib].isEmpty() && !ignore_empty_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UndefinedAttributeValue) .arg(atrib).arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::UndefinedAttributeValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); } /* If the parser is not in an if / else, concatenates the value of the attribute directly in definition in sql */ object_def+=attributes[atrib]; } break; //Conditional instruction extraction case CharIniConditional: prev_cond=cond; cond=getConditional(); //Checks whether the extracted token is a valid conditional if(cond!=TokenIf && cond!=TokenElse && cond!=TokenThen && cond!=TokenEnd && cond!=TokenOr && cond!=TokenNot && cond!=TokenAnd && cond!=TokenSet && cond!=TokenUnset) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidInstruction) .arg(cond).arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::InvalidInstruction,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(cond==TokenSet || cond==TokenUnset) { bool extract=false; /* Extracts or unset the attribute only if the process is not in the middle of a 'if-then-else' or if the parser is inside the 'if' part and the expression is evaluated as true, or in the 'else' part and the related 'if' is false. Otherwise the line where %set is located will be completely ignored */ extract=(if_level < 0 || vet_expif.empty()); if(!extract && if_level >= 0) { //If in 'else' the related 'if' is false, extracts the attribute if(prev_cond == TokenElse && !vet_expif[if_level]) extract=true; else if(prev_cond != TokenElse) { //If in the 'if' part all the previous ifs until the current must be true extract=true; for(int i=0; i <= if_level && extract; i++) { extract=(vet_expif[i] && !vet_tk_else[i]) || (!vet_expif[i] && vet_tk_else[i]); } } } if(extract) { if(cond==TokenSet) defineAttribute(); else unsetAttribute(); } else { column=0; line++; } } else { //If the toke is an 'if' if(cond==TokenIf) { //Evaluates the if expression storing the result on the vector if_expr=true; vet_expif.push_back(evaluateExpression()); /* Inserts the value of the current 'if' level in the previous 'if' levels vector. This vector is used to know which 'if' the parser was in before entering current if */ vet_prev_level.push_back(if_level); /* Mark the flags indicating that an 'if' was found and a 'then' and 'else' have not been found yet */ vet_tk_if.push_back(true); vet_tk_then.push_back(false); vet_tk_else.push_back(false); //Defines the current if level as the size of list 'if' tokens found -1 if_level=(vet_tk_if.size()-1); //Increases the number of found 'if's if_cnt++; } //If the parser is in 'if / else' and one 'then' token is found else if(cond==TokenThen && if_level>=0) { //Marks the then token flag of the current 'if' vet_tk_then[if_level]=true; /* Clears the expression extracted flag from the 'if - then', so that the parser does not generate an error when it encounters another 'if - then' with an expression still unextracted */ if_expr=false; } //If the parser is in 'if / else' and a 'else' token is found else if(cond==TokenElse && if_level>=0) //Mark the o flag do token else do if atual vet_tk_else[if_level]=true; //Case the parser is in 'if/else' and a 'end' token was found else if(cond==TokenEnd && if_level>=0) { //Increments the number of 'end' tokes found end_cnt++; //Get the level of the previous 'if' where the parser was prev_if_level=vet_prev_level[if_level]; //In case the current 'if' be internal (nested) (if_level > 0) if(if_level > 0) { //In case the current 'if' doesn't in the 'else' section of the above 'if' (previous if level) if(!vet_tk_else[prev_if_level]) //Get the extracted word vector on the above 'if' vet_aux=&if_map[prev_if_level]; else //Get the extracted word vector on the above 'else' vet_aux=&else_map[prev_if_level]; } else vet_aux=nullptr; /* Initializes the iterators to scan the auxiliary vector if necessary */ itr=itr_end=if_map[0].end(); /* In case the expression of the current 'if' has the value true then the parser will scan the list of words on the 'if' part of the current 'if' */ if(vet_expif[if_level]) { itr=if_map[if_level].begin(); itr_end=if_map[if_level].end(); } /* If there is a 'else' part on the current 'if' then the parser will scan the list of words on the 'else' part */ else if(else_map.count(if_level)>0) { itr=else_map[if_level].begin(); itr_end=else_map[if_level].end(); } /* This iteration scans the list of words selected above inserting them in 'if' part of the 'if' or 'else' superior to current. This is done so that only the words extracted based on ifs expressions of the buffer are embedded in defining sql */ while(itr!=itr_end) { //If the auxiliary vector is allocated, inserts the word on above 'if / else' if(vet_aux) vet_aux->push_back((*itr)); else { word=(*itr); //Check if the word is not an attribute if(!word.isEmpty() && word.startsWith(CharIniAttribute) && word.endsWith(CharEndAttribute)) { //If its an attribute, extracts the name between { } and checks if the same has empty value atrib=word.mid(1, word.size()-2); word=attributes[atrib]; /* If the attribute has no value set and parser must not ignore empty values raises an exception */ if(word.isEmpty() && !ignore_empty_atribs) { throw Exception(Exception::getErrorMessage(ErrorCode::UndefinedAttributeValue) .arg(atrib).arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::UndefinedAttributeValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } //Else, insert the work directly on the object definition object_def+=word; } itr++; } //Case the current if is nested (internal) if(if_level > 0) //Causes the parser to return to the earlier 'if' if_level=prev_if_level; /* In case the 'if' be the uppermost (level 0) indicates that all the if's has already been checked, so the parser will clear the used auxiliary structures*/ else { if_map.clear(); else_map.clear(); vet_tk_if.clear(); vet_tk_then.clear(); vet_tk_else.clear(); vet_expif.clear(); vet_prev_level.clear(); //Resets the ifs levels if_level=prev_if_level=-1; } } else error=true; if(!error) { /* Verifying that the conditional words appear in a valid order if not the parser generates an error. Correct order means IF before THEN, ELSE after IF and before END */ if((prev_cond==TokenIf && cond!=TokenThen) || (prev_cond==TokenElse && cond!=TokenIf && cond!=TokenEnd) || (prev_cond==TokenThen && cond==TokenThen)) error=true; } if(error) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } break; //Extraction of pure text or simple words default: if(chr==CharIniPlainText || chr==CharEndPlainText) word=getPureText(); else word=getWord(); //Case the parser is in 'if/else' if(if_level>=0) { /* In case the word/text be inside 'if' expression, the parser returns an error because only an attribute must be on the 'if' expression */ if(vet_tk_if[if_level] && !vet_tk_then[if_level]) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Case the parser is in 'if' section else if(vet_tk_if[if_level] && vet_tk_then[if_level] && !vet_tk_else[if_level]) //Inserts the word on the words map extracted on 'if' section if_map[if_level].push_back(word); else if(vet_tk_else[if_level]) //Inserts the word on the words map extracted on 'else' section else_map[if_level].push_back(word); } else //Case the parser is not in 'if/else' concatenates the word/text directly on the object definition object_def+=word; break; } } /* If has more 'if' toknes than 'end' tokens, this indicates that some 'if' in code was not closed thus the parser returns an error */ if(if_cnt!=end_cnt) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidSyntax) .arg(filename).arg(line + comment_count +1).arg(column+1), ErrorCode::InvalidSyntax,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } restartParser(); ignore_unk_atribs=false; ignore_empty_atribs=false; return(object_def); } QString SchemaParser::getCodeDefinition(const QString &filename, attribs_map &attribs) { try { loadFile(filename); attribs[Attributes::PgSqlVersion]=pgsql_version; return(getCodeDefinition(attribs)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libparsers/src/schemaparser.h000066400000000000000000000230111360462764600212760ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libparsers \brief ParserEsquema class definition used to create SQL definition for model objects from schemas files (stored on disk). \note Creation date: 19/06/2008 */ #ifndef SCHEMA_PARSER_H #define SCHEMA_PARSER_H #include "globalattributes.h" #include "exception.h" #include #include #include #include #include "xmlparser.h" #include "attribsmap.h" #include "pgsqlversions.h" class SchemaParser { private: /*! \brief Indicates that the parser should ignore unknown attributes avoiding raising exceptions */ bool ignore_unk_atribs; /*! \brief Indicates that the parser should ignore empty attributes avoiding raising exceptions */ bool ignore_empty_atribs; //! \brief RegExp used to validate attribute names static const QRegExp AttribRegExp; //! \brief Get an attribute name from the buffer on the current position QString getAttribute(void); //! \brief Get an conditional instruction from the buffer on the current position QString getConditional(void); //! \brief Get an metacharacter from the buffer on the current position QString getMetaCharacter(void); /*! \brief Returns the result (true|false) of conditional expression evaluation. The expression is evaluated from the left to the right and not support Polish Notation, so as the parser finds an attribute evaluates it and stores the result, when find another one evaluates and compare with previous evaluation, and so on. Example: Let's suppose a1 and a2 has values and a3 is empty, the following expression results will be: %if {a1} %or {a2} %and {a3} %then --> FALSE %if {a1} %or {a2} %and %not {a3} %then --> TRUE %if {a1} %or %not {a3} %then --> TRUE %if {a1} %and {a3} %then --> FALSE */ bool evaluateExpression(void); /*! \brief Returns the result (true|false) of a comparison expression. A comparison expression have the form: ( {attribute} [operator] "value" ), where: ( --> Starts the expression {attribute} --> Is the attribute to be compared to a value [operator] --> A valid comparison operator: == (equal), != (not equal), < (less than), > (greater than) <= (less or equal to), >= (greater or equal to) ) --> Closes the expression The parenthesis are mandatory otherwise the parser will not recognize the expression and raise an exception. Multiple expressions combined with logical operators %not %and %or in the same () are not supported. */ bool evaluateComparisonExpr(void); /*! \brief Creates a new attribute when finding: 1) %set {attrib-name} [expr] or 2) %set @{existing-attrib} [expr] Where [expr] can be pure texts, meta chars or other attributes exists overwrite its value. In the second form note the @ at the beginnig of 'existing-attribute', this variation creates a new attribute which the name is the value of {existing-attribute}. In this case the parser may return error if the value used is an invalid name. The %set construction must be the only one in the line otherwise the parser will return errors if another instruction starting with % is found. */ void defineAttribute(void); //! \brief Clears the value of attributes when finding the instruction: %unset {attr1} {attr2}... void unsetAttribute(void); //! \brief Increments the column counter while blank chars (space and tabs) are found on the line void ignoreBlankChars(const QString &line); //! \brief Translates the meta char token to the real character char translateMetaCharacter(const QString &meta); /*! \brief Get an word from the buffer on the current position (word is any string that isn't a conditional instruction or comment) */ QString getWord(void); //! \brief Gets a pure text, ignoring elements of the language QString getPureText(void); /*! \brief Returns whether a character is special i.e. indicators of attributes or conditional instructions */ bool isSpecialCharacter(char chr); //! \brief Filename that was loaded by the parser QString filename; /*! \brief Vectorial representation of the loaded file. This is the buffer that is analyzed by de parser */ QStringList buffer; int line, //! \brief Current line where the parser reading is column, //! \brief Current column where the parser reading is /*! \brief Comment line ammout extracted. This attribute is used to make the correct reference to the line on file that has syntax errors */ comment_count; attribs_map attributes; //! \brief PostgreSQL version currently used by the parser QString pgsql_version; public: static const char CharComment, //! \brief Character that starts a comment CharLineEnd, //! \brief Character that indicates end of line CharSpace, //! \brief Character that indicates spacing CharTabulation, //! \brief Character that indicates tabulation CharIniAttribute, //! \brief Character that indicates a reference to an attribute CharEndAttribute, //! \brief Character that delimits on the right the attribute name CharIniConditional, //! \brief Character that starts a conditional instruction CharIniMetachar, //! \brief Character that starts a metacharacter CharIniPlainText, //! \brief Character that starts a plain text CharEndPlainText, //! \brief Character that ends a plain text CharIniCompExpr, //! \brief Character that starts a comparison expression CharEndCompExpr, //! \brief Character that ends a comparison expression CharValueDelim, //! \brief Character that delimiters a value (string) CharValueOf; /*! \brief Character that is used on %set instructions to create an attribute name based upon another attribute value */ //! \brief Tokens related to conditional instructions and operators static const QString TokenIf, // %if TokenThen,// %then TokenElse,// %else TokenEnd, // %end TokenOr, // %or TokenNot, // %not TokenAnd, // %and TokenSet, //%set TokenUnset; //%unset //! \brief Tokens related to metacharacters static const QString TokenMetaSp,// $sp (space) TokenMetaBr,// $br (line break) TokenMetaTb,// $tb (tabulation) TokenMetaOb,// $ob (open square bracket '[') TokenMetaCb,// $cb (close square bracket ']') TokenMetaOc,// $ob (open curly bracket '{') TokenMetaCc;// $cb (close curly bracket '}') //! \brief Tokens related to comparison expressions static const QString TokenEqOper,// == (equal) TokenNeOper,// != (not equal) TokenGtOper,// > (greater than) TokenLtOper,// < (less than) TokenGtEqOper,// >= (greater or equal to) TokenLtEqOper;// <= (less or equal to) //! \brief Constants used to get a specific object definition static constexpr unsigned SqlDefinition=0, XmlDefinition=1; SchemaParser(void); /*! \brief Set the version of PostgreSQL to be adopted by the parser in obtaining the definition of the objects. This function should always be called at software startup or when the user wants to change the default version of the database */ void setPgSQLVersion(const QString &pgsql_ver); /*! \brief Returns the complete xml/sql definition for an database object represented by the map 'attributes'. For SQL definition is necessary to indicate the version of PostgreSQL in order to the to correct schema be loaded */ QString getCodeDefinition(const QString &obj_name, attribs_map &attribs, unsigned def_type); /*! \brief Generic method that loads a schema file and for a given map of attributes this method returns the data of the file analyzed and filled with the values ​​of the attributes map */ QString getCodeDefinition(const QString &filename, attribs_map &attribs); /*! \brief Generic method that interprets a pre-specified buffer (see loadBuffer()) and for a given map of attributes this method returns the data of the buffer analyzed and filled with the values ​​of the attributes map */ QString getCodeDefinition(attribs_map &attribs); //! \brief Loads the buffer with a string void loadBuffer(const QString &buf); //! \brief Loads a schema file and inserts its line into the parser's buffer void loadFile(const QString &filename); //! \brief Resets the parser in order to do new analysis void restartParser(void); //! \brief Set if the parser must ignore unknown attributes avoiding exception throwing void ignoreUnkownAttributes(bool ignore); //! \brief Set if the parser must ignore empty attributes avoiding exception throwing void ignoreEmptyAttributes(bool ignore); //! \brief Retorns the current PostgreSQL version used by the parser QString getPgSQLVersion(void); //! \brief Extracts the attributes names from the currently loaded buffer QStringList extractAttributes(void); /*! \brief Converts any chars (operators) < > " to the respective XML entities. This method is only * called when generating XML code and only tag attributes are treated.*/ static QString convertCharsToXMLEntities(QString buf); }; #endif pgmodeler-0.9.2/libparsers/src/xmlparser.cpp000066400000000000000000000301521360462764600211750ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "xmlparser.h" #include const QString XmlParser::CharAmp=QString("&"); const QString XmlParser::CharLt=QString("<"); const QString XmlParser::CharGt=QString(">"); const QString XmlParser::CharQuot=QString("""); const QString XmlParser::CharApos=QString("'"); XmlParser::XmlParser(void) { root_elem=nullptr; curr_elem=nullptr; xml_doc=nullptr; curr_line = 0; xmlInitParser(); } XmlParser::~XmlParser(void) { restartParser(); xmlCleanupParser(); } void XmlParser::removeDTD(void) { int pos1=-1, pos2=-1, pos3=-1, len; if(!xml_buffer.isEmpty()) { /* Removes the current DTD from document. If the user attempts to manipulate the structure of document damaging its integrity. */ pos1=xml_buffer.indexOf(QLatin1String("\n")); pos3=xml_buffer.indexOf(QLatin1String("\">\n")); if(pos1 >=0 && (pos2 >=0 || pos3 >= 0)) { len=((pos2 > pos3) ? (pos2-pos1)+3 : (pos3-pos2)+3); xml_buffer.replace(pos1,len,QString()); } } } void XmlParser::loadXMLFile(const QString &filename) { try { QFile input; QString buffer; if(!filename.isEmpty()) { //Opens a file stream using the file name input.setFileName(filename); input.open(QFile::ReadOnly); //Case the file opening was not sucessful if(!input.isOpen()) { throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(filename), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); } buffer=input.readAll(); input.close(); xml_doc_filename=filename; loadXMLBuffer(buffer); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void XmlParser::loadXMLBuffer(const QString &xml_buf) { try { int pos1=-1, pos2=-1, tam=0; if(xml_buf.isEmpty()) throw Exception(ErrorCode::AsgEmptyXMLBuffer,__PRETTY_FUNCTION__,__FILE__,__LINE__); pos1=xml_buf.indexOf(QLatin1String("")); xml_buffer=xml_buf; if(pos1 >= 0 && pos2 >= 0) { tam=(pos2-pos1)+3; xml_decl=xml_buffer.mid(pos1, tam); xml_buffer.replace(pos1,tam,QString()); } else xml_decl=QString("\n"); removeDTD(); readBuffer(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void XmlParser::setDTDFile(const QString &dtd_file, const QString &dtd_name) { QString fmt_dtd_file; if(dtd_file.isEmpty()) throw Exception(ErrorCode::AsgEmptyDTDFile,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(dtd_name.isEmpty()) throw Exception(ErrorCode::AsgEmptyDTDName,__PRETTY_FUNCTION__,__FILE__,__LINE__); #ifndef Q_OS_WIN fmt_dtd_file=QString("file://"); #else fmt_dtd_file=QString("file:///"); #endif //Formats the dtd file path to URL style (converting to percentage format the non reserved chars) fmt_dtd_file=QUrl::toPercentEncoding(QFileInfo(dtd_file).absoluteFilePath(), "/:"); dtd_decl=QString("\n"); } void XmlParser::readBuffer(void) { QByteArray buffer; QString msg, file; xmlError *xml_error=nullptr; int parser_opt; if(!xml_buffer.isEmpty()) { //Inserts the XML declaration buffer+=xml_decl; //Configures the parser, initially, to not validate the document against the dtd parser_opt=( XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOENT | XML_PARSE_BIG_LINES); //If the dtd declarions is setup if(!dtd_decl.isEmpty()) { //Inserts the default software DTD declarion into XML buffer buffer+=dtd_decl; //Now configures the parser to validate the buffer against the DTD parser_opt=(parser_opt | XML_PARSE_DTDLOAD | XML_PARSE_DTDVALID); } buffer+=xml_buffer; //Create an xml document from the buffer xml_doc=xmlReadMemory(buffer.data(), buffer.size(), nullptr, nullptr, parser_opt); //In case the document criation fails, gets the last xml parser error xml_error=xmlGetLastError(); //If some error is set if(xml_error) { //Formats the error msg=xml_error->message; file=xml_error->file; if(!file.isEmpty()) file=QString("(%1)").arg(file); msg.replace("\n"," "); //Restarts the parser if(xml_doc) restartParser(); //Raise an exception with the error massege from the parser xml throw Exception(Exception::getErrorMessage(ErrorCode::LibXMLError) .arg(xml_error->line).arg(xml_error->int2).arg(msg).arg(file), ErrorCode::LibXMLError,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Gets the referênce to the root element on the document root_elem=curr_elem=xmlDocGetRootElement(xml_doc); } } void XmlParser::savePosition(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); elems_stack.push(curr_elem); } void XmlParser::restorePosition(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(elems_stack.empty()) curr_elem=root_elem; else { curr_elem=elems_stack.top(); elems_stack.pop(); } } void XmlParser::restorePosition(const xmlNode *elem) { if(!elem) throw Exception(ErrorCode::OprNotAllocatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(elem->doc!=xml_doc) throw Exception(ErrorCode::OprInexistentElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); restartNavigation(); curr_elem=const_cast(elem); } void XmlParser::restartNavigation(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); curr_elem=root_elem; while(!elems_stack.empty()) elems_stack.pop(); } void XmlParser::restartParser(void) { root_elem=curr_elem=nullptr; curr_line = 0; if(xml_doc) { xmlFreeDoc(xml_doc); xml_doc=nullptr; } dtd_decl=xml_buffer=xml_decl=QString(); while(!elems_stack.empty()) elems_stack.pop(); xml_doc_filename=QString(); xmlResetLastError(); } bool XmlParser::accessElement(unsigned elem_type) { bool has_elem; xmlNode *elems[4]; if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); elems[RootElement]=curr_elem->parent; elems[ChildElement]=curr_elem->children; elems[NextElement]=curr_elem->next; elems[PreviousElement]=curr_elem->prev; /* Checks whether the current element has the element that is to be accessed. The flag 'has_elem' is also used on the method return to indicate if the element has been accessed or not. */ has_elem=hasElement(elem_type); if(has_elem) { curr_elem=elems[elem_type]; /* NOTE: Due to XML2 implementation big line numbers are stored in the psvi * attribute so we need to convert the void* to char and convert it back to integer value */ if(curr_elem->line == 65535 && curr_elem->next && curr_elem->next->psvi != nullptr) { char hex_value[10] = ""; int aux_line = 0; sprintf(hex_value, "%p", curr_elem->next->psvi); aux_line = static_cast(strtol(hex_value, nullptr, 16)); if(curr_line < aux_line) curr_line = aux_line; } else if(curr_elem->line > curr_line) curr_line = curr_elem->line; } return(has_elem); } bool XmlParser::hasElement(unsigned elem_type, xmlElementType xml_node_type) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(elem_type==RootElement) /* Returns the verification if the current element has a parent. The element must be different from the root, because the root element is not connected to a parent */ return(curr_elem!=root_elem && curr_elem->parent!=nullptr && (xml_node_type==0 || (xml_node_type!=0 && curr_elem->parent->type==xml_node_type))); else if(elem_type==ChildElement) //Returns the verification if the current element has children return(curr_elem->children!=nullptr && (xml_node_type==0 || (xml_node_type!=0 && curr_elem->children->type==xml_node_type))); else if(elem_type==NextElement) return(curr_elem->next!=nullptr && (xml_node_type==0 || (xml_node_type!=0 && curr_elem->next->type==xml_node_type))); else /* The second comparison in the expression is made for the root element because libxml2 places the previous element as the root itself */ return(curr_elem->prev!=nullptr && curr_elem->prev!=root_elem && (xml_node_type==0 || (xml_node_type!=0 && curr_elem->prev->type==xml_node_type))); } bool XmlParser::hasAttributes(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(curr_elem->properties!=nullptr); } QString XmlParser::getElementContent(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* If the current element has node returns the content of the CDATA instead of return the content of the element itself */ if(curr_elem->next && curr_elem->next->type == XML_CDATA_SECTION_NODE) return(QString(reinterpret_cast(curr_elem->next->content))); else //Return the content of the element when is not a CDATA node return(QString(reinterpret_cast(curr_elem->content))); } QString XmlParser::getElementName(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(QString(reinterpret_cast(curr_elem->name))); } xmlElementType XmlParser::getElementType(void) { if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(curr_elem->type); } const xmlNode *XmlParser::getCurrentElement(void) { return(curr_elem); } void XmlParser::getElementAttributes(attribs_map &attributes) { xmlAttr *elem_attribs=nullptr; QString attrib, value; if(!root_elem) throw Exception(ErrorCode::OprNotAllocatedElementTree,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Always clears the passed attributes maps attributes.clear(); //Gets the references to the element properties elem_attribs=curr_elem->properties; while(elem_attribs) { //Gets the attribute name attrib=QString(reinterpret_cast(elem_attribs->name)); //Gets the attribute value value=QString(reinterpret_cast(elem_attribs->children->content)); /* Assigns to the attribute map in the index specified by the attribute name the obtained value */ attributes[attrib]=value; //Step to the next element attribute elem_attribs=elem_attribs->next; } } QString XmlParser::getLoadedFilename(void) { return(xml_doc_filename); } QString XmlParser::getXMLBuffer(void) { return(xml_buffer); } int XmlParser::getCurrentBufferLine(void) { if(curr_elem) return(curr_line); else return(0); } int XmlParser::getBufferLineCount(void) { if(xml_doc) { /* To get the very last line of the document is necessary to call the last element of the last because xml_doc->last->line stores the last line of the root element. NOTE: Due to XML2 implementation big line numbers are stored in the psvi attribute so we need to convert the void* to char and convert it back to integer value */ if(xml_doc->last->last->line == 65535 && xml_doc->last->last->psvi != nullptr) { char hex_value[10] = ""; sprintf(hex_value, "%p", xml_doc->last->last->psvi); return(static_cast(strtol(hex_value, nullptr, 16))); } return(xml_doc->last->last->line); } else return(0); } pgmodeler-0.9.2/libparsers/src/xmlparser.h000066400000000000000000000131321360462764600206410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libparsers \class XMLParser \brief This class implements basic operations of a xml analyzer encapsulating some functions implemented by libxml2 library \note Creation date: 02/04/2008 */ #ifndef XML_PARSER_H #define XML_PARSER_H #include #include #include "schemaparser.h" #include "exception.h" #include #include #include "attribsmap.h" class XmlParser { private: /*! \brief Stores the name of the file that generated the xml buffer when loadXMLFile() method is called */ QString xml_doc_filename; //! \brief Stores the xml document (element tree) generated after the buffer reading xmlDoc *xml_doc; //! \brief Stores the approximated line position on the current parsed buffer int curr_line; //! \brief Stores the reference to the root element of the element tree xmlNode *root_elem, //! \brief Stores the current element that parser is analyzing *curr_elem; /*! \brief Stores the elements that marks the position in the tree before do a subsequent operation. To configure this element it is necessary call the method savePosition() and to return the navigation to the saved position is necessary call restorePosition() */ stack elems_stack; //! \brief Stores the document DTD declaration QString dtd_decl, //! \brief Stores XML document to be analyzed xml_buffer, /*! \brief Stores the declaration . If this isn't exists it will be a default declaration. */ xml_decl; /*! \brief Remove the original DTD from the document. This is done to evit that the user insert some external dtd in the model file that is not valid for pgModeler */ void removeDTD(void); /*! \brief Makes the interpretation of XML inside the buffer validating it according to DTD defined configured (by the parser) to the buffer. Initializes the necessary attributes to make possible the navigation through the element tree generated from the XML document read. */ void readBuffer(void); public: //! \brief Constants used to referência the elements on the element tree static constexpr unsigned RootElement=0, ChildElement=1, NextElement=2, PreviousElement=3; static const QString CharAmp, //! \brief & = & CharLt, //! \brief < = < CharGt, //! \brief < = > CharQuot, //! \brief < = " CharApos; //! \brief < = ' XmlParser(void); ~XmlParser(void); //! \brief Loads the XML buffer from a file void loadXMLFile(const QString &filename); //! \brief Loads the XML buffer from a string void loadXMLBuffer(const QString &xml_buf); //! \brief Informs the DTD file used to make element validations void setDTDFile(const QString &dtd_file, const QString &dtd_name); //! \brief Saves to stack the current navigation position on the element tree void savePosition(void); //! \brief Restores the previous navigation position oh the element tree void restorePosition(void); /*! \brief Restores the position of the navigation on a specific element on the document. The navigation stack is always emptied when this method is called */ void restorePosition(const xmlNode *elem); /*! \brief Moves one level in the element tree according to the type of element to be accessed. Returns true if the position was moved to the desired element. */ bool accessElement(unsigned elem_type); //! \brief Returns if an element has a root, child, previous or next element bool hasElement(unsigned elem_type, xmlElementType xml_node_type=static_cast(0)); //! \brief Retorns if an element has attributes bool hasAttributes(void); //! \brief Stores on a map the atrributes (names and values) of the current element void getElementAttributes(attribs_map &attributes); /*! \brief Returns the content text of the element, used only for elements which do not have children and that are filled by simple texts */ QString getElementContent(void); //! \brief Returns the current element type xmlElementType getElementType(void); //! \brief Returns the constant reference to the current element on the tree const xmlNode *getCurrentElement(void); //! \brief Returns the current line number on the buffer that is being processed int getCurrentBufferLine(void); //! \brief Returns the total line amount of the buffer int getBufferLineCount(void); //! \brief Returns the tag name that defines the current element QString getElementName(void); //! \brief Returns the filename that generated XML buffer QString getLoadedFilename(void); //! \brief Returns the full parser buffer QString getXMLBuffer(void); //! \brief Reset all the elements resposible to the navigation through the element tree void restartNavigation(void); /*! \brief Reset all the parser attributes, deallocating the element tree. The user have to reload the file to analyze it again */ void restartParser(void); }; #endif pgmodeler-0.9.2/libpgconnector/000077500000000000000000000000001360462764600165265ustar00rootroot00000000000000pgmodeler-0.9.2/libpgconnector/libpgconnector.pro000066400000000000000000000022331360462764600222600ustar00rootroot00000000000000# libpgconnector.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = lib TARGET = pgconnector windows: DESTDIR = $$PWD HEADERS += src/resultset.h \ src/connection.h \ src/catalog.h SOURCES += src/resultset.cpp \ src/connection.cpp \ src/catalog.cpp unix|windows: LIBS += $$PGSQL_LIB\ -L$$OUT_PWD/../libpgmodeler/ -lpgmodeler \ -L$$OUT_PWD/../libparsers/ -lparsers \ -L$$OUT_PWD/../libutils/ -lutils INCLUDEPATH += $$PWD/../libpgmodeler/src \ $$PWD/../libparsers/src \ $$PWD/../libutils/src DEPENDPATH += $$PWD/../libpgmodeler \ $$PWD/../libparsers \ $$PWD/../libutils # Deployment settings target.path = $$PRIVATELIBDIR INSTALLS = target pgmodeler-0.9.2/libpgconnector/src/000077500000000000000000000000001360462764600173155ustar00rootroot00000000000000pgmodeler-0.9.2/libpgconnector/src/catalog.cpp000066400000000000000000000634251360462764600214450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "catalog.h" const QString Catalog::QueryList=QString("list"); const QString Catalog::QueryAttribs=QString("attribs"); const QString Catalog::CatalogSchemasDir=QString("catalog"); const QString Catalog::PgSqlTrue=QString("t"); const QString Catalog::PgSqlFalse=QString("f"); const QString Catalog::BoolField=QString("_bool"); const QString Catalog::ArrayPattern=QString("((\\[)[0-9]+(\\:)[0-9]+(\\])=)?(\\{)((.)+(,)*)*(\\})$"); const QString Catalog::GetExtensionObjsSql=QString("SELECT objid AS oid FROM pg_depend WHERE objid > 0 AND refobjid > 0 AND deptype='e'"); const QString Catalog::PgModelerTempDbObj=QString("__pgmodeler_tmp"); attribs_map Catalog::catalog_queries; map Catalog::oid_fields= { {ObjectType::Database, "oid"}, {ObjectType::Role, "oid"}, {ObjectType::Schema,"oid"}, {ObjectType::Language, "oid"}, {ObjectType::Tablespace, "oid"}, {ObjectType::Extension, "ex.oid"}, {ObjectType::Function, "pr.oid"}, {ObjectType::Aggregate, "pr.oid"}, {ObjectType::Operator, "op.oid"}, {ObjectType::OpClass, "op.oid"}, {ObjectType::OpFamily, "op.oid"}, {ObjectType::Collation, "cl.oid"}, {ObjectType::Conversion, "cn.oid"}, {ObjectType::Cast, "cs.oid"}, {ObjectType::View, "vw.oid"}, {ObjectType::Sequence, "sq.oid"}, {ObjectType::Domain, "dm.oid"}, {ObjectType::Type, "tp.oid"}, {ObjectType::Table, "tb.oid"}, {ObjectType::Column, "cl.oid"}, {ObjectType::Constraint, "cs.oid"}, {ObjectType::Rule, "rl.oid"}, {ObjectType::Trigger, "tg.oid"}, {ObjectType::Index, "id.indexrelid"}, {ObjectType::EventTrigger, "et.oid"}, {ObjectType::Policy, "pl.oid"}, {ObjectType::ForeignDataWrapper, "fw.oid"}, {ObjectType::ForeignServer, "sv.oid"}, {ObjectType::UserMapping, "um.umid"}, {ObjectType::ForeignTable, "ft.oid"} }; map Catalog::ext_oid_fields={ {ObjectType::Constraint, "cs.conrelid"}, {ObjectType::Index, "id.indexrelid"}, {ObjectType::Trigger, "tg.tgrelid"}, {ObjectType::Rule, "rl.ev_class"}, {ObjectType::Policy, "pl.polrelid"} }; map Catalog::name_fields= { {ObjectType::Database, "datname"}, {ObjectType::Role, "rolname"}, {ObjectType::Schema,"nspname"}, {ObjectType::Language, "lanname"}, {ObjectType::Tablespace, "spcname"}, {ObjectType::Extension, "extname"}, {ObjectType::Function, "proname"}, {ObjectType::Aggregate, "proname"}, {ObjectType::Operator, "oprname"}, {ObjectType::OpClass, "opcname"}, {ObjectType::OpFamily, "opfname"}, {ObjectType::Collation, "collname"}, {ObjectType::Conversion, "conname"}, {ObjectType::Cast, ""}, {ObjectType::View, "relname"}, {ObjectType::Sequence, "relname"}, {ObjectType::Domain, "typname"}, {ObjectType::Type, "typname"}, {ObjectType::Table, "relname"}, {ObjectType::Column, "attname"}, {ObjectType::Constraint, "conname"}, {ObjectType::Rule, "rulename"}, {ObjectType::Trigger, "tgname"}, {ObjectType::Index, "relname"}, {ObjectType::EventTrigger, "evtname"}, {ObjectType::Policy, "polname"}, {ObjectType::ForeignDataWrapper, "fdwname"}, {ObjectType::ForeignServer, "srvname"}, {ObjectType::ForeignTable, "relname"} }; Catalog::Catalog(void) { last_sys_oid=0; setFilter(ExclExtensionObjs | ExclSystemObjs); } Catalog::Catalog(const Catalog &catalog) { (*this)=catalog; } void Catalog::setConnection(Connection &conn) { try { ResultSet res; QStringList ext_obj; connection.close(); connection.setConnectionParams(conn.getConnectionParams()); connection.connect(); //Retrieving the last system oid executeCatalogQuery(QueryList, ObjectType::Database, res, true, {{Attributes::Name, conn.getConnectionParam(Connection::ParamDbName)}}); if(res.accessTuple(ResultSet::FirstTuple)) { attribs_map attribs=changeAttributeNames(res.getTupleValues()); last_sys_oid=attribs[Attributes::LastSysOid].toUInt(); } //Retrieving the list of objects created by extensions this->connection.executeDMLCommand(GetExtensionObjsSql, res); if(res.accessTuple(ResultSet::FirstTuple)) { do { ext_obj.push_back(res.getColumnValue(QString("oid"))); } while(res.accessTuple(ResultSet::NextTuple)); ext_obj_oids=ext_obj.join(','); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Catalog::closeConnection(void) { connection.close(); } void Catalog::setFilter(unsigned filter) { bool list_all=(ListAllObjects & filter) == ListAllObjects; this->filter=filter; list_only_sys_objs=false; exclude_array_types=(ExclBuiltinArrayTypes & filter) == ExclBuiltinArrayTypes; exclude_ext_objs=(ExclExtensionObjs & filter) == ExclExtensionObjs; exclude_sys_objs=(ExclSystemObjs & filter) == ExclSystemObjs; if(!list_all) { list_only_sys_objs=(ListOnlySystemObjs & filter) == ListOnlySystemObjs; if(list_only_sys_objs) { exclude_ext_objs=true; exclude_sys_objs=false; } } } unsigned Catalog::getLastSysObjectOID(void) { return(last_sys_oid); } bool Catalog::isSystemObject(unsigned oid) { return(oid <= last_sys_oid); } bool Catalog::isExtensionObject(unsigned oid) { return(ext_obj_oids.contains(QString::number(oid))); } void Catalog::loadCatalogQuery(const QString &qry_id) { if(catalog_queries.count(qry_id)==0) { QFile input; input.setFileName(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + CatalogSchemasDir + GlobalAttributes::DirSeparator + qry_id + GlobalAttributes::SchemaExt); if(!input.open(QFile::ReadOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(input.fileName()), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); catalog_queries[qry_id]=QString(input.readAll()); input.close(); } schparser.loadBuffer(catalog_queries[qry_id]); } QString Catalog::getCatalogQuery(const QString &qry_type, ObjectType obj_type, bool single_result, attribs_map attribs) { QString sql, custom_filter; /* Escaping apostrophe (') in the attributes values to avoid SQL errors * due to support to this char in the middle of objects' names */ for(auto &attr : attribs) { if(attr.first != Attributes::CustomFilter && attr.second.contains(QChar('\''))) attr.second.replace(QChar('\''), QString("''")); } schparser.setPgSQLVersion(connection.getPgSQLVersion(true)); attribs[qry_type]=Attributes::True; if(exclude_sys_objs || list_only_sys_objs) attribs[Attributes::LastSysOid]=QString("%1").arg(last_sys_oid); if(list_only_sys_objs) attribs[Attributes::OidFilterOp]=QString("<="); else attribs[Attributes::OidFilterOp]=QString(">"); if(obj_type==ObjectType::Type && exclude_array_types) attribs[Attributes::ExcBuiltinArrays]=Attributes::True; //Checking if the custom filter expression is present if(attribs.count(Attributes::CustomFilter)) { custom_filter=attribs[Attributes::CustomFilter]; attribs.erase(Attributes::CustomFilter); } if(exclude_ext_objs && obj_type!=ObjectType::Database && obj_type!=ObjectType::Role && obj_type!=ObjectType::Tablespace && obj_type!=ObjectType::Extension) { if(ext_oid_fields.count(obj_type)==0) attribs[Attributes::NotExtObject]=getNotExtObjectQuery(oid_fields[obj_type]); else attribs[Attributes::NotExtObject]=getNotExtObjectQuery(ext_oid_fields[obj_type]); } loadCatalogQuery(BaseObject::getSchemaName(obj_type)); schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); attribs[Attributes::PgSqlVersion]=schparser.getPgSQLVersion(); sql=schparser.getCodeDefinition(attribs).simplified(); //Appeding the custom filter to the whole catalog query if(!custom_filter.isEmpty()) { int order_by_idx = sql.indexOf(QString("ORDER BY"), 0, Qt::CaseInsensitive); if(order_by_idx < 0) order_by_idx = sql.length(); if(!sql.contains(QString("WHERE"), Qt::CaseInsensitive)) sql.insert(order_by_idx, QString(" WHERE ") + custom_filter); else sql.insert(order_by_idx, QString(" AND (%1) ").arg(custom_filter)); } //Append a LIMIT clause when the single_result is set if(single_result) { if(sql.endsWith(';')) sql.remove(sql.size()-1, 1); sql+=QString(" LIMIT 1"); } return(sql); } void Catalog::executeCatalogQuery(const QString &qry_type, ObjectType obj_type, ResultSet &result, bool single_result, attribs_map attribs) { try { connection.executeDMLCommand(getCatalogQuery(qry_type, obj_type, single_result, attribs), result); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QString("catalog: %1").arg(BaseObject::getSchemaName(obj_type))); } } unsigned Catalog::getObjectCount(ObjectType obj_type, const QString &sch_name, const QString &tab_name, attribs_map extra_attribs) { try { ResultSet res; extra_attribs[Attributes::Schema]=sch_name; extra_attribs[Attributes::Table]=tab_name; executeCatalogQuery(QueryList, obj_type, res, false, extra_attribs); res.accessTuple(ResultSet::FirstTuple); return(res.getTupleCount()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } unsigned Catalog::getFilter(void) { return(filter); } void Catalog::getObjectsOIDs(map > &obj_oids, map > &col_oids, attribs_map extra_attribs) { try { vector types=BaseObject::getObjectTypes(true, { ObjectType::Database, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Textbox, ObjectType::Tag, ObjectType::Column, ObjectType::Permission, ObjectType::GenericSql }); attribs_map attribs, col_attribs, sch_names; vector tab_attribs; unsigned tab_oid=0; for(ObjectType type : types) { attribs=getObjectsNames(type, QString(), QString(), extra_attribs); for(auto &attr : attribs) { obj_oids[type].push_back(attr.first.toUInt()); //Store the schemas names in order to retrieve the tables' columns correctly if(type==ObjectType::Schema) sch_names[attr.first]=attr.second; else if(type==ObjectType::Table) { //Get the full set of attributes of the table tab_oid=attr.first.toUInt(); tab_attribs=getObjectsAttributes(type, QString(), QString(), { tab_oid }); //Retrieve the oid and names of the table's columns col_attribs=getObjectsNames(ObjectType::Column, sch_names[tab_attribs[0][Attributes::Schema]], attr.second); for(auto &col_attr : col_attribs) col_oids[tab_oid].push_back(col_attr.first.toUInt()); } } } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } attribs_map Catalog::getObjectsNames(ObjectType obj_type, const QString &sch_name, const QString &tab_name, attribs_map extra_attribs) { try { ResultSet res; attribs_map objects; extra_attribs[Attributes::Schema]=sch_name; extra_attribs[Attributes::Table]=tab_name; executeCatalogQuery(QueryList, obj_type, res, false, extra_attribs); if(res.accessTuple(ResultSet::FirstTuple)) { do { objects[res.getColumnValue(Attributes::Oid)]=res.getColumnValue(Attributes::Name); } while(res.accessTuple(ResultSet::NextTuple)); } return(objects); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } vector Catalog::getObjectsNames(vector obj_types, const QString &sch_name, const QString &tab_name, attribs_map extra_attribs, bool sort_results) { try { ResultSet res; vector objects; QString sql, select_kw=QString("SELECT"); QStringList queries; attribs_map attribs; extra_attribs[Attributes::Schema]=sch_name; extra_attribs[Attributes::Table]=tab_name; for(ObjectType obj_type : obj_types) { //Build the catalog query for the specified object type sql=getCatalogQuery(QueryList, obj_type, false, extra_attribs); /* For certain objects the catalog query will be empty due to the absence of that kind of element in the version of the database. E.g.: Event triggers does not exists in PgSQL < 9.3 */ if(!sql.isEmpty()) { //Injecting the object type integer code in order to sort the final result sql.replace(sql.indexOf(select_kw), select_kw.size(), QString("%1 %2 AS object_type, ").arg(select_kw).arg(enum_cast(obj_type))); sql+=QChar('\n'); queries.push_back(sql); } } //Joining the generated queries by using union in order to retrieve all results at once sql = QChar('(') + queries.join(QString(") UNION (")) + QChar(')'); if(sort_results) sql += QString(" ORDER BY oid, object_type"); connection.executeDMLCommand(sql, res); if(res.accessTuple(ResultSet::FirstTuple)) { do { attribs[Attributes::Oid]=res.getColumnValue(Attributes::Oid); attribs[Attributes::Name]=res.getColumnValue(Attributes::Name); attribs[Attributes::ObjectType]=res.getColumnValue(QString("object_type")); objects.push_back(attribs); attribs.clear(); } while(res.accessTuple(ResultSet::NextTuple)); } return(objects); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } attribs_map Catalog::getAttributes(const QString &obj_name, ObjectType obj_type, attribs_map extra_attribs) { try { ResultSet res; attribs_map obj_attribs; //Add the name of the object as extra attrib in order to retrieve the data only for it extra_attribs[Attributes::Name]=obj_name; executeCatalogQuery(QueryAttribs, obj_type, res, true, extra_attribs); if(res.accessTuple(ResultSet::FirstTuple)) obj_attribs=changeAttributeNames(res.getTupleValues()); /* Insert the object type as an attribute of the query result to facilitate the import process on the classes that uses the Catalog */ obj_attribs[Attributes::ObjectType]=QString("%1").arg(enum_cast(obj_type)); return(obj_attribs); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } vector Catalog::getMultipleAttributes(ObjectType obj_type, attribs_map extra_attribs) { try { ResultSet res; attribs_map tuple; vector obj_attribs; executeCatalogQuery(QueryAttribs, obj_type, res, false, extra_attribs); if(res.accessTuple(ResultSet::FirstTuple)) { do { tuple=changeAttributeNames(res.getTupleValues()); /* Insert the object type as an attribute of the query result to facilitate the import process on the classes that uses the Catalog */ tuple[Attributes::ObjectType]=QString("%1").arg(enum_cast(obj_type)); obj_attribs.push_back(tuple); tuple.clear(); } while(res.accessTuple(ResultSet::NextTuple)); } return(obj_attribs); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } vector Catalog::getMultipleAttributes(const QString &catalog_sch, attribs_map attribs) { try { ResultSet res; attribs_map tuple; vector obj_attribs; loadCatalogQuery(catalog_sch); schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); attribs[Attributes::PgSqlVersion]=schparser.getPgSQLVersion(); connection.executeDMLCommand(schparser.getCodeDefinition(attribs).simplified(), res); if(res.accessTuple(ResultSet::FirstTuple)) { do { tuple=changeAttributeNames(res.getTupleValues()); obj_attribs.push_back(tuple); tuple.clear(); } while(res.accessTuple(ResultSet::NextTuple)); } return(obj_attribs); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString Catalog::getCommentQuery(const QString &oid_field, bool is_shared_obj) { QString query_id=Attributes::Comment; try { attribs_map attribs={{Attributes::Oid, oid_field}, {Attributes::SharedObj, (is_shared_obj ? Attributes::True : QString())}}; loadCatalogQuery(query_id); return(schparser.getCodeDefinition(attribs).simplified()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QString("catalog: %1").arg(query_id)); } } QString Catalog::getNotExtObjectQuery(const QString &oid_field) { QString query_id=QString("notextobject"); try { attribs_map attribs={{Attributes::Oid, oid_field}, {Attributes::ExtObjOids, ext_obj_oids}}; loadCatalogQuery(query_id); return(schparser.getCodeDefinition(attribs).simplified()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QString("catalog: %1").arg(query_id)); } } attribs_map Catalog::changeAttributeNames(const attribs_map &attribs) { attribs_map::const_iterator itr=attribs.begin(); attribs_map new_attribs; QString attr_name, value; while(itr!=attribs.end()) { attr_name=itr->first; value=itr->second; if(attr_name.endsWith(BoolField)) { attr_name.remove(BoolField); if(value==PgSqlFalse) value.clear(); else value=Attributes::True; } attr_name.replace('_','-'); new_attribs[attr_name]=value; itr++; } return(new_attribs); } QString Catalog::createOidFilter(const vector &oids) { QString filter; for(unsigned i=0; i < oids.size(); i++) filter+=QString("%1,").arg(oids.at(i)); if(!filter.isEmpty()) filter.remove(filter.size()-1,1); return(filter); } vector Catalog::getObjectsAttributes(ObjectType obj_type, const QString &schema, const QString &table, const vector &filter_oids, attribs_map extra_attribs) { try { bool is_shared_obj=(obj_type==ObjectType::Database || obj_type==ObjectType::Role || obj_type==ObjectType::Tablespace || obj_type==ObjectType::Language || obj_type==ObjectType::Cast); extra_attribs[Attributes::Schema]=schema; extra_attribs[Attributes::Table]=table; if(!filter_oids.empty()) extra_attribs[Attributes::FilterOids]=createOidFilter(filter_oids); //Retrieve the comment catalog query. Only columns need to retreive comments in their own catalog query file if(obj_type != ObjectType::Column) extra_attribs[Attributes::Comment]=getCommentQuery(oid_fields[obj_type], is_shared_obj); return(getMultipleAttributes(obj_type, extra_attribs)); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QApplication::translate("Catalog","Object type: %1","", -1).arg(BaseObject::getSchemaName(obj_type))); } } attribs_map Catalog::getObjectAttributes(ObjectType obj_type, unsigned oid, const QString sch_name, const QString tab_name, attribs_map extra_attribs) { try { vector attribs_vect=getObjectsAttributes(obj_type, sch_name, tab_name, { oid }, extra_attribs); return(attribs_vect.empty() ? attribs_map() : attribs_vect[0]); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QApplication::translate("Catalog","Object type: %1","", -1).arg(BaseObject::getSchemaName(obj_type))); } } QString Catalog::getObjectOID(const QString &name, ObjectType obj_type, const QString &schema, const QString &table) { try { attribs_map attribs; ResultSet res; attribs[Attributes::CustomFilter] = QString("%1 = E'%2'").arg(name_fields[obj_type]).arg(name); attribs[Attributes::Schema] = schema; attribs[Attributes::Table] = table; executeCatalogQuery(QueryList, obj_type, res, false, attribs); if(res.getTupleCount() > 1) throw Exception(QApplication::translate("Catalog","The catalog query returned more than one OID!","", -1), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(res.isEmpty()) return("0"); else { res.accessTuple(ResultSet::FirstTuple); return(res.getColumnValue(Attributes::Oid)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QApplication::translate("Catalog","Object type: %1","", -1).arg(BaseObject::getSchemaName(obj_type))); } } attribs_map Catalog::getServerAttributes(void) { attribs_map attribs; try { ResultSet res = ResultSet(); QString sql, attr_name; attribs_map tuple, attribs_aux; loadCatalogQuery(QString("server")); schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); sql = schparser.getCodeDefinition(attribs).simplified(); connection.executeDMLCommand(sql, res); if(res.accessTuple(ResultSet::FirstTuple)) { do { tuple=res.getTupleValues(); attr_name = tuple[Attributes::Attribute]; attr_name.replace('_','-'); attribs[attr_name]=tuple[Attributes::Value]; } while(res.accessTuple(ResultSet::NextTuple)); attribs[Attributes::Connection] = connection.getConnectionId(); attribs_aux = connection.getServerInfo(); attribs.insert(attribs_aux.begin(), attribs_aux.end()) ; } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, QApplication::translate("Catalog","Object type: server","", -1)); } return(attribs); } QStringList Catalog::parseArrayValues(const QString &array_val) { QStringList list; if(QRegExp(ArrayPattern).exactMatch(array_val)) { //Detecting the position of { and } int start=array_val.indexOf('{')+1, end=array_val.lastIndexOf('}')-1; QString value=array_val.mid(start, (end - start)+1); if(value.contains('"')) list=parseDefaultValues(value, QString("\""), QString(",")); else list=value.split(',', QString::SkipEmptyParts); } return(list); } QStringList Catalog::parseDefaultValues(const QString &def_vals, const QString &str_delim, const QString &val_sep) { int idx=0, delim_start, delim_end, sep_idx, pos=0; QStringList values; while(idx < def_vals.size()) { //Get the index of string delimiters (default: ') delim_start=def_vals.indexOf(str_delim, idx); delim_end=def_vals.indexOf(str_delim, delim_start + 1); /* Get the index of value separator on default value string (by default the pg_get_expr separates values by comma and space (, ) */ sep_idx=def_vals.indexOf(val_sep, idx); /* If there is no separator on string (only one value) or the is beyond the string delimiters or even there is no string delimiter on string */ if(sep_idx < 0 || (sep_idx >=0 && delim_start >= 0 && delim_end >= 0 && (sep_idx < delim_start || sep_idx > delim_end)) || (sep_idx >=0 && (delim_start < 0 || delim_end < 0))) { //Extract the value from the current position values.push_back(def_vals.mid(pos, sep_idx-pos).trimmed()); //If there is no separator on string indicates that it contains only one value if(sep_idx < 0) //Forcing the loop abort idx=def_vals.size(); else { //Passing to the next value right after the separator pos=sep_idx+1; idx=pos; } } /* If the separator is between a string delimitation e.g.'abc, def' it will be ignored and the current postion will be moved to the first char after string delimiter */ else if(delim_start>=0 && delim_end >= 0 && sep_idx >= delim_start && sep_idx <=delim_end) { idx=delim_end+1; /* If the index reaches the end of string but the cursor (pos) isn't at end indicates that the last values wasn't retrieved, this way, the value will be pushed to list of values */ if(idx >= def_vals.size() && pos < def_vals.size()) values.push_back(def_vals.mid(pos, def_vals.size())); } else idx++; } return(values); } QStringList Catalog::parseRuleCommands(const QString &cmds) { int start=-1, end=-1; QRegExp cmd_regexp(QString("(DO)( )*(INSTEAD)*( )+")); start=cmd_regexp.indexIn(cmds) + cmd_regexp.matchedLength(); end=cmds.lastIndexOf(';'); return(cmds.mid(start,(end - start) + 1).split(';', QString::SkipEmptyParts)); } QStringList Catalog::parseIndexExpressions(const QString &expr) { int open_paren = 0, close_paren = 0, pos = 0; QStringList expressions; QChar chr; QString word; bool open_apos = false; if(!expr.isEmpty()) { while(pos < expr.length()) { chr = expr[pos++]; word += chr; if(chr == QChar('\'')) open_apos = !open_apos; if(!open_apos && chr == QChar('(')) open_paren++; else if(!open_apos && chr == QChar(')')) close_paren++; if(chr == QChar(',') || pos == expr.length()) { if(open_paren == close_paren) { if(word.endsWith(QChar(','))) word.remove(word.length() - 1, 1); if(word.contains('(') && word.contains(')')) expressions.push_back(word.trimmed()); else expressions.push_back(word); word.clear(); open_paren = close_paren = 0; } } } } return(expressions); } void Catalog::operator = (const Catalog &catalog) { try { this->ext_obj_oids=catalog.ext_obj_oids; this->connection.setConnectionParams(catalog.connection.getConnectionParams()); this->last_sys_oid=catalog.last_sys_oid; this->filter=catalog.filter; this->exclude_ext_objs=catalog.exclude_ext_objs; this->exclude_sys_objs=catalog.exclude_sys_objs; this->exclude_array_types=catalog.exclude_array_types; this->list_only_sys_objs=catalog.list_only_sys_objs; this->connection.connect(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgconnector/src/catalog.h000066400000000000000000000277761360462764600211230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgconnector \class Catalog \brief \brief Implements the operations to read data from information_schema as well from pg_catalog schema. This class is the basis for the reverse engineering feature. */ #ifndef CATALOG_H #define CATALOG_H #include "connection.h" #include "baseobject.h" #include "tableobject.h" #include #include class Catalog { private: SchemaParser schparser; static const QString QueryList, //! \brief Executes a list command on catalog QueryAttribs, //! \brief Executes a attribute retrieving command on catalog CatalogSchemasDir, //! \brief Default catalog schemas directory PgSqlTrue, //! \brief Replacement for true 't' boolean value PgSqlFalse, //! \brief Replacement for false 'f' boolean value BoolField, //! \brief Suffix for boolean fields. //! \brief Query used to retrieve extension objects. GetExtensionObjsSql, //! \brief This pattern matches the PostgreSQL array values in format [n:n]={a,b,c,d,...} or {a,b,c,d,...} ArrayPattern; /*! \brief Stores in comma seperated way the oids of all objects created by extensions. This attribute is use when filtering objects that are created by extensions */ QString ext_obj_oids; /*! \brief This map stores the oid field name for each object type. The oid field name can be composed by the pg_[OBJECT_TYPE] table alias. Refer to catalog query schema files for details */ static map oid_fields; /*! \brief This map stores the name field for each object type. Refer to catalog query schema files for details */ static map name_fields; /*! \brief This map stores the oid field name that is used to check if the object (or its parent) is part of a extension (see getNotExtObjectQuery()). By default the attribute oid_fields is used instead for that purpose, but, for some objects, there are different fields that tells if the object (or its parent) is part of extension. */ static map ext_oid_fields; //! \brief Store the cached catalog queries static attribs_map catalog_queries; //! \brief Connection used to query the pg_catalog Connection connection; //! \brief Stores the last system object identifier. This is used to filter system objects unsigned last_sys_oid, filter; //! \brief Indicates if the catalog must filter system objects bool exclude_sys_objs, //! \brief Indicates if the catalog must filter extension created objects exclude_ext_objs, //! \brief Indicates if the catalog must filter built-in array data types exclude_array_types, //! \brief Indicates if the catalog must list only system objects list_only_sys_objs; /*! \brief Load the schema parser buffer with the catalog query using identified by qry_id. The method will cache the catalog query if it's not cached yet (only when use_cached_queries=true) */ void loadCatalogQuery(const QString &qry_id); /*! \brief Executes a query on the catalog for the specified object type. If the parameter 'single_result' is true the query will return only one tuple on the result set. Additional attributes can be passed so that SchemaParser will use them when parsing the schema file for the object. A special extra attribute is accepted but not passed to SchemaParser: ParsersAttributes::CUSTOM_FILTER that will be appended to the current filter expression */ void executeCatalogQuery(const QString &qry_type, ObjectType obj_type, ResultSet &result, bool single_result=false, attribs_map attribs=attribs_map()); //! \brief Returns the catalog query according to the type of the object type provided QString getCatalogQuery(const QString &qry_type, ObjectType obj_type, bool single_result=false, attribs_map attribs=attribs_map()); /*! \brief Recreates the attribute map in such way that attribute names that have underscores have this char replaced by dashes. Another special operation made is to replace the values of fiels which suffix is _bool to '1' when 't' and to empty when 'f', this is because the resultant attribs_map will be passed to XMLParser/SchemaParser which understands bool values as 1 (one) or '' (empty) */ attribs_map changeAttributeNames(const attribs_map &attribs); //! \brief Returns a attribute set for the specified object type and name attribs_map getAttributes(const QString &obj_name, ObjectType obj_type, attribs_map extra_attribs=attribs_map()); /*! \brief Returns the query to retrieve the information if the object (specified by its oid field) is part or not of a extension. */ QString getNotExtObjectQuery(const QString &oid_field); /*! \brief Returns the query that is used to retrieve an objects comment. The 'is_shared_object' is used to query the pg_shdescription instead of pg_description */ QString getCommentQuery(const QString &oid_field, bool is_shared_obj=false); //! \brief Creates a comma separated string containing all the oids to be filtered QString createOidFilter(const vector &oids); public: Catalog(void); Catalog(const Catalog &catalog); //! \brief Stores the prefix of any temp object (in pg_temp) created during catalog reading by pgModeler static const QString PgModelerTempDbObj; //! \brief Excludes the system objects from listing static constexpr unsigned ExclSystemObjs=1, //! \brief Excludes the extension generated objects from listing ExclExtensionObjs=2, //! \brief Excludes the builtin array types. ExclBuiltinArrayTypes=4, /*! \brief Shows only system objects. Using this filter will disable the other two filters. Using this filter implies the listing of extension objects */ ListOnlySystemObjs=8, //! \brief Shows all objects including system objects and extension object. ListAllObjects=16; //! \brief Changes the current connection used by the catalog void setConnection(Connection &conn); /*! \brief Closes the connection used by the catalog. Once this method is called the user must call setConnection() again or the catalog queries will fail */ void closeConnection(void); //! \brief Configures the catalog query filter void setFilter(unsigned filter); //! \brief Returns the last system object oid registered on the database unsigned getLastSysObjectOID(void); //! \brief Returns if the specified oid is amongst the system objects' oids bool isSystemObject(unsigned oid); //! \brief Returns if the specified oid is amongst the extension created objects' oids bool isExtensionObject(unsigned oid); /*! \brief Returns the count for the specified object type. A schema name can be specified in order to filter only objects of the specifed schema */ unsigned getObjectCount(ObjectType obj_type, const QString &sch_name=QString(), const QString &tab_name=QString(), attribs_map extra_attribs=attribs_map()); //! \brief Returns the current filter configuration for the catalog unsigned getFilter(void); //! \brief Fills the specified maps with all object's oids querying the catalog with the specified filter void getObjectsOIDs(map > &obj_oids, map > &col_oids, attribs_map extra_attribs=attribs_map()); /*! \brief Returns a attributes map containing the oids (key) and names (values) of the objects from the specified type. A schema name can be specified in order to filter only objects of the specifed schema */ attribs_map getObjectsNames(ObjectType obj_type, const QString &sch_name=QString(), const QString &tab_name=QString(), attribs_map extra_attribs=attribs_map()); /*! \brief Returns a vector of attributes map containing the oids (key) and names as well types of the objects from the specified list of types. A schema name can be specified in order to filter only objects of the specifed schema */ vector getObjectsNames(vector obj_types, const QString &sch_name=QString(), const QString &tab_name=QString(), attribs_map extra_attribs=attribs_map(), bool sort_results=false); //! \brief Returns a set of multiple attributes (several tuples) for the specified object type vector getMultipleAttributes(ObjectType obj_type, attribs_map extra_attribs=attribs_map()); /*! \brief Returns a set of multiple attributes (several tuples) for the specified catalog schema file. * This version of the method differs from the one in which the user need to provide the object type. * This one, the user is responsible to provide all attributes that will be parsed together with the * catalog file. */ vector getMultipleAttributes(const QString &catalog_sch, attribs_map attribs=attribs_map()); /*! \brief Retrieve all available objects attributes for the specified type. Internally this method calls the get method for the specified type. User can filter items by oids (except for table child objects), by schema (in the object type is suitable to accept schema) and by table name (only when retriving child objects for a specific table) */ vector getObjectsAttributes(ObjectType obj_type, const QString &schema=QString(), const QString &table=QString(), const vector &filter_oids={}, attribs_map extra_attribs=attribs_map()); //! \brief Returns the attributes for the object specified by its type and OID attribs_map getObjectAttributes(ObjectType obj_type, unsigned oid, const QString sch_name=QString(), const QString tab_name=QString(), attribs_map extra_attribs=attribs_map()); /*! \brief Returns the OID of the named object. User can filter items by schema (if the object type is suitable to accept schema) and by table name (only when retriving child objects for a specific table). The method will raise an exception if the catalog query used returns more than one result. A zero OID is returned when no suitable object is found. */ QString getObjectOID(const QString &name, ObjectType obj_type, const QString &schema = QString(), const QString &table = QString()); //! brief This special method returns some server's attributes read from pg_settings attribs_map getServerAttributes(void); //! \brief Parse a PostgreSQL array value and return the elements in a string list static QStringList parseArrayValues(const QString &array_val); /*! \brief Parse a function's default value and return the elements in a string list. It can be specified the string delimiter as well the value separator if the input default value contains several values */ static QStringList parseDefaultValues(const QString &def_vals, const QString &str_delim=QString("'"), const QString &val_sep=QString(", ")); //! \brief Parse the raw commands of a rule retrieved by the catalog and returns only the relevant parts static QStringList parseRuleCommands(const QString &cmd); /*! \brief Parse a set of expressions related to an index returned by the pg_get_expr(oid) and separates * them as a string list. */ static QStringList parseIndexExpressions(const QString &expr); /*! \brief Enable/disable the use of cached catalog queries. When enabled, the schema files read for the first are stored in memory so in the next time the same catalog query must be used it'll be read right from the memory and not from the disk anymore */ static void enableCachedQueries(bool value); //! \brief Returns the current status of cached catalog queries static bool isCachedQueriesEnabled(void); //! \brief Performs the copy between two catalogs void operator = (const Catalog &catalog); }; #endif pgmodeler-0.9.2/libpgconnector/src/connection.cpp000066400000000000000000000344611360462764600221700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "connection.h" #include #include #include "attributes.h" const QString Connection::SslDisable=QString("disable"); const QString Connection::SslAllow=QString("allow"); const QString Connection::SslPrefer=QString("prefer"); const QString Connection::SslRequire=QString("require"); const QString Connection::SslCaVerify=QString("verify-ca"); const QString Connection::SslFullVerify=QString("verify-full"); const QString Connection::ParamAlias=QString("alias"); const QString Connection::ParamServerFqdn=QString("host"); const QString Connection::ParamServerIp=QString("hostaddr"); const QString Connection::ParamPort=QString("port"); const QString Connection::ParamDbName=QString("dbname"); const QString Connection::ParamUser=QString("user"); const QString Connection::ParamPassword=QString("password"); const QString Connection::ParamConnTimeout=QString("connect_timeout"); const QString Connection::ParamOthers=QString("options"); const QString Connection::ParamSslMode=QString("sslmode"); const QString Connection::ParamSslCert=QString("sslcert"); const QString Connection::ParamSslKey=QString("sslkey"); const QString Connection::ParamSslRootCert=QString("sslrootcert"); const QString Connection::ParamSslCrl=QString("sslcrl"); const QString Connection::ParamKerberosServer=QString("krbsrvname"); const QString Connection::ParamLibGssapi=QString("gsslib"); const QString Connection::ServerPid=QString("server-pid"); const QString Connection::ServerProtocol=QString("server-protocol"); const QString Connection::ServerVersion=QString("server-version"); bool Connection::notice_enabled=false; bool Connection::print_sql=false; bool Connection::silence_conn_err=true; QStringList Connection::notices; Connection::Connection(void) { connection=nullptr; auto_browse_db=false; cmd_exec_timeout=0; for(unsigned idx=OpValidation; idx <= OpDiff; idx++) default_for_oper[idx]=false; } Connection::Connection(const attribs_map ¶ms) : Connection() { setConnectionParams(params); } Connection::~Connection(void) { if(connection) { PQfinish(connection); connection=nullptr; } } void Connection::setSQLExecutionTimout(unsigned timeout) { cmd_exec_timeout=timeout; } void Connection::setConnectionParam(const QString ¶m, const QString &value) { //Regexp used to validate the host address QRegExp ip_regexp("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"); //Raise an error in case the param name is empty if(param.isEmpty()) throw Exception(ErrorCode::AsgInvalidConnParameter, __PRETTY_FUNCTION__, __FILE__, __LINE__); /* Set the value to the specified param on the map. One special case is treated here, if user use the parameter SERVER_FQDN and the value is a IP address, the method will assign the value to the SERVER_IP parameter */ if(param==ParamServerFqdn && ip_regexp.exactMatch(value)) { connection_params[Connection::ParamServerIp]=value; connection_params[Connection::ParamServerFqdn]=QString(); } else connection_params[param]=value; //Updates the connection string generateConnectionString(); } void Connection::setConnectionParams(const attribs_map ¶ms) { this->connection_params=params; generateConnectionString(); } void Connection::setAutoBrowseDB(bool value) { auto_browse_db=value; } void Connection::generateConnectionString(void) { QString value, param_str = QString("%1=%2 "); //Scans the parameter map concatening the params (itr->first) / values (itr->second) connection_str.clear(); for(auto &itr : connection_params) { if(itr.first!=ParamAlias) { value=itr.second; value.replace("\\","\\\\"); value.replace("'","\\'"); if(itr.first==ParamPassword && (value.contains(' ') || value.isEmpty())) value=QString("'%1'").arg(value); if(!value.isEmpty()) { if(itr.first==ParamDbName) connection_str.prepend(param_str.arg(itr.first).arg(value)); else if(itr.first!=ParamOthers) connection_str+=param_str.arg(itr.first).arg(value); else connection_str+=value; } } } if(!connection_str.contains(ParamDbName) || (!connection_str.contains(ParamServerFqdn) && !connection_str.contains(ParamServerIp))) connection_str.clear(); } void Connection::noticeProcessor(void *, const char *message) { notices.push_back(QString(message)); } void Connection::validateConnectionStatus(void) { if(cmd_exec_timeout > 0) { qint64 dt=(QDateTime::currentDateTime().toMSecsSinceEpoch() - last_cmd_execution.toMSecsSinceEpoch())/1000; if(dt >= cmd_exec_timeout) { close(); throw Exception(ErrorCode::ConnectionTimeout, __PRETTY_FUNCTION__, __FILE__, __LINE__); } } if(PQstatus(connection)==CONNECTION_BAD) throw Exception(Exception::getErrorMessage(ErrorCode::ConnectionBroken) .arg(connection_params[ParamServerFqdn].isEmpty() ? connection_params[ParamServerIp] : connection_params[ParamServerFqdn]) .arg(connection_params[ParamPort]), ErrorCode::ConnectionBroken, __PRETTY_FUNCTION__, __FILE__, __LINE__); } void Connection::setNoticeEnabled(bool value) { notice_enabled=value; } bool Connection::isNoticeEnabled(void) { return(notice_enabled); } void Connection::setPrintSQL(bool value) { print_sql=value; } bool Connection::isSQLPrinted(void) { return(print_sql); } void Connection::setSilenceConnError(bool value) { silence_conn_err=value; } bool Connection::isConnErrorSilenced(void) { return(silence_conn_err); } void Connection::connect(void) { /* If the connection string is not established indicates that the user is trying to connect without configuring connection parameters, thus an error is raised */ if(connection_str.isEmpty()) throw Exception(ErrorCode::ConnectionNotConfigured, __PRETTY_FUNCTION__, __FILE__, __LINE__); else if(connection) { if(!silence_conn_err) throw Exception(ErrorCode::ConnectionAlreadyStablished, __PRETTY_FUNCTION__, __FILE__, __LINE__); else { QTextStream err(stderr); err << QT_TR_NOOP("ERROR: trying to open an already stablished connection.") << endl << QString("Conn. info: [ ") << connection_str << QString("]") << endl; this->close(); } } //Try to connect to the database connection=PQconnectdb(connection_str.toStdString().c_str()); last_cmd_execution=QDateTime::currentDateTime(); /* If the connection descriptor has not been allocated or if the connection state is CONNECTION_BAD it indicates that the connection was not successful */ if(connection==nullptr || PQstatus(connection)==CONNECTION_BAD) { //Raise the error generated by the DBMS throw Exception(Exception::getErrorMessage(ErrorCode::ConnectionNotStablished) .arg(PQerrorMessage(connection)), ErrorCode::ConnectionNotStablished, __PRETTY_FUNCTION__, __FILE__, __LINE__); } notices.clear(); if(!notice_enabled) //Completely disable notice/warnings in the connection PQsetNoticeReceiver(connection, disableNoticeOutput, nullptr); else //Enable the notice/warnings in the connection by pushing them into the list of generated notices PQsetNoticeProcessor(connection, noticeProcessor, nullptr); } void Connection::close(void) { if(connection) { //Finalizes the connection if the status is OK if(PQstatus(connection)==CONNECTION_OK) PQfinish(connection); connection=nullptr; last_cmd_execution=QDateTime(); } } void Connection::reset(void) { //Raise an erro in case the user try to reset a not opened connection if(!connection) throw Exception(ErrorCode::OprNotAllocatedConnection, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Reinicia a conexão PQreset(connection); } QString Connection::getConnectionParam(const QString ¶m) { return(connection_params[param]); } attribs_map Connection::getConnectionParams(void) const { return(connection_params); } attribs_map Connection::getServerInfo(void) { attribs_map info; if(!connection) throw Exception(ErrorCode::OprNotAllocatedConnection,__PRETTY_FUNCTION__,__FILE__,__LINE__); info[ServerPid]=QString::number(PQbackendPID(connection)); info[ServerVersion]=getPgSQLVersion(); info[ServerProtocol]=QString::number(PQprotocolVersion(connection)); return(info); } QString Connection::getConnectionString(void) { return(connection_str); } QString Connection::getConnectionId(bool host_port_only, bool incl_db_name) { QString addr, db_name, port; if(!isConfigured()) return(QString()); if(!connection_params[ParamServerFqdn].isEmpty()) addr=connection_params[ParamServerFqdn]; else addr=connection_params[ParamServerIp]; if(!connection_params[ParamPort].isEmpty()) port = QString(":%1").arg(connection_params[ParamPort]); if(incl_db_name) db_name = QString("%1@").arg(connection_params[ParamDbName]); if(host_port_only) return(QString("%1%2%3").arg(db_name, addr, port)); else return(QString("%1%2 (%3%4)").arg(db_name, connection_params[ParamAlias], addr, port)); } bool Connection::isStablished(void) { return(connection!=nullptr); } bool Connection::isConfigured(void) { return(!connection_str.isEmpty()); } bool Connection::isAutoBrowseDB(void) { return(auto_browse_db); } QString Connection::getPgSQLVersion(bool major_only) { QString raw_ver, fmt_ver; if(!connection) throw Exception(ErrorCode::OprNotAllocatedConnection, __PRETTY_FUNCTION__, __FILE__, __LINE__); raw_ver=QString("%1").arg(PQserverVersion(connection)); //If the version is 10+ if(raw_ver.contains(QRegExp("^((1)[0-9])(.)+"))) { //New PostgreSQL 10+ versioning: 100001 means 10.1 (Major.Minor) fmt_ver=QString("%1.%2") .arg(raw_ver.mid(0,2)) .arg(raw_ver.mid(3,1).toInt()); if(!major_only) return(QString("%1.%2").arg(raw_ver.mid(0,2)).arg(raw_ver.mid(4,2).toInt())); } //For versions below or equal to 9.6 else { fmt_ver=QString("%1.%2") .arg(raw_ver.mid(0,2).toInt()/10) .arg(raw_ver.mid(2,2).toInt()/10); if(!major_only) return(QString("%1.%2").arg(fmt_ver).arg(raw_ver.mid(4,1))); } return(fmt_ver); } QStringList Connection::getNotices(void) { return (notices); } void Connection::executeDMLCommand(const QString &sql, ResultSet &result) { ResultSet *new_res=nullptr; PGresult *sql_res=nullptr; //Raise an error in case the user try to close a not opened connection if(!connection) throw Exception(ErrorCode::OprNotAllocatedConnection, __PRETTY_FUNCTION__, __FILE__, __LINE__); validateConnectionStatus(); notices.clear(); //Alocates a new result to receive the resultset returned by the sql command sql_res=PQexec(connection, sql.toStdString().c_str()); //Prints the SQL to stdout when the flag is active if(print_sql) { QTextStream out(stdout); out << QString("\n---\n") << sql << endl; } //Raise an error in case the command sql execution is not sucessful if(strlen(PQerrorMessage(connection))>0) { throw Exception(Exception::getErrorMessage(ErrorCode::SQLCommandNotExecuted) .arg(PQerrorMessage(connection)), ErrorCode::SQLCommandNotExecuted, __PRETTY_FUNCTION__, __FILE__, __LINE__, nullptr, QString(PQresultErrorField(sql_res, PG_DIAG_SQLSTATE))); } //Generates the resultset based on the sql result descriptor new_res=new ResultSet(sql_res); //Copy the new resultset to the parameter resultset result=*(new_res); //Deallocate the new resultset delete(new_res); PQclear(sql_res); } void Connection::executeDDLCommand(const QString &sql) { PGresult *sql_res=nullptr; //Raise an error in case the user try to close a not opened connection if(!connection) throw Exception(ErrorCode::OprNotAllocatedConnection, __PRETTY_FUNCTION__, __FILE__, __LINE__); validateConnectionStatus(); notices.clear(); sql_res=PQexec(connection, sql.toStdString().c_str()); //Prints the SQL to stdout when the flag is active if(print_sql) { QTextStream out(stdout); out << QString("\n---\n") << sql << endl; } //Raise an error in case the command sql execution is not sucessful if(strlen(PQerrorMessage(connection)) > 0) { QString field = QString(PQresultErrorField(sql_res, PG_DIAG_SQLSTATE)); PQclear(sql_res); throw Exception(Exception::getErrorMessage(ErrorCode::SQLCommandNotExecuted) .arg(PQerrorMessage(connection)), ErrorCode::SQLCommandNotExecuted, __PRETTY_FUNCTION__, __FILE__, __LINE__, nullptr, field); } PQclear(sql_res); } void Connection::setDefaultForOperation(unsigned op_id, bool value) { if(op_id > OpNone) throw Exception(ErrorCode::RefElementInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); else if(op_id!=OpNone) default_for_oper[op_id]=value; } bool Connection::isDefaultForOperation(unsigned op_id) { if(op_id > OpNone) throw Exception(ErrorCode::RefElementInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); else if(op_id==OpNone) return(false); return(default_for_oper[op_id]); } void Connection::switchToDatabase(const QString &dbname) { QString prev_dbname=connection_params[ParamDbName]; try { //Closing the current connection if it's opened if(isStablished()) close(); //Change the database name and reconfigure the connection string connection_params[ParamDbName]=dbname; generateConnectionString(); //Reopen connection connect(); } catch(Exception &e) { connection_params[ParamDbName]=prev_dbname; connect(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Connection::operator = (const Connection &conn) { if(this->isStablished()) this->close(); this->auto_browse_db=conn.auto_browse_db; this->connection_params=conn.connection_params; this->connection_str=conn.connection_str; this->connection=nullptr; for(unsigned idx=OpValidation; idx <= OpDiff; idx++) default_for_oper[idx]=conn.default_for_oper[idx]; } void Connection::requestCancel(void) { if(!connection) throw Exception(ErrorCode::OprNotAllocatedConnection, __PRETTY_FUNCTION__, __FILE__, __LINE__); PQrequestCancel(connection); } pgmodeler-0.9.2/libpgconnector/src/connection.h000066400000000000000000000216561360462764600216370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgconnector \class Connection \brief This class encapsulates some connection manipulation functions implemented by the PostgreSQL libpq \note Creation date: 13/07/2009 */ #ifndef CONNECTION_H #define CONNECTION_H #include "resultset.h" #include "attribsmap.h" #include #include class Connection { private: //! \brief Database connection descriptor PGconn *connection; //! \brief Parameters map used to generate the connection string attribs_map connection_params; //! \brief Formated connection string QString connection_str; /*! \brief Date-time value used to check the timeout between commands execution. This attribute is used to abort the command execution to avoid program crashes if the connection is closed by the server due to timeouts */ QDateTime last_cmd_execution; /*! \brief Stores the maximum timeout (in seconds) between two command executions. A zero value means no timeout in this case the validateConnection() will not raise errors related to the exceeded timeout */ unsigned cmd_exec_timeout; /*! \brief List of notices generated during the command execution The list is filled only if notice_enabled is true */ static QStringList notices; //! \brief Generates the connection string based on the parameter map void generateConnectionString(void); /*! \brief This static method disable the notice messages when executing commands. By default all connections are created with notice disabled. To enable it the user must call Connection::setNoticeEnabled(). Note: connections already stablished aren't affected when calling this method the user must disconnect then connect again to enable output. */ static void disableNoticeOutput(void *, const PGresult *){} /*! \brief This function overrides the default notice handler of the connections and captures and stores all message in a string list that can be retrieved by the user for later usage */ static void noticeProcessor(void *, const char *message); //! \brief Indicates if notices are enabled static bool notice_enabled, //! \brief Indicates if executed sql must be printed (stdout) [default is false] print_sql, //! \brief Indicates if error silence is enabled silence_conn_err; /*! \brief Indicates that the initial database configured in the connection can be automatically browsed after connect the server. This attribute is useful only in SQLTool */ bool auto_browse_db, /*! \brief Indicates in which operations (diff, export, import, validation) the connection is used if none is explicitly specified by the user in the UI */ default_for_oper[4]; /*! \brief Validates the connection status (command exec. timeout and connection status) and raise errors in case of exceeded timeout or bad connection. This method is called prior any command execution */ void validateConnectionStatus(void); public: //! \brief Constants used to reference the connections parameters static const QString ParamAlias, ParamServerFqdn, ParamServerIp, ParamPort, ParamDbName, ParamUser, ParamPassword, ParamConnTimeout, ParamOthers, ParamSslMode, ParamSslCert, ParamSslKey, ParamSslRootCert, ParamSslCrl, ParamKerberosServer, ParamLibGssapi, SslDisable, SslAllow, SslPrefer, SslRequire, SslCaVerify, SslFullVerify; //! \brief Constants used to reference the server info details (see getServerInfo()) static const QString ServerVersion, ServerProtocol, ServerPid; //! \brief Constants used to reference the default usage in model operations (see setDefaultForOperation()) static constexpr unsigned OpValidation=0, OpExport=1, OpImport=2, OpDiff=3, OpNone=4; Connection(void); Connection(const attribs_map ¶ms); ~Connection(void); /*! \brief Set the maximum timeout that a connectio can be idle (without running commands) Setting a zero value will cause not timemout checking */ void setSQLExecutionTimout(unsigned timeout); //! \brief Toggles the notice output for connections. By default any notice are omitted static void setNoticeEnabled(bool value); //! \brief Returns the current state for notice output static bool isNoticeEnabled(void); //! \brief Toggles the executed sql output for connections. By default any sql are omitted static void setPrintSQL(bool value); //! \brief Returns the current state for sql output static bool isSQLPrinted(void); /*! \brief When calling this method with a true parameter any try to connect when the connection is already opened will raise exceptions. If calling the method using false the issue mentioned will be reported on stderr */ static void setSilenceConnError(bool value); //! \brief Returns the current state for silence connection errors static bool isConnErrorSilenced(void); /*! \brief Sets one connection parameter. This method can only be called before the connection to the database */ void setConnectionParam(const QString ¶m, const QString &value); //! \brief Sets all the connection parameters at once void setConnectionParams(const attribs_map ¶ms); //! \brief Set if the database configured on the connection is auto browseable when using the SQLTool manage database void setAutoBrowseDB(bool value); //! \brief Open the connection to the database. void connect(void); //! \brief Resets the database connection void reset(void); //! \brief Close the opened connection void close(void); //! \brief Request the cancel of the running command on a opened connection void requestCancel(void); //! \brief Returns the value of specified parameter name QString getConnectionParam(const QString ¶m); //! \brief Returns the full parameter map attribs_map getConnectionParams(void) const; //! \brief Returns a map containing some server's info attribs_map getServerInfo(void); //! \brief Returns the connection string used to connect to de database QString getConnectionString(void); /*! \brief Returns a string containing the following signature 'alias (host:port)' by default. If host_port_only is true the signature will not contain the alias being in the form 'host:port' If incl_db_name is true the database name will be prepended to the final signature 'dbname@host:port' */ QString getConnectionId(bool host_port_only = false, bool incl_db_name = false); /*! \brief Returns the DBMS version in format XX.YY[.ZZ] If major_only is true only XX.YY portion is returned */ QString getPgSQLVersion(bool major_only=false); /*! Returns all notices/warnings produced by the command executions. This method will return an empty list if notices/warnings are disabled in the connections */ static QStringList getNotices(void); /*! \brief Change the current database to the specified db name using the parameters from the current stablished connection causing the connection to be reset and moved to the new database. The effect of this is the same by type \c dbname on psql console. In case of errors the method will raise an exception and switch back to the previous database. */ void switchToDatabase(const QString &dbname); //! \brief Returns if the connection is stablished bool isStablished(void); //! \brief Returns if the connection is configured (has some attributes set) bool isConfigured(void); //! \brief Returns if the db configured in the connection can be automatically browsed in SQLTool bool isAutoBrowseDB(void); /*! \brief Executes a DML command on the server using the opened connection. Its mandatory to specify the object to receive the returned resultset. */ void executeDMLCommand(const QString &sql, ResultSet &result); /*! \brief Executes a DDL command on the server using the opened connection. The user don't need to specify the resultset since the commando executed is intended to be an data definition one */ void executeDDLCommand(const QString &sql); //! \brief Toggles the default status for the connect in the specified operation (OP_??? constants). void setDefaultForOperation(unsigned op_id, bool value); //! \brief Returns if the connection is the default for the specifed operation bool isDefaultForOperation(unsigned op_id); //! \brief Makes an copy between two connections void operator = (const Connection &conn); }; #endif pgmodeler-0.9.2/libpgconnector/src/resultset.cpp000066400000000000000000000241031360462764600220530ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "resultset.h" ResultSet::ResultSet(void) { sql_result=nullptr; empty_result=false; is_res_copied=false; current_tuple=-1; } ResultSet::ResultSet(PGresult *sql_result) { QString str_aux; int res_state; if(!sql_result) throw Exception(ErrorCode::AsgNotAllocatedSQLResult, __PRETTY_FUNCTION__, __FILE__, __LINE__); this->sql_result=sql_result; res_state=PQresultStatus(this->sql_result); //Handling the status of the result switch(res_state) { //Generating an error in case the server returns an incomprehensible response case PGRES_BAD_RESPONSE: throw Exception(ErrorCode::IncomprehensibleDBMSResponse, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Generating an error in case the server returns a fatal error case PGRES_FATAL_ERROR: str_aux=Exception::getErrorMessage(ErrorCode::DBMSFatalError) .arg(PQresultErrorMessage(sql_result)); throw Exception(str_aux,ErrorCode::DBMSFatalError, __PRETTY_FUNCTION__, __FILE__, __LINE__); //In case of sucess states the result will be created case PGRES_COMMAND_OK: case PGRES_TUPLES_OK: case PGRES_SINGLE_TUPLE: case PGRES_COPY_OUT: case PGRES_COPY_IN: default: empty_result=(res_state!=PGRES_TUPLES_OK && res_state!=PGRES_SINGLE_TUPLE && res_state!=PGRES_EMPTY_QUERY); current_tuple=-1; is_res_copied=false; break; } } ResultSet::~ResultSet(void) { clearResultSet(); } void ResultSet::clearResultSet(void) { /* Destroy the resultset of the object if it was not copied to another class instance (see 'operator =') */ if(sql_result && !is_res_copied) PQclear(sql_result); //Reset the other attributes sql_result=nullptr; empty_result=false; is_res_copied=false; current_tuple=-1; } QString ResultSet::getColumnName(int column_idx) { //Throws an error in case the column index is invalid if(column_idx < 0 || column_idx >= getColumnCount()) throw Exception(ErrorCode::RefTupleColumnInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Returns the column name on the specified index return(QString(PQfname(sql_result, column_idx))); } unsigned ResultSet::getColumnTypeId(int column_idx) { //Throws an error in case the column index is invalid if(column_idx < 0 || column_idx >= getColumnCount()) throw Exception(ErrorCode::RefTupleColumnInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Returns the column type id on the specified index return(static_cast(PQftype(sql_result, column_idx))); } int ResultSet::getColumnIndex(const QString &column_name) { int col_idx=-1; //Get the column index using it's name col_idx=PQfnumber(sql_result, column_name.toStdString().c_str()); /* In case the index is negative indicates that the column doesn't exists in the tuple thus an error will be raised */ if(col_idx < 0) throw Exception(ErrorCode::RefTupleColumnInvalidName, __PRETTY_FUNCTION__, __FILE__, __LINE__); return(col_idx); } int ResultSet::validateColumnName(const QString &column_name) { try { /* Raises an error if the user try to get the value of a column in a tuple of an empty result or generated from an INSERT, DELETE, UPDATE, that is, which command do not return lines but only do updates or removal */ if(getTupleCount()==0 || empty_result) throw Exception(ErrorCode::RefInvalidTuple, __PRETTY_FUNCTION__, __FILE__, __LINE__); else if(current_tuple < 0 || current_tuple >= getTupleCount()) throw Exception(ErrorCode::RefInvalidTupleColumn, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Get the column index through its name return (getColumnIndex(column_name)); } catch(Exception &e) { //Capture and redirect any generated exception throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__, __FILE__, __LINE__, &e); } } char *ResultSet::getColumnValue(const QString &column_name) { //Returns the column value on the current tuple return(PQgetvalue(sql_result, current_tuple, validateColumnName(column_name))); } void ResultSet::validateColumnIndex(int column_idx) { //Raise an error in case the column index is invalid if(column_idx < 0 || column_idx >= getColumnCount()) throw Exception(ErrorCode::RefTupleColumnInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); /* Raises an error if the user try to get the value of a column in a tuple of an empty result or generated from an INSERT, DELETE, UPDATE, that is, which command do not return lines but only do updates or removal */ else if(getTupleCount()==0 || empty_result) throw Exception(ErrorCode::RefInvalidTuple, __PRETTY_FUNCTION__, __FILE__, __LINE__); else if(current_tuple < 0 || current_tuple >= getTupleCount()) throw Exception(ErrorCode::RefInvalidTupleColumn, __PRETTY_FUNCTION__, __FILE__, __LINE__); } char *ResultSet::getColumnValue(int column_idx) { validateColumnIndex(column_idx); //Returns the column value on the current tuple return(PQgetvalue(sql_result, current_tuple, column_idx)); } bool ResultSet::isColumnValueNull(int column_idx) { validateColumnIndex(column_idx); //Returns the null state of the column on the current tuple return(PQgetisnull(sql_result, current_tuple, column_idx)); } bool ResultSet::isColumnValueNull(const QString &column_name) { //Returns the null state of the column on the current tuple return(PQgetisnull(sql_result, current_tuple, validateColumnName(column_name))); } int ResultSet::getColumnSize(const QString &column_name) { //Returns the column value length on the current tuple return(PQgetlength(sql_result, current_tuple, validateColumnName(column_name))); } int ResultSet::getColumnSize(int column_idx) { //Raise an error in case the column index is invalid if(column_idx < 0 || column_idx >= getColumnCount()) throw Exception(ErrorCode::RefTupleColumnInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); else if(current_tuple < 0 || current_tuple >= getTupleCount()) throw Exception(ErrorCode::RefInvalidTupleColumn, __PRETTY_FUNCTION__, __FILE__, __LINE__); //Retorns the column value length on the current tuple return(PQgetlength(sql_result, current_tuple, column_idx)); } attribs_map ResultSet::getTupleValues(void) { attribs_map tup_vals; if(current_tuple < 0 || current_tuple >= getTupleCount()) throw Exception(ErrorCode::RefInvalidTuple, __PRETTY_FUNCTION__, __FILE__, __LINE__); for(int col=0; col < getColumnCount(); col++) tup_vals[getColumnName(col)]=getColumnValue(col); return(tup_vals); } int ResultSet::getTupleCount(void) { //In case the result has some tuples if(!empty_result) //Returns the tuple count gathered after the SQL command return(PQntuples(sql_result)); else /* Returns the line amount that were affected by the SQL command (only for INSERT, DELETE, UPDATE) */ return(atoi(PQcmdTuples(sql_result))); } int ResultSet::getColumnCount(void) { return(PQnfields(sql_result)); } int ResultSet::getCurrentTuple(void) { return(current_tuple); } bool ResultSet::isColumnBinaryFormat(const QString &column_name) { int col_idx=-1; try { col_idx=getColumnIndex(column_name); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__, __FILE__, __LINE__, &e); } /* Returns the column format in the current tuple. According to libpq documentation, value = 0, indicates column text format, value = 1 the column has binary format, the other values are reserved */ return(PQfformat(sql_result, col_idx)==1); } bool ResultSet::isColumnBinaryFormat(int column_idx) { //Raise an error in case the column index is invalid if(column_idx < 0 || column_idx >= getColumnCount()) throw Exception(ErrorCode::RefTupleColumnInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__); /* Returns the column format in the current tuple. According to libpq documentation, value = 0, indicates column text format, value = 1 the column has binary format, the other values are reserved. One additional check is made, if the type of the column is bytea. */ return(PQfformat(sql_result, column_idx)==1 || PQftype(sql_result, column_idx)==BYTEAOID); } bool ResultSet::accessTuple(unsigned tuple_type) { int tuple_count=getTupleCount(); /* Raises an error if the result is derived from a command which affects only rows or The tuple type to be accessed is invalid, out of set defined by the class */ if(empty_result || tuple_type > NextTuple) throw Exception(ErrorCode::RefInvalidTuple, __PRETTY_FUNCTION__, __FILE__, __LINE__); if(tuple_count==0) return(false); else { bool accessed=true; switch(tuple_type) { case FirstTuple: current_tuple=0; break; case LastTuple: current_tuple=tuple_count-1; break; case PreviousTuple: accessed=(current_tuple > 0); if(accessed) current_tuple--; break; case NextTuple: accessed=(current_tuple < (tuple_count-1)); if(accessed) current_tuple++; break; } return(accessed); } } bool ResultSet::isEmpty(void) { return(empty_result); } bool ResultSet::isValid(void) { return(sql_result != nullptr); } void ResultSet::operator = (ResultSet &res) { /* Mark the result parameter as copied, avoiding the sql_result attribute to be deallocated */ res.is_res_copied=true; /* If the resultset 'this' is allocated, it will be deallocated to avoid memory leaks */ clearResultSet(); //Copy the parameter restulset attributes to 'this' resultset this->current_tuple=res.current_tuple; this->empty_result=res.empty_result; this->sql_result=PQcopyResult(res.sql_result, PG_COPYRES_TUPLES | PG_COPYRES_ATTRS | PG_COPYRES_EVENTS); this->is_res_copied=false; } pgmodeler-0.9.2/libpgconnector/src/resultset.h000066400000000000000000000106471360462764600215300ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgconnector \class ResultSet \brief This class encapsulates some functions implemented by libpq for manipulation of resultsets returned by PostgreSQL SQL commands. It the resultset contains data the user must call ResultSet::accessTuple() to access the first tuple in order to perform operations on it. \note Creation date: 14/07/2009 */ #ifndef RESULTSET_H #define RESULTSET_H #include "exception.h" #include "attribsmap.h" #include #include #include //This constant is defined on PostgreSQL source code src/catalog/pg_type.h #define BYTEAOID 17 class ResultSet { private: /*! \brief Indicates whether the result was copied, this flag is used to avoid segmentation faults when calling the destructor. As the pointer 'sql_result' is copied to other elements if it is destroyed can cause reference fails. Thus, such a pointer is only deleted when this flag is marked as false */ bool is_res_copied; void validateColumnIndex(int column_idx); int validateColumnName(const QString &column_name); protected: //! \brief Stores the current tuple index, just for navigation int current_tuple; /*! \brief Indicates that the result was generated from a command which generates no tuples. Example: INSERT, DELETE, CREATE .. */ bool empty_result; //! \brief Stores the result object of a SQL command PGresult *sql_result; /*! \brief This class may be constructed from a result of SQL command generated in DBConnection class */ ResultSet(PGresult *sql_result); public: //! \brief Constants used to navigate through the resultset static constexpr unsigned FirstTuple=0, LastTuple=1, PreviousTuple=2, NextTuple=3; ResultSet(void); ~ResultSet(void); //! \brief Returns the value of a column (searching by name or index) char *getColumnValue(const QString &column_name); char *getColumnValue(int column_idx); //! \brief Returns the data allocated size of a column (searching by name or index) int getColumnSize(const QString &column_name); int getColumnSize(int column_idx); //! \brief Returns all the column names / values for the current tuple. attribs_map getTupleValues(void); /*! \brief Returns the number of rows affected by the command that generated the result if it is an INSERT, DELETE, UPDATE or the number of tuples returned if the command was a SELECT */ int getTupleCount(void); //! \brief Returns the column count present in one tuple int getColumnCount(void); //! \brief Returns the name of the column specified by it's index QString getColumnName(int column_idx); //! \brief Returns the type OID of the column specified by it's index unsigned getColumnTypeId(int column_idx); //! \brief Returns the index of the column specified by it's name int getColumnIndex(const QString &column_name); //! \brief Returns the current tuple where the navigation is int getCurrentTuple(void); //! \brief Informs if the column is in binary format bool isColumnBinaryFormat(const QString &column_name); bool isColumnBinaryFormat(int column_idx); //! \brief Informs if the column has a null value. In PostgreSQL null =/= empty bool isColumnValueNull(int column_idx); bool isColumnValueNull(const QString &column_name); //! \brief Access on tuple on result set via navigation constants bool accessTuple(unsigned tuple_type); //! \brief Returns if the result set is empty due a DML command that does not returned any data bool isEmpty(void); //! \brief Returns if the result set is valid (created from a valid result set) bool isValid(void); void clearResultSet(void); //! \brief Make a copy between two resultsets void operator = (ResultSet &res); friend class Connection; }; #endif pgmodeler-0.9.2/libpgmodeler/000077500000000000000000000000001360462764600161635ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler/libpgmodeler.pro000066400000000000000000000067131360462764600213610ustar00rootroot00000000000000# libpgmodeler.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = lib TARGET = pgmodeler windows: DESTDIR = $$PWD HEADERS += src/textbox.h \ src/cast.h \ src/function.h \ src/language.h \ src/operator.h \ src/baserelationship.h \ src/basetable.h \ src/column.h \ src/domain.h \ src/aggregate.h \ src/permission.h \ src/databasemodel.h \ src/role.h \ src/constraint.h \ src/type.h \ src/tablespace.h \ src/trigger.h \ src/baseobject.h \ src/rule.h \ src/sequence.h \ src/pgsqltypes.h \ src/conversion.h \ src/schema.h \ src/indexelement.h \ src/index.h \ src/basegraphicobject.h \ src/relationship.h \ src/table.h \ src/usermapping.h \ src/view.h \ src/operatorfamily.h \ src/operatorclasselement.h \ src/operatorclass.h \ src/operationlist.h \ src/tableobject.h \ src/reference.h \ src/collation.h \ src/excludeelement.h \ src/element.h \ src/parameter.h \ src/operation.h \ src/copyoptions.h \ src/typeattribute.h \ src/extension.h \ src/pgmodelerns.h \ src/tag.h \ src/eventtrigger.h \ src/genericsql.h \ src/policy.h \ src/partitionkey.h \ src/foreigndatawrapper.h \ src/foreignobject.h \ src/foreignserver.h \ src/physicaltable.h \ src/foreigntable.h SOURCES += src/textbox.cpp \ src/domain.cpp \ src/trigger.cpp \ src/basegraphicobject.cpp \ src/baserelationship.cpp \ src/type.cpp \ src/column.cpp \ src/tablespace.cpp \ src/indexelement.cpp \ src/index.cpp \ src/operator.cpp \ src/constraint.cpp \ src/pgsqltypes.cpp \ src/schema.cpp \ src/language.cpp \ src/role.cpp \ src/sequence.cpp \ src/usermapping.cpp \ src/view.cpp \ src/conversion.cpp \ src/function.cpp \ src/permission.cpp \ src/databasemodel.cpp \ src/rule.cpp \ src/table.cpp \ src/cast.cpp \ src/aggregate.cpp \ src/baseobject.cpp \ src/relationship.cpp \ src/basetable.cpp \ src/operatorfamily.cpp \ src/operatorclasselement.cpp \ src/operatorclass.cpp \ src/operationlist.cpp \ src/tableobject.cpp \ src/reference.cpp \ src/collation.cpp \ src/excludeelement.cpp \ src/element.cpp \ src/parameter.cpp \ src/copyoptions.cpp \ src/typeattribute.cpp \ src/extension.cpp \ src/pgmodelerns.cpp \ src/tag.cpp \ src/eventtrigger.cpp \ src/operation.cpp \ src/genericsql.cpp \ src/policy.cpp \ src/partitionkey.cpp \ src/foreigndatawrapper.cpp \ src/foreignobject.cpp \ src/foreignserver.cpp \ src/physicaltable.cpp \ src/foreigntable.cpp unix|windows: LIBS += -L$$OUT_PWD/../libparsers/ -lparsers \ -L$$OUT_PWD/../libutils/ -lutils INCLUDEPATH += $$PWD/../libparsers/src \ $$PWD/../libutils/src DEPENDPATH += $$PWD/../libparsers \ $$PWD/../libutils # Deployment settings target.path = $$PRIVATELIBDIR INSTALLS = target pgmodeler-0.9.2/libpgmodeler/src/000077500000000000000000000000001360462764600167525ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler/src/aggregate.cpp000066400000000000000000000226071360462764600214130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "aggregate.h" Aggregate::Aggregate(void) { obj_type=ObjectType::Aggregate; functions[0]=functions[1]=nullptr; sort_operator=nullptr; attributes[Attributes::Types]=QString(); attributes[Attributes::TransitionFunc]=QString(); attributes[Attributes::StateType]=QString(); attributes[Attributes::BaseType]=QString(); attributes[Attributes::FinalFunc]=QString(); attributes[Attributes::InitialCond]=QString(); attributes[Attributes::SortOp]=QString(); } void Aggregate::setFunction(unsigned func_idx, Function *func) { //Case the function index is invalid raises an error if(func_idx!=FinalFunc && func_idx!=TransitionFunc) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Checks if the function is valid, if not the case raises an error if(!isValidFunction(func_idx, func)) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidConfiguration) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Aggregate)), ErrorCode::AsgFunctionInvalidConfiguration,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(functions[func_idx]!=func); functions[func_idx]=func; } bool Aggregate::isValidFunction(unsigned func_idx, Function *func) { if(func) { if(func_idx==FinalFunc) { /* According to docs the final function to be valid must have 1 parameter which type is the same as the state_type attribute. BUT when importing system aggregates some functions has different parameter counts so in order to import them correctly we remove the restriction of one paramenter for this function */ /*return((func->getParameterCount()==1 || func->getParameter(0).getType().canCastTo(state_type));*/ return(func->getParameterCount() > 0 && func->getParameter(0).getType().canCastTo(state_type)); } else { unsigned qtd, i; bool cond1,cond2=true; /* The transition function must have n+1 parameters, where n is the accepted data types list size. Also, the first parameter of the function and the return type must be the same as the 'state_type' attribute. Lastly, the other parameters must be the same as the accepted data types (the appearece order is important here). IMPORTANT: this is not documented by aggregate docs but when trying to import some catalog aggregates the majority of the functions used by them has polymorphic parameters so in order to accept that situation and recreate aggregates in the model we enable the usage of polymorphic functions here */ cond1=(func->getReturnType().canCastTo(state_type)) && ((func->getParameterCount()==data_types.size() + 1) || (func->getParameterCount() > 0 && func->getParameter(func->getParameterCount()-1).getType().isPolymorphicType())) && (func->getParameter(0).getType().canCastTo(state_type)); qtd=func->getParameterCount(); for(i=1 ; i < qtd && cond2; i++) cond2=(func->getParameter(i).getType().isPolymorphicType() || func->getParameter(i).getType().canCastTo(data_types[i-1])); return(cond1 && cond2); } } else return(true); } void Aggregate::setStateType(PgSqlType state_type) { setCodeInvalidated(this->state_type != state_type); this->state_type=state_type; } void Aggregate::setInitialCondition(const QString &cond) { setCodeInvalidated(initial_condition != cond); initial_condition=cond; } void Aggregate::setSortOperator(Operator *sort_op) { if(sort_op) { Function *func=nullptr; /* Accordingly to the documentation, a sort operator only can be assigned to the aggregate when: 1) The aggregate accepts only one data type 2) The function that defines the operator has the parameter types identical as the input data type of the aggregate */ func=sort_op->getFunction(Operator::FuncOperator); //Validating the condition 1 if(data_types.size()!=1) throw Exception(ErrorCode::AsgInvalidOperatorArguments,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Validating the condition 2 else if(func->getParameter(0).getType()!=data_types[0] || (func->getParameterCount()==2 && func->getParameter(1).getType()!=data_types[0])) throw Exception(ErrorCode::AsgInvalidOperatorTypes,__PRETTY_FUNCTION__,__FILE__,__LINE__); } setCodeInvalidated(sort_operator != sort_op); this->sort_operator=sort_op; } void Aggregate::setTypesAttribute(unsigned def_type) { QString str_types; unsigned i, count; count=data_types.size(); for(i=0; i < count; i++) { if(def_type==SchemaParser::SqlDefinition) { str_types+=data_types[i].getCodeDefinition(SchemaParser::SqlDefinition); if(i < (count-1)) str_types+=','; } else str_types+=data_types[i].getCodeDefinition(def_type); } /* Case none data type is specified for the aggregate creates an aggregate that accepts any possible data '*' e.g. function(*) */ if(def_type == SchemaParser::SqlDefinition && str_types.isEmpty()) str_types='*'; attributes[Attributes::Types]=str_types; } void Aggregate::addDataType(PgSqlType type) { data_types.push_back(type); setCodeInvalidated(true); } void Aggregate::removeDataType(unsigned type_idx) { //Raises an exception if the type index is out of bound if(type_idx >= data_types.size()) throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Removes the type at the specified position data_types.erase(data_types.begin() + type_idx); setCodeInvalidated(true); } void Aggregate::removeDataTypes(void) { data_types.clear(); setCodeInvalidated(true); } unsigned Aggregate::getDataTypeCount(void) { return(data_types.size()); } Function *Aggregate::getFunction(unsigned func_idx) { //Raises an exception if the function index is invalid if(func_idx!=FinalFunc && func_idx!=TransitionFunc) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(functions[func_idx]); } PgSqlType Aggregate::getStateType(void) { return(state_type); } QString Aggregate::getInitialCondition(void) { return(initial_condition); } Operator *Aggregate::getSortOperator(void) { return(sort_operator); } PgSqlType Aggregate::getDataType(unsigned type_idx) { //Raises an exception if the type index is out of bound if(type_idx >= data_types.size()) throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(data_types[type_idx]); } QString Aggregate::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); setTypesAttribute(def_type); if(functions[TransitionFunc]) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::TransitionFunc]=functions[TransitionFunc]->getSignature(); else { functions[TransitionFunc]->setAttribute(Attributes::RefType, Attributes::TransitionFunc); attributes[Attributes::TransitionFunc]=functions[TransitionFunc]->getCodeDefinition(def_type,true); } } if(functions[FinalFunc]) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::FinalFunc]=functions[FinalFunc]->getSignature(); else { functions[FinalFunc]->setAttribute(Attributes::RefType, Attributes::FinalFunc); attributes[Attributes::FinalFunc]=functions[FinalFunc]->getCodeDefinition(def_type,true); } } if(sort_operator) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::SortOp]=sort_operator->getName(true); else attributes[Attributes::SortOp]=sort_operator->getCodeDefinition(def_type,true); } if(!initial_condition.isEmpty()) attributes[Attributes::InitialCond]=initial_condition; if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::StateType]=*(state_type); else attributes[Attributes::StateType]=state_type.getCodeDefinition(def_type,Attributes::StateType); return(BaseObject::__getCodeDefinition(def_type)); } QString Aggregate::getDropDefinition(bool cascade) { setTypesAttribute(SchemaParser::SqlDefinition); return(BaseObject::getDropDefinition(cascade)); } QString Aggregate::getAlterDefinition(BaseObject *object) { try { setTypesAttribute(SchemaParser::SqlDefinition); return(BaseObject::getAlterDefinition(object)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString Aggregate::getSignature(bool format) { QStringList types; if(data_types.empty()) types.push_back(QString("*")); else { for(auto &tp : data_types) types.push_back(tp.getCodeDefinition(SchemaParser::SqlDefinition)); } return(BaseObject::getSignature(format) + QString("(%1)").arg(types.join(','))); } void Aggregate::configureSearchAttributes(void) { QStringList list; BaseObject::configureSearchAttributes(); for(auto &type : data_types) list += *type; search_attribs[Attributes::Type] = list.join("; "); } pgmodeler-0.9.2/libpgmodeler/src/aggregate.h000066400000000000000000000071661360462764600210630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Aggregate \brief Implements the operations to manipulate aggregates on the database. \note Creation date: 16/04/2008 **/ #ifndef AGGREGATE_H #define AGGREGATE_H #include "baseobject.h" #include "function.h" #include "operator.h" class Aggregate: public BaseObject { private: /*! \brief List of types with which the aggregate operates. If it is empty will be considered all possible types '*' To maintain compatibility with the old syntax, where the aggregate function accepts only one data type, the list of types 'data_types' must have only one element. To declare an aggregate function which works with several types in the old syntax, the only element of the list must be of type 'any' */ vector data_types; /*! \brief Function that defines the aggregate behavior 0 -> Final function 1 -> Transition function */ Function *functions[2]; //! \brief Data type used as aggregate's state PgSqlType state_type; //! \brief Initial condition for the aggregate QString initial_condition; //! \brief Sort operator used by the aggregate Operator *sort_operator; //! \brief Formats the data types to be used as attribute by the SchemaParser void setTypesAttribute(unsigned def_type); //! \brief Checks if the passed function is valid according to the rule of aggregate definition bool isValidFunction(unsigned func_idx, Function *func); protected: virtual void configureSearchAttributes(void); public: //! \brief Constants used to reference the functions used by the aggregate static constexpr unsigned FinalFunc=0, TransitionFunc=1; Aggregate(void); //! \brief Defines one of the functions used by the aggregate void setFunction(unsigned func_idx, Function *func); //! \brief Defines the state data type of the aggregate void setStateType(PgSqlType state_type); //! \brief Defines the initial condition for the aggregate void setInitialCondition(const QString &cond); //! \brief Defines the sort operator used by the aggregate void setSortOperator(Operator *sort_op); //! \brief Adds a data type in the group that is accepted by the aggregate void addDataType(PgSqlType type); //! \brief Removes one aggregate accepted data type void removeDataType(unsigned type_idx); //! \brief Removes all accepted data types from aggregate void removeDataTypes(void); Function *getFunction(unsigned func_idx); PgSqlType getStateType(void); QString getInitialCondition(void); Operator *getSortOperator(void); PgSqlType getDataType(unsigned type_idx); unsigned getDataTypeCount(void); //! \brief Returns the SQL / XML code definition for the aggregate virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getDropDefinition(bool cascade) final; virtual QString getAlterDefinition(BaseObject *object) final; virtual QString getSignature(bool format=true) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/basegraphicobject.cpp000066400000000000000000000064771360462764600231330ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "basegraphicobject.h" BaseGraphicObject::BaseGraphicObject(void) { is_modified=true; is_faded_out=false; attributes[Attributes::XPos]=QString(); attributes[Attributes::YPos]=QString(); attributes[Attributes::Position]=QString(); attributes[Attributes::FadedOut]=QString(); attributes[Attributes::Layer]=QString(); receiver_object=nullptr; layer = 0; } void BaseGraphicObject::setProtected(bool value) { BaseObject::setProtected(value); emit s_objectProtected(this->isProtected()); } void BaseGraphicObject::setSystemObject(bool value) { BaseObject::setSystemObject(value); } void BaseGraphicObject::setModified(bool value) { is_modified=value; if(is_modified) emit s_objectModified(); } void BaseGraphicObject::setSQLDisabled(bool value) { bool curr_val=sql_disabled; BaseObject::setSQLDisabled(value); if(value != curr_val) emit s_objectModified(); } void BaseGraphicObject::setFadedOut(bool value) { setCodeInvalidated(is_faded_out != value); is_faded_out = value; } bool BaseGraphicObject::isModified(void) { return(is_modified); } bool BaseGraphicObject::isFadedOut(void) { return(is_faded_out); } void BaseGraphicObject::setFadedOutAttribute(void) { attributes[Attributes::FadedOut]=(is_faded_out ? Attributes::True : QString()); } void BaseGraphicObject::setPositionAttribute(void) { attributes[Attributes::XPos]=QString("%1").arg(position.x()); attributes[Attributes::YPos]=QString("%1").arg(position.y()); attributes[Attributes::Position]=schparser.getCodeDefinition(Attributes::Position, attributes, SchemaParser::XmlDefinition); } void BaseGraphicObject::setPosition(QPointF pos) { setCodeInvalidated(position != pos); position=pos; } QPointF BaseGraphicObject::getPosition(void) { return(position); } void BaseGraphicObject::operator = (BaseGraphicObject &obj) { *(dynamic_cast(this))=dynamic_cast(obj); this->position=obj.position; } void BaseGraphicObject::setReceiverObject(QObject *obj) { if(!obj && receiver_object) disconnect(this, nullptr, receiver_object, nullptr); receiver_object=obj; } QObject *BaseGraphicObject::getOverlyingObject(void) { return(receiver_object); } bool BaseGraphicObject::isGraphicObject(ObjectType type) { return(type==ObjectType::Table || type==ObjectType::View || type==ObjectType::Relationship || type==ObjectType::BaseRelationship || type==ObjectType::Textbox || type==ObjectType::Schema || type==ObjectType::ForeignTable); } void BaseGraphicObject::setLayer(unsigned layer) { setCodeInvalidated(this->layer != layer); this->layer = layer; } unsigned BaseGraphicObject::getLayer(void) { return(layer); } pgmodeler-0.9.2/libpgmodeler/src/basegraphicobject.h000066400000000000000000000112671360462764600225710ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class BaseGraphicObject \brief This is a basic implementation to control graphical objects such as tables, relationships, textboxes, views. The full graphical representation of these objects are made in an separated layer this is treated in the BaseObjectView class on libobjrenderer library \note Creation date: 17/09/2006 */ #ifndef BASE_GRAPHIC_OBJECT_H #define BASE_GRAPHIC_OBJECT_H #include #include #include "baseobject.h" class BaseGraphicObject: public QObject, public BaseObject { private: Q_OBJECT /*! \brief Stores the position of the object on the model. This attribute is used only to memorize the position of the object in xml code generation */ QPointF position; /*! \brief Indicates that the object structure was modified somehow and it is needed to be updated or specially treated */ bool is_modified, //! \bried Indicates if the graphical representation of this object is faded out is_faded_out; /*! \brief Stores a reference to the object which is currently the receiver of signals emitted by the instance of this class. The receiver is an object that represents the 'this' object in the QGraphicsScene. This attribute breaks some concepts of OO but is required for some cases when is necessary to recover the graphical object in a fast way (rather than find it in the QGraphcisScene) */ QObject *receiver_object; protected: //! \brief This attributes holds the layer in which the object is visible. unsigned layer; /*! \brief Method that defines the objects position attributes used in generation of XML code definition */ void setPositionAttribute(void); //! \brief Defines the receveir objects that represents the 'this' object on the QGraphicsScene void setReceiverObject(QObject *obj); void setFadedOutAttribute(void); public: BaseGraphicObject(void); ~BaseGraphicObject(void){} /*! \brief Sets whether the object is protected or not (method overloading from base class BaseObject) the difference is that this method emits the signal s_objectProtected() */ virtual void setProtected(bool value); /*! \brief Sets whether the object is system or not (method overloading from base class BaseObject) the difference is that this method emits the same signal s_objectProtected() */ virtual void setSystemObject(bool value); //! \brief Sets the object's position void setPosition(QPointF pos); /*! \brief Sets if the objects is modified or not. This method emits the signal s_objectModified() */ virtual void setModified(bool value); virtual void setSQLDisabled(bool value); //! \brief Sets the fade out status of the receiver object void setFadedOut(bool value); //! \brief Returns the modified status of the object bool isModified(void); //! \brief Returns the fade out status of the object bool isFadedOut(void); //! \brief Returns the current position of the object QPointF getPosition(); //! \brief Assigns on object to other mading the correct attribute copy void operator = (BaseGraphicObject &obj); //! \brief Gets the current overlying (top object, scene object) that graphically represents the 'this' object QObject *getOverlyingObject(void); //! \brief Returns the code definition of the object virtual QString getCodeDefinition(unsigned)=0; //! \brief Returns if the passed type one that has a graphical representation (table, view, schema, relationship or textbox) static bool isGraphicObject(ObjectType type); //! \brief Defines in which layer the object is visible void setLayer(unsigned layer); //! \brief Returns the layer in which the object is visible unsigned getLayer(void); signals: //! \brief Signal emitted when the user calls the setModified() method void s_objectModified(void); //! \brief Signal emitted when the user calls the setProtected() method void s_objectProtected(bool); friend class BaseObjectView; friend class DatabaseModel; friend class OperationList; }; #endif pgmodeler-0.9.2/libpgmodeler/src/baseobject.cpp000066400000000000000000001215511360462764600215640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baseobject.h" #include "pgmodelerns.h" #include const QByteArray BaseObject::special_chars = QByteArray("'_-.@ $:()/<>+*\\=~!#%^&|?{}[]`;"); /* CAUTION: If both amount and order of the enumerations are modified then the order and amount of the elements of this vector must also be modified */ const QString BaseObject::objs_schemas[BaseObject::ObjectTypeCount]={ "column", "constraint", "function", "trigger", "index", "rule", "table", "view", "domain", "schema", "aggregate", "operator", "sequence", "role", "conversion", "cast", "language", "usertype", "tablespace", "opfamily", "opclass", "database","collation", "extension", "eventtrigger", "policy", "foreigndatawrapper", "foreignserver", "foreigntable", "usermapping", "relationship", "textbox", "permission", "parameter", "typeattribute", "tag", "genericsql", "relationship" }; const QString BaseObject::obj_type_names[BaseObject::ObjectTypeCount]={ QT_TR_NOOP("Column"), QT_TR_NOOP("Constraint"), QT_TR_NOOP("Function"), QT_TR_NOOP("Trigger"), QT_TR_NOOP("Index"), QT_TR_NOOP("Rule"), QT_TR_NOOP("Table"), QT_TR_NOOP("View"), QT_TR_NOOP("Domain"), QT_TR_NOOP("Schema"), QT_TR_NOOP("Aggregate"), QT_TR_NOOP("Operator"), QT_TR_NOOP("Sequence"), QT_TR_NOOP("Role"), QT_TR_NOOP("Conversion"), QT_TR_NOOP("Cast"), QT_TR_NOOP("Language"), QT_TR_NOOP("Type"), QT_TR_NOOP("Tablespace"), QT_TR_NOOP("Operator Family"), QT_TR_NOOP("Operator Class"), QT_TR_NOOP("Database"), QT_TR_NOOP("Collation"), QT_TR_NOOP("Extension"), QT_TR_NOOP("Event Trigger"), QT_TR_NOOP("Policy"), QT_TR_NOOP("Foreign Data Wrapper"), QT_TR_NOOP("Foreign Server"), QT_TR_NOOP("Foreign Table"), QT_TR_NOOP("User Mapping"), QT_TR_NOOP("Relationship"), QT_TR_NOOP("Textbox"), QT_TR_NOOP("Permission"), QT_TR_NOOP("Parameter"), QT_TR_NOOP("Type Attribute"), QT_TR_NOOP("Tag"), QT_TR_NOOP("Generic SQL"), QT_TR_NOOP("Basic Relationship") }; const QString BaseObject::objs_sql[BaseObject::ObjectTypeCount]={ QString("COLUMN"), QString("CONSTRAINT"), QString("FUNCTION"), QString("TRIGGER"), QString("INDEX"), QString("RULE"), QString("TABLE"), QString("VIEW"), QString("DOMAIN"), QString("SCHEMA"), QString("AGGREGATE"), QString("OPERATOR"), QString("SEQUENCE"), QString("ROLE"), QString("CONVERSION"), QString("CAST"), QString("LANGUAGE"), QString("TYPE"), QString("TABLESPACE"), QString("OPERATOR FAMILY"), QString("OPERATOR CLASS"), QString("DATABASE"), QString("COLLATION"), QString("EXTENSION"), QString("EVENT TRIGGER"), QString("POLICY"), QString("FOREIGN DATA WRAPPER"), QString("SERVER"), QString("FOREIGN TABLE"), QString("USER MAPPING") }; /* Initializes the global id which is shared between instances of classes derived from the this class. The value of global_id starts at 40k because the id ranges 0, 1k, 2k, 3k are respectively assigned to objects of classes Role, Tablespace DatabaseModel, Tag */ unsigned BaseObject::global_id=4000; QString BaseObject::pgsql_ver=PgSqlVersions::DefaulVersion; bool BaseObject::use_cached_code=true; bool BaseObject::escape_comments=true; BaseObject::BaseObject(void) { object_id=BaseObject::global_id++; is_protected=system_obj=sql_disabled=false; code_invalidated=true; obj_type=ObjectType::BaseObject; schema=nullptr; owner=nullptr; tablespace=nullptr; database=nullptr; collation=nullptr; attributes[Attributes::Name]=QString(); attributes[Attributes::Alias]=QString(); attributes[Attributes::Comment]=QString(); attributes[Attributes::Owner]=QString(); attributes[Attributes::Tablespace]=QString(); attributes[Attributes::Schema]=QString(); attributes[Attributes::Collation]=QString(); attributes[Attributes::Protected]=QString(); attributes[Attributes::SqlDisabled]=QString(); attributes[Attributes::AppendedSql]=QString(); attributes[Attributes::PrependedSql]=QString(); attributes[Attributes::Drop]=QString(); attributes[Attributes::Signature]=QString(); attributes[Attributes::EscapeComment]=QString(); this->setName(QApplication::translate("BaseObject","new_object","", -1)); } unsigned BaseObject::getGlobalId(void) { return(global_id); } void BaseObject::setEscapeComments(bool value) { escape_comments = value; } bool BaseObject::isEscapeComments(void) { return(escape_comments); } QString BaseObject::getTypeName(ObjectType obj_type) { if(obj_type!=ObjectType::BaseObject) /* Due to the class BaseObject not be derived from QObject the function tr() is inefficient to translate the type names thus the method called to do the translation is from the application specifying the context (BaseObject) in the ts file and the text to be translated */ return(QApplication::translate("BaseObject",obj_type_names[enum_cast(obj_type)].toStdString().c_str(),"", -1)); else return(QString()); } QString BaseObject::getTypeName(const QString &type_str) { return(getTypeName(getObjectType(type_str))); } ObjectType BaseObject::getObjectType(const QString &type_name) { ObjectType obj_type=ObjectType::BaseObject; for(unsigned i=0; i < BaseObject::ObjectTypeCount; i++) { if(objs_schemas[i]==type_name) { obj_type=static_cast(i); break; } } return(obj_type); } QString BaseObject::getSchemaName(ObjectType obj_type) { return(objs_schemas[enum_cast(obj_type)]); } QString BaseObject::getSQLName(ObjectType obj_type) { return(objs_sql[enum_cast(obj_type)]); } QString BaseObject::formatName(const QString &name, bool is_operator) { bool is_formated=false; QString frmt_name; QByteArray raw_name; unsigned char chr, chr1, chr2; //Checking if the name is already formated enclosed by quotes is_formated=QRegExp(QString("(\")(.)+(\")")).exactMatch(name); /* If the name is not formatted or it symbolizes the name of an operator (which has characters invalid according to the rule and is the only exception to which its name is formatted even being invalid) or if the name is valid according with PostgreSQL rules for other types of objects */ if(!is_formated && (is_operator || isValidName(name))) { bool needs_fmt=false; unsigned i = 0, qtd = 0; raw_name.append(name); /* Checks if the name has some upper case letter. If its the case the name will be enclosed in quotes */ needs_fmt = (!is_operator && name.contains(QRegExp("^[0-9]+"))); for(int idx = 0; idx < special_chars.size() && !needs_fmt; idx++) needs_fmt = (!is_operator && special_chars.at(idx) != '_' && name.indexOf(special_chars.at(idx)) >= 0); qtd=name.size(); i=0; while(i < qtd && !needs_fmt) { chr=raw_name[i]; if(((i + 1) < (qtd-1)) && ((chr >= 0xC2 && chr <= 0xDF) || (chr >= 0xE0 && chr <= 0xEF))) chr1=raw_name[i+1]; else chr1=0; if((i + 2) < (qtd-1) && chr >= 0xE0 && chr <= 0xEF) chr2=raw_name[i+2]; else chr2=0; if(chr1!=0 && chr2!=0) i+=3; else if(chr1!=0 && chr2==0) i+=2; else i++; //2 bytes UTF-8 character if((chr >= 0xC2 && chr <= 0xDF && chr1 >= 0x80 && chr1 <= 0xBF) || //3 bytes UTF-8 character (chr >= 0xE0 && chr <= 0xEF && chr1 >= 0x80 && chr1 <= 0xBF && chr2 >= 0x80 && chr2 <= 0xBF) || QChar(chr).isUpper()) { needs_fmt=true; } } if(needs_fmt || PgModelerNs::isReservedKeyword(name)) frmt_name=QString("\"%1\"").arg(name); else frmt_name=name; } else if(is_formated) frmt_name=name; return(frmt_name); } bool BaseObject::isValidName(const QString &name) { QString aux_name=name; if(aux_name.contains(QRegExp("^(\")(.)+(\")$"))) { aux_name.remove(0,1); aux_name.remove(aux_name.size()-1,1); } /* If the name is greater than the maximum size accepted by PostgreSQL (currently 63 bytes) the name is invalid. In this case the starting and ending quotes are discarded from the name in order to validate the length. */ if(name.isEmpty() || aux_name.size() > ObjectNameMaxLength) return(false); else { int i=0, len; bool valid=true; unsigned char chr='\0', chr1='\0', chr2='\0'; QByteArray raw_name; raw_name.append(name); len=raw_name.size(); chr=raw_name[0]; if(len > 1) chr1=raw_name[len-1]; //Checks if the name is enclosed in quotes if(chr=='\"' && chr1=='\"') { /* Validates the name but the validation will continue until the end of string (or the last quote) */ valid=true; i++; len--; } while(valid && i < len) { chr=raw_name[i]; /* Validation of simple ASCI characters. Checks if the name has the characters in the set [ a-z A-Z 0-9 _ . @ $ - : space () <>] */ if((chr >= 'a' && chr <='z') || (chr >= 'A' && chr <='Z') || (chr >= '0' && chr <='9') || special_chars.contains(chr)) { valid=true; i++; } else valid=false; /* Validation of UTF8 charactes (2 and 3 bytes long). Reference: http://www.fileformat.info/info/unicode/utf8.htm http://en.wikipedia.org/wiki/UTF-8 Snippet extracted from the above url: The value of each individual byte indicates its UTF-8 function, as follows: 00 to 7F hex (0 to 127): first and only byte of a sequence. 80 to BF hex (128 to 191): continuing byte in a multi-byte sequence. C2 to DF hex (194 to 223): first byte of a two-byte sequence. E0 to EF hex (224 to 239): first byte of a three-byte sequence. */ if(!valid && (i < len-1)) { chr1=raw_name[i+1]; if((i + 2) <= (len-1)) chr2=raw_name[i+2]; else chr2=0; //UTF-8 character with 2 bytes length if((chr >= 0xC2 && chr <= 0xDF && chr1 >= 0x80 && chr1 <= 0xBF) || //UTF-8 character with 3 bytes length (chr >= 0xE0 && chr <= 0xEF && chr1 >= 0x80 && chr1 <= 0xBF && chr2 >= 0x80 && chr2 <= 0xBF)) valid=true; //Increments the counter in the size of the validated char if(chr >= 0xC2 && chr <= 0xDF) //2 bytes char i+=2; else //3 bytes char i+=3; } } return(valid); } } void BaseObject::setDatabase(BaseObject *db) { if((db && db->getObjectType()==ObjectType::Database) || !db) this->database=db; } BaseObject *BaseObject::getDatabase(void) { return(this->database); } void BaseObject::setProtected(bool value) { setCodeInvalidated(this->is_protected != value); is_protected=value; } void BaseObject::setName(const QString &name) { QString aux_name=name; bool is_quoted=aux_name.contains(QRegExp("^(\")(.)+(\")$")); //Raises an error if the passed name is invalid if(!isValidName(aux_name)) { if(aux_name.isEmpty()) throw Exception(ErrorCode::AsgEmptyNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //If the name is quoted we add 2 bytes to the maximum in order to check if it exceeds the limit else if(aux_name.size() > (ObjectNameMaxLength + (is_quoted ? 2 : 0))) throw Exception(ErrorCode::AsgLongNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } aux_name.remove('"'); setCodeInvalidated(this->obj_name!=aux_name); this->obj_name=aux_name; } void BaseObject::setAlias(const QString &alias) { if(alias.size() > ObjectNameMaxLength) throw Exception(ErrorCode::AsgLongNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->alias = alias; setCodeInvalidated(this->alias != alias); } void BaseObject::setComment(const QString &comment) { setCodeInvalidated(this->comment!=comment); this->comment=comment; } bool BaseObject::acceptsSchema(ObjectType obj_type) { return(obj_type==ObjectType::Function || obj_type==ObjectType::Table || obj_type==ObjectType::View || obj_type==ObjectType::Domain || obj_type==ObjectType::Aggregate || obj_type==ObjectType::Operator || obj_type==ObjectType::Sequence || obj_type==ObjectType::Conversion || obj_type==ObjectType::Type || obj_type==ObjectType::OpClass || obj_type==ObjectType::OpFamily || obj_type==ObjectType::Collation || obj_type==ObjectType::Extension || obj_type==ObjectType::ForeignTable); } bool BaseObject::acceptsSchema(void) { return(BaseObject::acceptsSchema(this->obj_type)); } bool BaseObject::acceptsOwner(ObjectType obj_type) { return(obj_type==ObjectType::Function || obj_type==ObjectType::Table || obj_type==ObjectType::Domain || obj_type==ObjectType::Schema || obj_type==ObjectType::Aggregate || obj_type==ObjectType::Operator || obj_type==ObjectType::Conversion || obj_type==ObjectType::Sequence || obj_type==ObjectType::Language || obj_type==ObjectType::Type || obj_type==ObjectType::Tablespace || obj_type==ObjectType::Database || obj_type==ObjectType::OpClass || obj_type==ObjectType::OpFamily || obj_type==ObjectType::Collation || obj_type==ObjectType::View || obj_type==ObjectType::EventTrigger || obj_type==ObjectType::ForeignDataWrapper || obj_type==ObjectType::ForeignServer || obj_type==ObjectType::UserMapping || obj_type==ObjectType::ForeignTable); } bool BaseObject::acceptsOwner(void) { return(BaseObject::acceptsOwner(this->obj_type)); } bool BaseObject::acceptsTablespace(ObjectType obj_type) { return(obj_type==ObjectType::Index || obj_type==ObjectType::Table || obj_type==ObjectType::View || obj_type==ObjectType::Constraint || obj_type==ObjectType::Database); } bool BaseObject::acceptsTablespace(void) { return(BaseObject::acceptsTablespace(this->obj_type)); } bool BaseObject::acceptsCollation(ObjectType obj_type) { return(obj_type==ObjectType::Domain || obj_type==ObjectType::Column || obj_type==ObjectType::Collation || obj_type==ObjectType::Type || obj_type==ObjectType::TypeAttribute); } bool BaseObject::acceptsCollation(void) { return(BaseObject::acceptsCollation(this->obj_type)); } bool BaseObject::acceptsCustomSQL(ObjectType obj_type) { return(obj_type!=ObjectType::Column && obj_type!=ObjectType::Constraint && obj_type!=ObjectType::Relationship && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::Parameter && obj_type!=ObjectType::TypeAttribute && obj_type!=ObjectType::BaseRelationship && obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::BaseTable && obj_type!=ObjectType::Permission && obj_type!=ObjectType::Tag && obj_type!=ObjectType::GenericSql); } bool BaseObject::acceptsAlterCommand(ObjectType obj_type) { return(obj_type==ObjectType::Collation || obj_type==ObjectType::Column || obj_type==ObjectType::Domain || obj_type==ObjectType::EventTrigger || obj_type==ObjectType::Extension || obj_type==ObjectType::Function || obj_type==ObjectType::Index || obj_type==ObjectType::Role || obj_type==ObjectType::Schema || obj_type==ObjectType::Sequence || obj_type==ObjectType::Table || obj_type==ObjectType::Tablespace || obj_type==ObjectType::Type || obj_type==ObjectType::Policy || obj_type==ObjectType::ForeignDataWrapper || obj_type==ObjectType::ForeignServer || obj_type==ObjectType::UserMapping || obj_type==ObjectType::ForeignTable); } bool BaseObject::acceptsDropCommand(ObjectType obj_type) { return(obj_type!=ObjectType::Permission && obj_type!=ObjectType::Relationship && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::TypeAttribute && obj_type!=ObjectType::Parameter && obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::Tag && obj_type!=ObjectType::BaseRelationship && obj_type!=ObjectType::BaseTable); } bool BaseObject::acceptsAlias(ObjectType obj_type) { return(obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Table || obj_type==ObjectType::Schema || obj_type==ObjectType::View || obj_type == ObjectType::Column || obj_type == ObjectType::Constraint || obj_type == ObjectType::Index || obj_type == ObjectType::Rule || obj_type == ObjectType::Trigger || obj_type == ObjectType::Policy || obj_type==ObjectType::ForeignTable); } bool BaseObject::acceptsCustomSQL(void) { return(BaseObject::acceptsCustomSQL(this->obj_type)); } bool BaseObject::acceptsAlterCommand(void) { return(BaseObject::acceptsAlterCommand(this->obj_type)); } bool BaseObject::acceptsDropCommand(void) { return(BaseObject::acceptsDropCommand(this->obj_type)); } void BaseObject::setSchema(BaseObject *schema) { if(!schema) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedSchema) .arg(this->obj_name) .arg(this->getTypeName()), ErrorCode::AsgNotAllocatedSchema,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(schema && schema->getObjectType()!=ObjectType::Schema) throw Exception(ErrorCode::AsgInvalidSchemaObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!acceptsSchema()) throw Exception(ErrorCode::AsgInvalidSchemaObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->schema != schema); this->schema=schema; } void BaseObject::setOwner(BaseObject *owner) { if(owner && owner->getObjectType()!=ObjectType::Role) throw Exception(ErrorCode::AsgInvalidRoleObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!acceptsOwner()) throw Exception(ErrorCode::AsgRoleObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->owner != owner); this->owner=owner; } void BaseObject::setTablespace(BaseObject *tablespace) { if(tablespace && tablespace->getObjectType()!=ObjectType::Tablespace) throw Exception(ErrorCode::AsgInvalidTablespaceObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!acceptsTablespace()) throw Exception(ErrorCode::AsgTablespaceInvalidObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->tablespace != tablespace); this->tablespace=tablespace; } void BaseObject::setCollation(BaseObject *collation) { if(collation && !acceptsCollation()) throw Exception(ErrorCode::AsgInvalidCollationObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(collation && collation->getObjectType()!=ObjectType::Collation) throw Exception(ErrorCode::AsgInvalidCollationObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->collation != collation); this->collation=collation; } void BaseObject::setAppendedSQL(const QString &sql) { if(!acceptsCustomSQL()) throw Exception(ErrorCode::AsgCustomSQLObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->appended_sql != sql); this->appended_sql=sql; } void BaseObject::setPrependedSQL(const QString &sql) { if(!acceptsCustomSQL()) throw Exception(ErrorCode::AsgCustomSQLObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->prepended_sql != sql); this->prepended_sql=sql; } QString BaseObject::getName(bool format, bool prepend_schema) { if(format) { QString aux_name; aux_name=formatName(this->obj_name, (obj_type==ObjectType::Operator)); if(this->schema && prepend_schema) aux_name=formatName(this->schema->getName(format)) + QString(".") + aux_name; if(!aux_name.isEmpty()) return(aux_name); else return(this->obj_name); } else return(this->obj_name); } QString BaseObject::getAlias(void) { return(this->alias); } QString BaseObject::getSignature(bool format) { return(this->getName(format, true)); } QString BaseObject::getComment(void) { return(comment); } QString BaseObject::getEscapedComment(bool escape_special_chars) { QString fmt_comm = comment.trimmed(); if(escape_special_chars) { fmt_comm.replace(QChar('\\'), QString("\\\\")); fmt_comm.replace(QChar::LineFeed, QString("\\n")); fmt_comm.replace(QChar::Tabulation, QString("\\t")); } fmt_comm.replace(QChar('\''), QString("''")); return(fmt_comm); } BaseObject *BaseObject::getSchema(void) { return(schema); } BaseObject *BaseObject::getOwner(void) { return(owner); } BaseObject *BaseObject::getTablespace(void) { return(tablespace); } BaseObject *BaseObject::getCollation(void) { return(collation); } QString BaseObject::getAppendedSQL(void) { return(appended_sql); } QString BaseObject::getPrependedSQL(void) { return(prepended_sql); } ObjectType BaseObject::getObjectType(void) { return(obj_type); } QString BaseObject::getTypeName(void) { return(BaseObject::getTypeName(this->obj_type)); } QString BaseObject::getSchemaName(void) { return(BaseObject::getSchemaName(this->obj_type)); } QString BaseObject::getSQLName(void) { return(BaseObject::getSQLName(this->obj_type)); } bool BaseObject::isProtected(void) { return(is_protected); } unsigned BaseObject::getObjectId(void) { return(object_id); } void BaseObject::setSQLDisabled(bool value) { setCodeInvalidated(this->sql_disabled != value); sql_disabled=value; } bool BaseObject::isSQLDisabled(void) { return(sql_disabled); } void BaseObject::setSystemObject(bool value) { setCodeInvalidated(this->system_obj != value); system_obj=sql_disabled=value; } bool BaseObject::isSystemObject(void) { return(system_obj); } void BaseObject::setBasicAttributes(bool format_name) { if(attributes[Attributes::Name].isEmpty()) attributes[Attributes::Name]=this->getName(format_name); if(attributes[Attributes::Alias].isEmpty()) attributes[Attributes::Alias]=this->getAlias(); if(attributes[Attributes::Signature].isEmpty()) attributes[Attributes::Signature]=this->getSignature(format_name); if(attributes[Attributes::SqlObject].isEmpty()) attributes[Attributes::SqlObject]=objs_sql[enum_cast(this->obj_type)]; } QString BaseObject::__getCodeDefinition(unsigned def_type) { return(BaseObject::getCodeDefinition(def_type, false)); } QString BaseObject::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def; if((def_type==SchemaParser::SqlDefinition && obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::BaseRelationship && obj_type!=ObjectType::BaseTable && obj_type!=ObjectType::Textbox) || (def_type==SchemaParser::XmlDefinition && obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::BaseTable)) { bool format=false; schparser.setPgSQLVersion(BaseObject::pgsql_ver); attributes[Attributes::SqlDisabled]=(sql_disabled ? Attributes::True : QString()); //Formats the object's name in case the SQL definition is being generated format=((def_type==SchemaParser::SqlDefinition) || (def_type==SchemaParser::XmlDefinition && reduced_form && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::Relationship)); setBasicAttributes(format); if(schema) { if(def_type==SchemaParser::XmlDefinition) attributes[Attributes::Schema]=schema->getCodeDefinition(def_type, true); else attributes[Attributes::Schema]=schema->getName(format); } if(def_type==SchemaParser::XmlDefinition) attributes[Attributes::Protected]=(is_protected ? Attributes::True : QString()); if(tablespace) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Tablespace]=tablespace->getName(format); else attributes[Attributes::Tablespace]=tablespace->getCodeDefinition(def_type, true); } if(collation && attributes[Attributes::Collation].isEmpty()) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Collation]=collation->getName(format); else attributes[Attributes::Collation]=collation->getCodeDefinition(def_type, true); } if(owner) { if(def_type==SchemaParser::SqlDefinition) { attributes[Attributes::Owner]=owner->getName(format); /* Only tablespaces, database and user mapping do not have an ALTER OWNER SET because the rule says that PostgreSQL tablespaces and database should be created with just a command line isolated from the others */ if(obj_type!=ObjectType::Tablespace && obj_type!=ObjectType::Database && obj_type!=ObjectType::UserMapping) { SchemaParser sch_parser; QString filename=GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::AlterSchemaDir + GlobalAttributes::DirSeparator + Attributes::Owner + GlobalAttributes::SchemaExt; sch_parser.ignoreUnkownAttributes(true); attributes[Attributes::Owner]=sch_parser.getCodeDefinition(filename, attributes); /* Disabling the SQL statement regarding the owner configuration (ALTER...OWNER TO...) when * the role used to be the owner of the object has its SQL code disabled. This will avoid * errors if the user wants to ignore that command without disabling the whole object's SQL when * its owner is disabled too */ if(owner->isSQLDisabled()) attributes[Attributes::Owner].prepend(QString("-- ")); } } else attributes[Attributes::Owner]=owner->getCodeDefinition(def_type, true); } if(!comment.isEmpty()) { if(def_type==SchemaParser::SqlDefinition) { QString escape_comm = getEscapedComment(escape_comments); attributes[Attributes::EscapeComment]=escape_comments ? Attributes::True : QString(); attributes[Attributes::Comment]=escape_comm; } else attributes[Attributes::Comment]=comment; schparser.ignoreUnkownAttributes(true); attributes[Attributes::Comment]= schparser.getCodeDefinition(Attributes::Comment, attributes, def_type); } if(!appended_sql.isEmpty()) { attributes[Attributes::AppendedSql]=appended_sql; if(def_type==SchemaParser::XmlDefinition) { schparser.ignoreUnkownAttributes(true); attributes[Attributes::AppendedSql]= schparser.getCodeDefinition(QString(Attributes::AppendedSql).remove('-'), attributes, def_type); } else { attributes[Attributes::AppendedSql]=QString("\n-- Appended SQL commands --\n") + appended_sql; } } if(!prepended_sql.isEmpty()) { attributes[Attributes::PrependedSql]=prepended_sql; if(def_type==SchemaParser::XmlDefinition) { schparser.ignoreUnkownAttributes(true); attributes[Attributes::PrependedSql]= schparser.getCodeDefinition(QString(Attributes::PrependedSql).remove('-'), attributes, def_type); } else { attributes[Attributes::PrependedSql]=QString("\n-- Prepended SQL commands --\n") + prepended_sql; } } if(def_type==SchemaParser::SqlDefinition && this->acceptsDropCommand()) { attributes[Attributes::Drop]=getDropDefinition(true); attributes[Attributes::Drop].remove(Attributes::DdlEndToken + '\n'); } attributes[Attributes::ReducedForm]=(reduced_form ? Attributes::True : QString()); try { code_def+=schparser.getCodeDefinition(objs_schemas[enum_cast(obj_type)], attributes, def_type); //Internally disabling the SQL definition if(sql_disabled && def_type==SchemaParser::SqlDefinition) { //Creates a text stream and insert an comment start token on each line QTextStream ts(&code_def); QString buf; while(!ts.atEnd()) buf+=QString("-- %1\n").arg(ts.readLine()); //The entire commented buffer will be returned code_def=buf; } clearAttributes(); //Database object doesn't handles cached code. if(use_cached_code && obj_type!=ObjectType::Database) { if(def_type==SchemaParser::SqlDefinition || (!reduced_form && def_type==SchemaParser::XmlDefinition)) cached_code[def_type]=code_def; else if(reduced_form) cached_reduced_code=code_def; } code_invalidated=false; } catch(Exception &e) { schparser.restartParser(); clearAttributes(); if(e.getErrorCode()==ErrorCode::UndefinedAttributeValue) throw Exception(Exception::getErrorMessage(ErrorCode::AsgObjectInvalidDefinition) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgObjectInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } return(code_def); } void BaseObject::setAttribute(const QString &attrib, const QString &value) { attributes[attrib]=value; } void BaseObject::clearAttributes(void) { attribs_map::iterator itr, itr_end; itr=attributes.begin(); itr_end=attributes.end(); while(itr!=itr_end) { itr->second=QString(); itr++; } } void BaseObject::swapObjectsIds(BaseObject *obj1, BaseObject *obj2, bool enable_cl_obj_swap) { //Raises an error if some of the objects aren't allocated if(!obj1 || !obj2) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the involved objects are the same else if(obj1==obj2) throw Exception(ErrorCode::InvIdSwapSameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the some of the objects are system objects else if(obj1->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(obj1->getName()) .arg(obj1->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(obj2->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(obj2->getName()) .arg(obj2->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the object is object is cluster level and the swap of these types isn't enabled else if(!enable_cl_obj_swap && (obj1->getObjectType()==ObjectType::Database || obj1->getObjectType()==ObjectType::Tablespace || obj1->getObjectType()==ObjectType::Role || obj2->getObjectType()==ObjectType::Database || obj2->getObjectType()==ObjectType::Tablespace || obj2->getObjectType()==ObjectType::Role)) throw Exception(ErrorCode::InvIdSwapInvalidObjectType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { unsigned id_bkp=obj1->object_id; obj1->object_id=obj2->object_id; obj2->object_id=id_bkp; } } void BaseObject::updateObjectId(BaseObject *obj) { //Raises an error if some of the objects aren't allocated if(!obj) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(obj->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(obj->getName()) .arg(obj->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else obj->object_id=++global_id; } vector BaseObject::getObjectTypes(bool inc_table_objs, vector exclude_types) { vector vet_types={ ObjectType::BaseRelationship, ObjectType::Aggregate, ObjectType::Cast, ObjectType::Collation, ObjectType::Conversion, ObjectType::Database, ObjectType::Domain, ObjectType::Extension, ObjectType::EventTrigger, ObjectType::ForeignDataWrapper, ObjectType::ForeignServer, ObjectType::Function, ObjectType::GenericSql, ObjectType::Language, ObjectType::OpClass, ObjectType::Operator, ObjectType::OpFamily, ObjectType::Permission, ObjectType::Relationship, ObjectType::Role, ObjectType::Schema, ObjectType::Sequence, ObjectType::Table, ObjectType::Tablespace, ObjectType::Tag, ObjectType::Textbox, ObjectType::Type, ObjectType::UserMapping, ObjectType::View, ObjectType::ForeignTable }; vector::iterator itr; if(inc_table_objs) { vet_types.push_back(ObjectType::Column); vet_types.push_back(ObjectType::Constraint); vet_types.push_back(ObjectType::Trigger); vet_types.push_back(ObjectType::Rule); vet_types.push_back(ObjectType::Index); vet_types.push_back(ObjectType::Policy); } for(ObjectType type : exclude_types) { itr=std::remove(vet_types.begin(), vet_types.end(), type); if(itr!=vet_types.end()) vet_types.erase(itr); } return(vet_types); } vector BaseObject::getChildObjectTypes(ObjectType obj_type) { if(obj_type==ObjectType::Database) return(vector()={ ObjectType::Cast, ObjectType::Role, ObjectType::Language, ObjectType::Tablespace, ObjectType::Schema, ObjectType::Extension, ObjectType::EventTrigger, ObjectType::ForeignDataWrapper, ObjectType::ForeignServer, ObjectType::UserMapping }); if(obj_type==ObjectType::Schema) return(vector()={ ObjectType::Aggregate, ObjectType::Conversion, ObjectType::Collation, ObjectType::Domain, ObjectType::ForeignTable, ObjectType::Function, ObjectType::OpClass, ObjectType::Operator, ObjectType::OpFamily, ObjectType::Sequence, ObjectType::Type, ObjectType::Table, ObjectType::View }); if(obj_type==ObjectType::Table) return(vector()={ ObjectType::Column, ObjectType::Constraint, ObjectType::Rule, ObjectType::Trigger, ObjectType::Index, ObjectType::Policy }); if(obj_type==ObjectType::ForeignTable) return(vector()={ ObjectType::Column, ObjectType::Constraint, ObjectType::Trigger }); if(obj_type==ObjectType::View) return(vector()={ObjectType::Rule, ObjectType::Trigger, ObjectType::Index}); return(vector()={}); } void BaseObject::setPgSQLVersion(const QString &ver) { pgsql_ver=ver; } QString BaseObject::getPgSQLVersion(void) { return(pgsql_ver); } attribs_map BaseObject::getSearchAttributes(void) { return(search_attribs); } void BaseObject::enableCachedCode(bool value) { use_cached_code=value; } void BaseObject::operator = (BaseObject &obj) { this->owner=obj.owner; this->schema=obj.schema; this->tablespace=obj.tablespace; this->database=obj.database; this->comment=obj.comment; this->obj_name=obj.obj_name; this->alias=obj.alias; this->obj_type=obj.obj_type; this->is_protected=obj.is_protected; this->sql_disabled=obj.sql_disabled; this->system_obj=obj.system_obj; this->setCodeInvalidated(use_cached_code); } void BaseObject::setCodeInvalidated(bool value) { if(use_cached_code && value!=code_invalidated) { if(value) { cached_reduced_code.clear(); cached_code[0].clear(); cached_code[1].clear(); } code_invalidated=value; } } void BaseObject::configureSearchAttributes(void) { search_attribs[Attributes::Name] = this->getName(false); search_attribs[Attributes::Signature] = this->getSignature(false); search_attribs[Attributes::Schema] = schema ? schema->getName(false) : QString(); search_attribs[Attributes::Tablespace] = tablespace ? tablespace->getName(false) : QString(); search_attribs[Attributes::Owner] = owner ? owner->getName(false) : QString(); search_attribs[Attributes::Comment] = comment; } bool BaseObject::isCodeInvalidated(void) { return(use_cached_code && code_invalidated); } bool BaseObject::isCodeDiffersFrom(const QString &xml_def1, const QString &xml_def2, const vector &ignored_attribs, const vector &ignored_tags) { QString xml, tag=QString("<%1").arg(this->getSchemaName()), attr_regex=QString("(%1=\")"), tag_regex=QString("<%1[^>]*((/>)|(>((?:(?!).)*)))"); QStringList xml_defs{ xml_def1, xml_def2 }; int start=0, end=-1, tag_end=-1; QRegExp regexp; for(int i=0; i < 2; i++) { xml=xml_defs[i].simplified(); //Removing ignored attributes for(QString attr : ignored_attribs) { do { regexp=QRegExp(attr_regex.arg(attr)); tag_end=xml.indexOf(QRegExp(QString("(\\\\)?(>)"))); start=regexp.indexIn(xml); end=xml.indexOf('"', start + regexp.matchedLength()); if(end > tag_end) end=-1; if(start >=0 && end >=0) xml.remove(start, (end - start) + 1); } while(start >= 0 && end >= 0); } //Removing ignored tags for(QString tag : ignored_tags) xml.remove(QRegExp(tag_regex.arg(tag))); xml_defs[i]=xml.simplified(); } return(xml_defs[0]!=xml_defs[1]); } bool BaseObject::isCodeDiffersFrom(BaseObject *object, const vector &ignored_attribs, const vector &ignored_tags) { if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(object->getObjectType()!=this->getObjectType()) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { return(BaseObject::isCodeDiffersFrom(this->getCodeDefinition(SchemaParser::XmlDefinition), object->getCodeDefinition(SchemaParser::XmlDefinition), ignored_attribs, ignored_tags)); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString BaseObject::getCachedCode(unsigned def_type, bool reduced_form) { if(use_cached_code && def_type==SchemaParser::SqlDefinition && schparser.getPgSQLVersion()!=BaseObject::pgsql_ver) code_invalidated=true; if(!code_invalidated && ((!reduced_form && !cached_code[def_type].isEmpty()) || (def_type==SchemaParser::XmlDefinition && reduced_form && !cached_reduced_code.isEmpty()))) { if(def_type==SchemaParser::XmlDefinition && reduced_form) return(cached_reduced_code); else return(cached_code[def_type]); } else return(QString()); } QString BaseObject::getDropDefinition(bool cascade) { try { if(acceptsDropCommand()) { attribs_map attribs; setBasicAttributes(true); schparser.setPgSQLVersion(BaseObject::pgsql_ver); schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); attribs=attributes; /* Creating an attribute that identifies the object type in order to permit conditional code generation inside the DROP script */ if(attribs.count(this->getSchemaName())==0) attribs[this->getSchemaName()]=Attributes::True; attribs[Attributes::Cascade]=(cascade ? Attributes::True : QString()); return(schparser.getCodeDefinition(Attributes::Drop, attribs, SchemaParser::SqlDefinition)); } else return(QString()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString BaseObject::getAlterDefinition(QString sch_name, attribs_map &attribs, bool ignore_ukn_attribs, bool ignore_empty_attribs) { try { SchemaParser schparser; QString alter_sch_dir=GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::AlterSchemaDir + GlobalAttributes::DirSeparator + QString("%1") + GlobalAttributes::SchemaExt; schparser.setPgSQLVersion(BaseObject::pgsql_ver); schparser.ignoreEmptyAttributes(ignore_empty_attribs); schparser.ignoreUnkownAttributes(ignore_ukn_attribs); return(schparser.getCodeDefinition(alter_sch_dir.arg(sch_name), attribs)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void BaseObject::copyAttributes(attribs_map &attribs) { if(!attribs.empty()) { attributes[Attributes::HasChanges]=Attributes::True; for(auto &itr : attribs) attributes[itr.first]=itr.second; } else attributes[Attributes::HasChanges]=QString(); } QString BaseObject::getAlterDefinition(BaseObject *object) { return(getAlterDefinition(object, false)); } QString BaseObject::getAlterDefinition(BaseObject *object, bool ignore_name_diff) { if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); QString alter; if(object->obj_type!=this->obj_type) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setBasicAttributes(true); try { QStringList attribs={ Attributes::Owner, Attributes::Schema, Attributes::Tablespace }; bool accepts_obj[3]={ acceptsOwner(), acceptsSchema(), acceptsTablespace() }; BaseObject *dep_objs[3]={ this->getOwner(), this->getSchema(), this->getTablespace() }, *aux_dep_objs[3]={ object->getOwner(), object->getSchema(), object->getTablespace() }; if(!ignore_name_diff && this->getName()!=object->getName()) { attributes[Attributes::NewName]=object->getName(true, false); alter+=BaseObject::getAlterDefinition(Attributes::Rename, attributes, true); attributes[Attributes::Name]=attributes[Attributes::NewName]; attributes[Attributes::Signature]=object->getSignature(true); } for(unsigned i=0; i < 3; i++) { if(accepts_obj[i] && dep_objs[i] && aux_dep_objs[i] && dep_objs[i]->getName(true)!=aux_dep_objs[i]->getName(true)) { attributes[attribs[i]]=aux_dep_objs[i]->getName(true); alter+=BaseObject::getAlterDefinition(attribs[i], attributes, true); } } alter += getAlterCommentDefinition(object, attributes); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } return(alter); } QString BaseObject::getAlterCommentDefinition(BaseObject *object, attribs_map attributes) { try { QString comm_this = this->getEscapedComment(escape_comments), comm_obj = object->getEscapedComment(escape_comments); if(comm_this != comm_obj) { if(comm_obj.isEmpty()) attributes[Attributes::Comment]=Attributes::Unset; else { attributes[Attributes::EscapeComment] = escape_comments ? Attributes::True : QString(); attributes[Attributes::Comment]=comm_obj; } schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); return(schparser.getCodeDefinition(Attributes::Comment, attributes, SchemaParser::SqlDefinition)); } return(QString()); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/baseobject.h000066400000000000000000000541711360462764600212340ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \class BaseObject \brief Implements the most important operations to define, maintain and generate code (SQL or XML) of database objects \note Creation date: 12/09/2006 \ingroup libpgmodeler */ #ifndef BASE_OBJECT_H #define BASE_OBJECT_H #include "attributes.h" #include "exception.h" #include "pgsqltypes.h" #include "schemaparser.h" #include "xmlparser.h" #include #include #include #include #include enum class ObjectType: unsigned { Column, Constraint, Function, Trigger, Index, Rule, Table, View, Domain, Schema, Aggregate, Operator, Sequence, Role, Conversion, Cast, Language, Type, Tablespace, OpFamily, OpClass, Database, Collation, Extension, EventTrigger, Policy, ForeignDataWrapper, ForeignServer, ForeignTable, UserMapping, Relationship, Textbox, Permission, Parameter, TypeAttribute, Tag, GenericSql, BaseRelationship, BaseObject, BaseTable }; class BaseObject { private: //! \brief Current PostgreSQL version used in SQL code generation static QString pgsql_ver; //! \brief Indicates the the cached code enabled static bool use_cached_code; static bool escape_comments; //! \brief Stores the set of special (valid) chars that forces the object's name quoting static const QByteArray special_chars; //! \brief Stores the database wich the object belongs BaseObject *database; protected: SchemaParser schparser; /*! \brief This static attribute is used to generate the unique identifier for objects. As object instances are created this value ​​are incremented. In some classes like Schema, DatabaseModel, Tablespace, Role, Type and Function id generators are used each with a custom different numbering range (see cited classes declaration). */ static unsigned global_id; /*! \brief Stores the unique identifier for the object. This id is nothing else than the current value of global_id. This identifier is used to know the chronological order of the creation of each object in the model because the generation and reading of the XML code is completely tied to the order in which the objects were created */ unsigned object_id; //! \brief Objects type count declared on enum ObjectType static constexpr unsigned ObjectTypeCount=enum_cast(ObjectType::BaseTable) + 1; /*! \brief Indicates whether the object is protected or not. A protected object indicates that it can not suffer changes in position (e.g. can not be moved or rotated) can not have your name / text changed, and deleted. This is only a flag, the cited operations are controled in a upper class layer */ bool is_protected, /*! \brief This property indicates that the object is a system protected object and cannot be modified by the user. Additionally, the this attribute is true the SQL/XML code for the object is not generated */ system_obj, /*! \brief Indicates if the generated SQL code is disable. When this flag is true the object's SQL code is created normally but is commented. This is useful when using the role only as a reference since it already exists on the destination server. */ sql_disabled, /*! \brief Indicates if the cached code is invalidated. Some key attributes of this class and other base classes automatically change the value of this attribute when the respective set[Attribute]() is called. For all the rest the method setCodeInvalidated() should be explicitly called if you need to invalidate the code and generate it again */ code_invalidated; //! \brief Stores the cached xml and sql code QString cached_code[2], //! \brief Stores the xml code in reduced form cached_reduced_code; /*! \brief This map stores the name of each object type associated to a schema file that generates the object's code definition */ static const QString objs_schemas[ObjectTypeCount]; /*! \brief This map associates the object type to a keyword on SQL language that represents the object */ static const QString objs_sql[ObjectTypeCount]; /*! \brief Stores the name of the type of objects to be used in error messages formatting and others operations that envolves object type name */ static const QString obj_type_names[ObjectTypeCount]; /*! \brief Role that is owner of the object. Some objects cannot be associated to a role so if one is assigned to the object an error will be raised */ BaseObject *owner; /*! \brief Schema the objects belongs. Some objects cannot be associated to a schema so if one is assigned to the object an error will be raised */ BaseObject *schema; /*! \brief Tablespace to which the object is part. Some objects cannot be associated to a tablespace so if one is assigned to the object an error will be raised */ BaseObject *tablespace; /*! \brief Collation referenced by the object. Some objects cannot be associated to a collation so if one is assigned to the object an error will be raised */ BaseObject *collation; //! \brief Comments related to object QString comment, //! \brief Object's name (in PostgreSQL accepted format) obj_name, //! \brief Object's alias (human readable / friendly) name alias, //! \brief The set of SQL commands appended on the objectc's definition appended_sql, //! \brief The set of SQL commands prepended on the objectc's definition prepended_sql; /*! \brief Stores the attributes and their values ​​shaped in strings to be used by SchemaParser on the object's code definition creation. The attribute name related to model objects are defined in ParsersAttributes namespace. */ attribs_map attributes, /*! \brief Stores the attributes and their vales which can be used by the * searching mechanism to match patters */ search_attribs; /*! \brief Type of object, may have one of the values ​​of the enum ObjectType It was used a numeric type to avoid the use excessive of RTTI. */ ObjectType obj_type; /*! \brief This method calls the getCodeDefinition(unsigned, bool) method with the 'reduced_form' defined as 'false', This is the real implementation of the virtual method getCodeDefinition(unsigned). */ QString __getCodeDefinition(unsigned def_type); /*! \brief Set the database that owns the object ATTENTION: calling this method with a nullptr parameter doesn't means that the object will be removed from the database, only the attribute will be set as nullptr and if the user calls getDatabase() in further operations may result in crash */ void setDatabase(BaseObject *db); /*! \brief Swap the the ids of the specified objects. The method will raise errors if the objects are the same, or some of them are system object. The boolean param enables the id swap between ordinary object and cluster level objects (database, tablespace and roles). */ static void swapObjectsIds(BaseObject *obj1, BaseObject *obj2, bool enable_cl_obj_swap); //! \brief Changes the current object id to the most recent global id value. static void updateObjectId(BaseObject *obj); //! \brief Clears all the attributes used by the SchemaParser void clearAttributes(void); /*! \brief Returns the cached code for the specified code type. This method returns an empty string in case of no code is cached */ QString getCachedCode(unsigned def_type, bool reduced_form); /*! \brief Configures the DIF_SQL attribute depending on the type of the object. This attribute is used to know how ALTER, COMMENT and DROP commands must be generated. Refer to schema files for comments, drop and alter. */ void setBasicAttributes(bool format_name); /*! \brief Compares two xml buffers and returns if they differs from each other. The user can specify which attributes and tags must be ignored when makin the comparison. NOTE: only the name for attributes and tags must be informed */ bool isCodeDiffersFrom(const QString &xml_def1, const QString &xml_def2, const vector &ignored_attribs, const vector &ignored_tags); /*! \brief Copies the non-empty attributes on the map at parameter to the own object attributes map. This method is used as an auxiliary when generating alter definition for some objects. When one or more attributes are copied an especial attribute is inserted (HAS_CHANGES) in order to help the atler generatin process to identify which attributes are products of comparison */ void copyAttributes(attribs_map &attribs); static QString getAlterDefinition(QString sch_name, attribs_map &attribs, bool ignore_ukn_attribs=false, bool ignore_empty_attribs=false); QString getAlterCommentDefinition(BaseObject *object, attribs_map attributes); public: //! \brief Maximum number of characters that an object name on PostgreSQL can have static constexpr int ObjectNameMaxLength=63; /*! \brief The default number of objects supposed to be stored in objects list. * This values is just a reference (hint) and is used to preallocate (reserve) space on vectors which handle objects * to avoid excessive allocation/deallocation by resizing the vectors due to insert operation */ static constexpr unsigned DefMaxObjectCount=20; BaseObject(void); BaseObject(bool system_obj); virtual ~BaseObject(void){} //! \brief Returns the reference to the database that owns the object BaseObject *getDatabase(void); /*! \brief Defines a specific attribute in the attribute list used to generate the code definition. This method can be used when a class needs to directly write some attributes of another class but does not have permission. */ void setAttribute(const QString &attrib, const QString &value); /*! \brief Returns whether the object name is in conformity with the PostgreSQL object naming rule. (e.g. 63 bytes long and chars in set [a-zA-z0-9_] */ static bool isValidName(const QString &name); /*! \brief Formats the passed name following the PostgreSQL object naming rule. The 'is_operator' parameter indicates that the passed name is a for an operator this is the only type of object that accepts characters outside of the alphabet (e.g. mathematical signs) on the composition of its name. In this case, the formatting function just ignores some validations if the parameter is checked */ static QString formatName(const QString &name, bool is_operator=false); //! \brief Returns the object's type translated name related to the passed object type static QString getTypeName(ObjectType obj_type); /*! \brief Returns the object's type translated name related to the passed object type id (in string format). The string parameter is the value returned by getSchemaName() */ static QString getTypeName(const QString &type_str); //! \brief Returns the object's type related to the passed type name static ObjectType getObjectType(const QString &type_name); /*! \brief Returns the schema identifier used to generate the code definition related to the passed object type */ static QString getSchemaName(ObjectType obj_type); //! \brief Returns the keyword related to the object on SQL language static QString getSQLName(ObjectType obj_type); //! \brief Returns the current value of the global object id counter static unsigned getGlobalId(void); static void setEscapeComments(bool value); static bool isEscapeComments(void); //! \brief Defines the comment of the object that will be attached to its SQL definition virtual void setComment(const QString &comment); //! \brief Defines the objects name. If the passed name isn't valid it'll raise an error virtual void setName(const QString &name); /*! \brief Defines the object's alias (human readable / friendly name). An alias is used when the database model is being * displayed in compact view. This method raises an error when the provided name is larger than 63 bytes * (the same rule for PostgreSQL names length) */ virtual void setAlias(const QString &alias); //! \brief Toggles the object's modify protection virtual void setProtected(bool value); /*! \brief Defines the schema that the object belongs. An error is raised if the passed schema is not valid or the object does not accepts the use of schemas. */ virtual void setSchema(BaseObject *schema); /*! \brief Defines the owner of the object. An error is raised if the passed owner is not valid or the object does not accepts the use of owners. */ virtual void setOwner(BaseObject *owner); /*! \brief Defines the tablespace which the objects will use. An error is raised if the passed tablespace is not valid or the object does not accepts the use of tablespaces. */ virtual void setTablespace(BaseObject *tablespace); /*! \brief Defines the collation which the objects will use. An error is raised if the passed collation is not valid or the object does not accepts the use of collations. */ virtual void setCollation(BaseObject *collation); //! \brief Disables the SQL code commenting it on generation virtual void setSQLDisabled(bool value); //! \brief Assign to the object a set of SQL commands to be appended to it's definition void setAppendedSQL(const QString &sql); //! \brief Assign to the object a set of SQL commands to be prepended to it's definition void setPrependedSQL(const QString &sql); //! \brief Returns if the generated SQL is commented bool isSQLDisabled(void); //! \brief Defines if the object is a system protected object virtual void setSystemObject(bool value); //! \brief Returns if the object is a system protected object bool isSystemObject(void); /*! \brief Returns the object's name. The parameter 'format' is used to get the name properly formated (using quotes when there is uppercase char or extended utf-8), the parameter 'prepend_schema' includes the schema name on the objects name (defult) */ virtual QString getName(bool format=false, bool prepend_schema=true); //! \brief Returns the object's alias (user friendly) name virtual QString getAlias(void); //! \brief Returns the name of the object with schema name (when available) prepended by default virtual QString getSignature(bool format=true); //! \brief Returns the object's comment (in raw form) QString getComment(void); /*! \brief Returns the object's comment in such way that the quotes are escaped as well, * if escape_special_chars is true, any line break and tabulation is returned in form \n and \t */ QString getEscapedComment(bool escape_special_chars); //! \brief Returns the object's type ObjectType getObjectType(void); //! \brief Returns the object's type name QString getTypeName(void); //! \brief Returns the object's schema name used to generate code definition QString getSchemaName(void); //! \brief Returns the keyword related to the object type QString getSQLName(void); //! \brief Returns the schema that the objects is part BaseObject *getSchema(void); //! \brief Returns the owner of the object BaseObject *getOwner(void); //! \brief Returns the tablespace that the object is part BaseObject *getTablespace(void); //! \brief Returns the collation that the object makes use BaseObject *getCollation(void); QString getAppendedSQL(void); QString getPrependedSQL(void); //! \brief Returns the object's generated id unsigned getObjectId(void); //! \brief Returns if the object is protected or not bool isProtected(void); //! \brief Assigns an object to other copiyng all the attributes correctly virtual void operator = (BaseObject &obj); /*! \brief Forcing the class to be virtual. This means that derivated classes may override this method in order to be possible its instatiation. */ virtual QString getCodeDefinition(unsigned)=0; /*! \brief Returns the object's SQL or XML code definition. The attribute 'reduced_form' indicates that the code generation will be an XML minimum representation of the object. See schema file for: functions, schemas, domains, types. */ virtual QString getCodeDefinition(unsigned def_type, bool reduced_form); /*! \brief Returns the SQL definition in form of ALTER commands containing the differences between the this and 'object'. This form do the camparison considering the difference on the objects' names (ignore_name_diff=false). This method is used in cases when the objects' name differences are important and can't be discarded */ virtual QString getAlterDefinition(BaseObject *object); /*! \brief Returns the SQL definition in form of ALTER commands containing the differences between the this and 'object'. The paramenter ignore_name_diff when true will cause the method to not generate a ALTER ... RENAME TO when the name of objects differs. */ virtual QString getAlterDefinition(BaseObject *object, bool ignore_name_diff); //!brief Returns the DROP statement for the object virtual QString getDropDefinition(bool cascade); //! \brief Returns if the specified type accepts to have a schema assigned static bool acceptsSchema(ObjectType obj_type); //! \brief Returns if the specified type accepts to have an owner assigned static bool acceptsOwner(ObjectType obj_type); //! \brief Returns if the specified type accepts to have a tablespace assigned static bool acceptsTablespace(ObjectType obj_type); //! \brief Returns if the specified type accepts to have a collation assigned static bool acceptsCollation(ObjectType obj_type); //! \brief Returns if the specified type accepts to have appended sql commands static bool acceptsCustomSQL(ObjectType obj_type); /*! \brief Returns if the specified type accepts the use of ALTER commands in order to change their attributes This is different from PostgreSQL implementation. In pgModeler, an object accepts ALTER when an attribute other than name, schema or owner can be changed. */ static bool acceptsAlterCommand(ObjectType obj_type); //! \brief Returns if the specified type accepts the use of DROP commands static bool acceptsDropCommand(ObjectType obj_type); //! \brief Returns if the specified type accepts an alias (friendly name) static bool acceptsAlias(ObjectType obj_type); //! \brief Returns if the object accepts to have a schema assigned bool acceptsSchema(void); //! \brief Returns if the object accepts to have an owner assigned bool acceptsOwner(void); //! \brief Returns if the object accepts to have a tablespace assigned bool acceptsTablespace(void); //! \brief Returns if the object accepts to have a collation assigned bool acceptsCollation(void); //! \brief Returns if the object accepts to have appended sql commands bool acceptsCustomSQL(void); //! \brief Returns if the object accepts the use of ALTER commands to have its attributes changed bool acceptsAlterCommand(void); //! \brief Returns if the object accepts the use of DROP commands bool acceptsDropCommand(void); /*! \brief Marks the current cached code as invalid and forces its regenaration. Some key attributes / setters in the base classes BaseObject, BaseTable and BaseRelationship will automatically invalidate the code but for all other setters / attributes the user must call this method explicitly in order to force the regeneration of the code. This method has no effect when the cached code support is disables. See enableCachedCode() */ virtual void setCodeInvalidated(bool value); virtual void configureSearchAttributes(void); //! \brief Returns if the code (sql and xml) is invalidated bool isCodeInvalidated(void); /*! \brief Compares the xml code between the "this" object and another one. The user can specify which attributes and tags must be ignored when makin the comparison. NOTE: only the name for attributes and tags must be informed */ virtual bool isCodeDiffersFrom(BaseObject *object, const vector &ignored_attribs={}, const vector &ignored_tags={}); /*! \brief Enable/disable the use of cached sql/xml code. When enabled the code generation speed is hugely increased but the downward is an increasing on memory usage. Make sure to every time when an attribute of any instance derivated of this class changes you need to call setCodeInvalidated() in order to force the update of the code cache */ static void enableCachedCode(bool value); /*! \brief Returns the valid object types in a vector. The types ObjectType::ObjBaseObject, TYPE_ATTRIBUTE and ObjectType::ObjBaseTable aren't included in return vector. By default table objects (columns, trigger, constraints, etc) are included. To avoid the insertion of these types set the boolean param to false. */ static vector getObjectTypes(bool inc_table_objs=true, vector exclude_types={}); /*! \brief Returns the valid object types that are child or grouped under the specified type. This method works a litte different from getObjectTypes() since this latter returns all valid types and this one returns only the valid types for the current specified type. For now the only accepted types are ObjectType::Database, ObjectType::Schema, ObjectType::Table, ObjectType::ForeignTable */ static vector getChildObjectTypes(ObjectType obj_type); /*! \brief Sets the default version when generating the SQL code. This affects all instances of classes that is based upon this one */ static void setPgSQLVersion(const QString &ver); //! \brief Returns the current version for SQL code generation static QString getPgSQLVersion(void); //! \brief Returns the set of attributes used by the search mechanism attribs_map getSearchAttributes(void); friend class DatabaseModel; friend class ModelValidationHelper; friend class DatabaseImportHelper; friend class SwapObjectsIdsWidget; friend class ModelWidget; }; #endif pgmodeler-0.9.2/libpgmodeler/src/baserelationship.cpp000066400000000000000000000371351360462764600230230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baserelationship.h" #include BaseRelationship::BaseRelationship(BaseRelationship *rel) { if(!rel) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); for(unsigned i=0; i < 3; i++) lables[i]=nullptr; src_table=dst_table=nullptr; (*(this))=(*rel); custom_color=QColor(Qt::transparent); reference_fk = nullptr; } BaseRelationship::BaseRelationship(unsigned rel_type, BaseTable *src_tab, BaseTable *dst_tab, bool src_mandatory, bool dst_mandatory) { try { QString str_aux; this->connected=false; this->src_mandatory=src_mandatory; this->dst_mandatory=dst_mandatory; this->src_table=src_tab; this->dst_table=dst_tab; this->rel_type=rel_type; this->custom_color=QColor(Qt::transparent); this->reference_fk=nullptr; for(unsigned i=0; i < 3; i++) { lables[i]=nullptr; lables_dist[i]=QPointF(DNaN, DNaN); } configureRelationship(); str_aux=QApplication::translate("BaseRelationship","rel_%1_%2","") .arg(src_tab->getName()).arg(dst_tab->getName()); if(str_aux.size() > BaseObject::ObjectNameMaxLength) str_aux.resize(BaseObject::ObjectNameMaxLength); setName(str_aux); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void BaseRelationship::configureRelationship(void) { obj_type=ObjectType::BaseRelationship; attributes[Attributes::Type]=QString(); attributes[Attributes::SrcRequired]=QString(); attributes[Attributes::DstRequired]=QString(); attributes[Attributes::SrcTable]=QString(); attributes[Attributes::DstTable]=QString(); attributes[Attributes::Points]=QString(); attributes[Attributes::Columns]=QString(); attributes[Attributes::Constraints]=QString(); attributes[Attributes::Elements]=QString(); attributes[Attributes::Identifier]=QString(); attributes[Attributes::ReducedForm]=QString(); attributes[Attributes::Deferrable]=QString(); attributes[Attributes::DeferType]=QString(); attributes[Attributes::TableName]=QString(); attributes[Attributes::SpecialPkCols]=QString(); attributes[Attributes::RelationshipNn]=QString(); attributes[Attributes::RelationshipGen]=QString(); attributes[Attributes::RelationshipDep]=QString(); attributes[Attributes::RelationshipPart]=QString(); attributes[Attributes::Relationship1n]=QString(); attributes[Attributes::Relationship11]=QString(); attributes[Attributes::Constraints]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::AncestorTable]=QString(); attributes[Attributes::CopyOptions]=QString(); attributes[Attributes::CopyMode]=QString(); attributes[Attributes::SrcColPattern]=QString(); attributes[Attributes::DstColPattern]=QString(); attributes[Attributes::PkPattern]=QString(); attributes[Attributes::UqPattern]=QString(); attributes[Attributes::SrcFkPattern]=QString(); attributes[Attributes::DstFkPattern]=QString(); attributes[Attributes::PkColPattern]=QString(); attributes[Attributes::SinglePkColumn]=QString(); attributes[Attributes::UpdAction]=QString(); attributes[Attributes::DelAction]=QString(); attributes[Attributes::CustomColor]=QString(); attributes[Attributes::ReferenceFk]=QString(); attributes[Attributes::PartitionBoundExpr]=QString(); attributes[Attributes::OriginalPk]=QString(); //Check if the relationship type is valid if(rel_type <= RelationshipFk) { //Raises an error if one of the tables is not allocated if(!src_table || !dst_table) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedTable) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::BaseRelationship)), ErrorCode::AsgNotAllocatedTable,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the relationship type is generalization or dependency and the source and destination table are the same. */ if((rel_type==RelationshipGen || rel_type==RelationshipDep || rel_type==RelationshipPart) && src_table==dst_table) throw Exception(ErrorCode::InvInheritCopyPartRelationship,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Allocates the textbox for the name label lables[RelNameLabel]=new Textbox; lables[RelNameLabel]->setTextAttribute(Textbox::ItalicText, true); //Allocates the cardinality labels only when the relationship is not generalization or dependency (copy) if(rel_type!=RelationshipGen && rel_type!=RelationshipDep && rel_type!=RelationshipPart) { lables[SrcCardLabel]=new Textbox; lables[DstCardLabel]=new Textbox; lables[SrcCardLabel]->setTextAttribute(Textbox::ItalicText, true); lables[DstCardLabel]->setTextAttribute(Textbox::ItalicText, true); //Configures the mandatory participation for both tables setMandatoryTable(SrcTable,src_mandatory); setMandatoryTable(DstTable,dst_mandatory); } } else //Raises an error if the specified relationship typ is invalid throw Exception(ErrorCode::AllocationObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } BaseRelationship::~BaseRelationship(void) { disconnectRelationship(); //Unallocates the labels for(unsigned i=0; i<3; i++) if(lables[i]) delete(lables[i]); } void BaseRelationship::setName(const QString &name) { try { BaseObject::setName(name); if(lables[RelNameLabel]) lables[RelNameLabel]->setComment(name); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void BaseRelationship::setMandatoryTable(unsigned table_id, bool value) { QString cmin, aux; unsigned label_id; /* Raises an error if the user tries to create an relationship One to One where both tables are mandatory partitipation (1,1)-<>-(1,1). This type of relationship is not implemented because it requires the table fusion. */ if(rel_type==Relationship11 && ((table_id==SrcTable && value && dst_mandatory) || (table_id==DstTable && value && src_mandatory))) throw Exception(ErrorCode::NotImplementedRelationshipType,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Case the source table is mandatory if(table_id==SrcTable) { src_mandatory=value; //Indicates that the source cardinality label will be configured label_id=SrcCardLabel; } else { if(rel_type!=Relationship1n) dst_mandatory=value; else /* For One to many (1-n) relationship the entity on the "many" side will be always in the format (0,n) */ dst_mandatory=false; //Indicates that the destination cardinality label will be configured label_id=DstCardLabel; } if(!value) cmin=QString("0"); else cmin=QString("1"); if(lables[label_id]) { if(rel_type==Relationship11) lables[label_id]->setComment(cmin + QString(":1")); else if(rel_type==Relationship1n) { aux=(table_id==SrcTable ? QString("1") : QString("n")); lables[label_id]->setComment(cmin + QString(":") + aux); } else if(rel_type==RelationshipFk) { if((table_id==SrcTable && dynamic_cast
(src_table)->isReferTableOnForeignKey(dynamic_cast
(dst_table))) || (!isSelfRelationship() && table_id==DstTable && dynamic_cast
(dst_table)->isReferTableOnForeignKey(dynamic_cast
(src_table)))) aux=QString("n"); else aux=QString("1"); lables[label_id]->setComment(aux); } else if(rel_type==RelationshipNn) lables[label_id]->setComment(QString("n")); lables[label_id]->setModified(true); } } BaseTable *BaseRelationship::getTable(unsigned table_id) { if(table_id==SrcTable) return(src_table); else if(table_id==DstTable) return(dst_table); else return(nullptr); } bool BaseRelationship::isTableMandatory(unsigned table_id) { if(table_id==SrcTable) return(src_mandatory); else return(dst_mandatory); } void BaseRelationship::setConnected(bool value) { connected=value; if(!this->signalsBlocked()) { src_table->setModified(true); if(dst_table!=src_table) dst_table->setModified(true); dynamic_cast(src_table->getSchema())->setModified(true); if(dst_table->getSchema()!=src_table->getSchema()) dynamic_cast(dst_table->getSchema())->setModified(true); this->setModified(true); } } void BaseRelationship::disconnectRelationship(void) { if(connected) { setConnected(false); setCodeInvalidated(true); } } void BaseRelationship::connectRelationship(void) { if(!connected) { setConnected(true); setCodeInvalidated(true); } } Textbox *BaseRelationship::getLabel(unsigned label_id) { if(label_id<=RelNameLabel) return(lables[label_id]); //Raises an error when the label id is invalid throw Exception(ErrorCode::RefLabelInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); } unsigned BaseRelationship::getRelationshipType(void) { return(rel_type); } bool BaseRelationship::isRelationshipConnected(void) { return(connected); } bool BaseRelationship::isSelfRelationship(void) { return(dst_table==src_table); } void BaseRelationship::setRelationshipAttributes(void) { unsigned count, i; QString str_aux, label_attribs[3]={ Attributes::SrcLabel, Attributes::DstLabel, Attributes::NameLabel}; attributes[Attributes::Layer]=QString::number(layer); attributes[Attributes::Type]=getRelTypeAttribute(); attributes[Attributes::SrcRequired]=(src_mandatory ? Attributes::True : QString()); attributes[Attributes::DstRequired]=(dst_mandatory ? Attributes::True : QString()); if(src_table) attributes[Attributes::SrcTable]=src_table->getName(true); if(dst_table) attributes[Attributes::DstTable]=dst_table->getName(true); count=points.size(); for(i=0; i < count; i++) { attributes[Attributes::XPos]=QString("%1").arg(points[i].x()); attributes[Attributes::YPos]=QString("%1").arg(points[i].y()); str_aux+=schparser.getCodeDefinition(Attributes::Position, attributes, SchemaParser::XmlDefinition); } attributes[Attributes::Points]=str_aux; str_aux=QString(); for(i=0; i < 3; i++) { if(!std::isnan(lables_dist[i].x())) { attributes[Attributes::XPos]=QString("%1").arg(lables_dist[i].x()); attributes[Attributes::YPos]=QString("%1").arg(lables_dist[i].y()); attributes[Attributes::Position]=schparser.getCodeDefinition(Attributes::Position, attributes, SchemaParser::XmlDefinition); attributes[Attributes::RefType]=label_attribs[i]; str_aux+=schparser.getCodeDefinition(Attributes::Label, attributes, SchemaParser::XmlDefinition); } } attributes[Attributes::LabelsPos]=str_aux; attributes[Attributes::CustomColor]=(custom_color!=Qt::transparent ? custom_color.name() : QString()); attributes[Attributes::ReferenceFk]=(reference_fk ? reference_fk->getName() : QString()); setFadedOutAttribute(); } QString BaseRelationship::getCachedCode(unsigned def_type) { if(!code_invalidated && ((!cached_code[def_type].isEmpty()) || (def_type==SchemaParser::XmlDefinition && !cached_reduced_code.isEmpty()))) { if(def_type==SchemaParser::XmlDefinition && !cached_reduced_code.isEmpty()) return(cached_reduced_code); else return(cached_code[def_type]); } else return(QString()); } void BaseRelationship::setReferenceForeignKey(Constraint *ref_fk) { //if(ref_fk && rel_type != RELATIONSHIP_FK) //Throw error... this->reference_fk = ref_fk; } Constraint *BaseRelationship::getReferenceForeignKey(void) { return(reference_fk); } QString BaseRelationship::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type); if(!code_def.isEmpty()) return(code_def); if(def_type==SchemaParser::SqlDefinition) { if(rel_type!=RelationshipFk) return(QString()); else { cached_code[def_type] = reference_fk->getCodeDefinition(SchemaParser::SqlDefinition); return(cached_code[def_type]); } } else { bool reduced_form; setRelationshipAttributes(); reduced_form=(attributes[Attributes::Points].isEmpty() && attributes[Attributes::LabelsPos].isEmpty()); if(!reduced_form) cached_reduced_code.clear(); return(BaseObject::getCodeDefinition(SchemaParser::XmlDefinition,reduced_form)); } } void BaseRelationship::setPoints(const vector &points) { this->setCodeInvalidated(true); this->points=points; } void BaseRelationship::setLabelDistance(unsigned label_id, QPointF label_dist) { if(label_id > RelNameLabel) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->lables_dist[label_id]=label_dist; this->setCodeInvalidated(true); } QPointF BaseRelationship::getLabelDistance(unsigned label_id) { if(label_id > RelNameLabel) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(this->lables_dist[label_id]); } void BaseRelationship::setCustomColor(const QColor &color) { custom_color=color; } QColor BaseRelationship::getCustomColor(void) { return(custom_color); } void BaseRelationship::resetLabelsDistance(void) { for(unsigned i=0; i < 3; i++) this->setLabelDistance(i, QPointF(DNaN,DNaN)); } vector BaseRelationship::getPoints(void) { return(points); } void BaseRelationship::operator = (BaseRelationship &rel) { (*dynamic_cast(this))=dynamic_cast(rel); this->connected=false; this->src_table=rel.src_table; this->dst_table=rel.dst_table; this->rel_type=rel.rel_type; this->points=rel.points; for(int i=0; i < 3; i++) { if(rel.lables[i]) { if(!this->lables[i]) this->lables[i]=new Textbox; (*this->lables[i])=(*rel.lables[i]); } this->lables_dist[i]=rel.lables_dist[i]; } this->setMandatoryTable(SrcTable, false); this->setMandatoryTable(DstTable, false); this->setMandatoryTable(SrcTable, rel.src_mandatory); this->setMandatoryTable(DstTable, rel.dst_mandatory); } QString BaseRelationship::getRelTypeAttribute(void) { switch(rel_type) { case Relationship11: return(Attributes::Relationship11); case Relationship1n: return(Attributes::Relationship1n); case RelationshipNn: return(Attributes::RelationshipNn); case RelationshipGen: return(Attributes::RelationshipGen); case RelationshipPart: return(Attributes::RelationshipPart); case RelationshipFk: return(Attributes::RelationshipFk); default: { if(src_table->getObjectType()==ObjectType::View) return(Attributes::RelationshipTabView); else return(Attributes::RelationshipDep); } } } QString BaseRelationship::getRelationshipTypeName(unsigned rel_type, bool is_view) { switch(rel_type) { case Relationship11: return(trUtf8("One-to-one")); case Relationship1n: return(trUtf8("One-to-many")); case RelationshipNn: return(trUtf8("Many-to-many")); case RelationshipGen: return(trUtf8("Inheritance")); case RelationshipPart: return(trUtf8("Partitioning")); case RelationshipFk: return(trUtf8("FK relationship")); default: { if(is_view) return(trUtf8("Dependency")); else return(trUtf8("Copy")); } } } QString BaseRelationship::getRelationshipTypeName(void) { return(getRelationshipTypeName(rel_type, src_table->getObjectType()==ObjectType::View)); } void BaseRelationship::setCodeInvalidated(bool value) { BaseObject::setCodeInvalidated(value); if(src_table) src_table->setCodeInvalidated(value); if(dst_table) dst_table->setCodeInvalidated(value); } pgmodeler-0.9.2/libpgmodeler/src/baserelationship.h000066400000000000000000000145051360462764600224640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class BaseRelationship \brief Implements the basic operations to manipulate relationships between tables \note Creation date: 09/04/2008 */ #ifndef BASE_RELATIONSHIP_H #define BASE_RELATIONSHIP_H #include "table.h" #include "textbox.h" #include "schema.h" #include #include class BaseRelationship: public BaseGraphicObject { protected: //! \brief This attribute stores the foreign key used to generate the relationship (only for FK relationships) Constraint *reference_fk; //! \brief This attribute overrides the default color configuration for relationship line and descriptor QColor custom_color; //! \brief Represents the points added by the user on the relationship line vector points; //! \brief Indicates whether the relationship is linked to the tables bool connected; //! \brief Indicates the mandatory participation of source and destination tables bool dst_mandatory, src_mandatory; /*! \brief Relationship lables: 0 - Source cardinality 1 - Destination cardinality 2 - Relationship name */ Textbox *lables[3]; /*! \brief Stores the distances of the labels from its respectively origins. This is used to controle de position of the labels when they are moved by the user */ QPointF lables_dist[3]; //! \brief Entities envolved on the relationship BaseTable *src_table, *dst_table; /*! \brief Relationship type. It can be "One to One", "One to Many", "Many to Many", "Generalization", "Dependecy". The constants RELATIONSHIP_??? are used to assign a type to the relationship */ unsigned rel_type; //! \brief Sets the attributes used on the generation of XML definition for relationship void setRelationshipAttributes(void); //! \brief Makes the initial configuration creating the labels void configureRelationship(void); //! \brief Marks the flag indicating that relationship is connected void connectRelationship(void); //! \brief Uncheck the flag indicating that relationship is disconnected void disconnectRelationship(void); //! \brief Toggles the connected flag and forces the tables/schemas/relationship update void setConnected(bool value); QString getCachedCode(unsigned def_type); virtual QString getDropDefinition(bool) final { return(""); } void setReferenceForeignKey(Constraint *reference_fk); public: //! \brief Constants used to assign the type to relationship static constexpr unsigned Relationship11=10, //! \brief One to one Relationship1n=11, //! \brief One to many RelationshipNn=12, //! \brief Many to many RelationshipGen=13, //! \brief Generalization (Inheritance) RelationshipDep=14, //! \brief Dependency (table-view) / Copy (table-table) RelationshipPart=15,//! \brief Partitioning relationship RelationshipFk=16; //! \brief Relationship generated by creating a foreign key manually on a table //! \brief Constats used to reference the relationship labels static constexpr unsigned SrcCardLabel=0, DstCardLabel=1, RelNameLabel=2; //! \brief Constants used to reference the source and destination tables static constexpr unsigned SrcTable=0, DstTable=1; BaseRelationship(BaseRelationship *rel); BaseRelationship(unsigned rel_type, BaseTable *src_tab, BaseTable *dst_tab, bool dst_mandatory, bool src_mandatory); ~BaseRelationship(void); //! \brief Sets the name of the relationship void setName(const QString &name); //! \brief Sets the mandatory participation for the specified table (Via constants SRC_TABLE | DST_TABLE) void setMandatoryTable(unsigned table_id, bool value); //! \brief Return one relationship label using its id (Via constants LABEL_???) Textbox *getLabel(unsigned label_id); //! \brief Returns one of the participant tables (Via constants SRC_TABLE | DST_TABLE) BaseTable *getTable(unsigned table_id); //! \brief Returns the relationship type unsigned getRelationshipType(void); //! \brief Returns the mandatory participation for the specified table (Via constants SRC_TABLE | DST_TABLE) bool isTableMandatory(unsigned table_id); //! \brief Returns the relationship connection state bool isRelationshipConnected(void); /*! \brief Since base relationships doesn't has SQL code definition this method will return a empty definition whenever the user try to generate a SQL for this object. */ virtual QString getCodeDefinition(unsigned def_type); //! \brief Returns whether the table is linked to itself via relationship (self-relationship) bool isSelfRelationship(void); //! \brief Stores the points that defines the custom relationship line void setPoints(const vector &points); //! \brief Returns the relationship point list vector getPoints(void); //! \brief Sets the distance of the specified label in relation to its origin void setLabelDistance(unsigned label_id, QPointF label_dist); //! \brief Gets the distance of the specified label in relation to its origin QPointF getLabelDistance(unsigned label_id); void setCustomColor(const QColor &color); QColor getCustomColor(void); void resetLabelsDistance(void); Constraint *getReferenceForeignKey(void); //! \brief Assigns one relationship to other making the appropriate attribute copy void operator = (BaseRelationship &rel); QString getRelTypeAttribute(void); virtual void setCodeInvalidated(bool value); virtual QString getAlterDefinition(BaseObject *) { return(""); } static QString getRelationshipTypeName(unsigned rel_type, bool is_view = false); QString getRelationshipTypeName(void); friend class DatabaseModel; friend class RelationshipWidget; friend class ModelWidget; }; #endif pgmodeler-0.9.2/libpgmodeler/src/basetable.cpp000066400000000000000000000057131360462764600214060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "basetable.h" BaseTable::BaseTable(void) { tag=nullptr; obj_type=ObjectType::BaseTable; attributes[Attributes::Tag]=QString(); attributes[Attributes::MaxObjCount]=QString(); attributes[Attributes::CollapseMode]=QString(); attributes[Attributes::Pagination]=QString(); attributes[Attributes::AttribsPage]=QString(); attributes[Attributes::ExtAttribsPage]=QString(); pagination_enabled = false; collapse_mode = CollapseMode::NotCollapsed; resetCurrentPages(); } void BaseTable::resetCurrentPages(void) { curr_page[AttribsSection] = 0; curr_page[ExtAttribsSection] = 0; } void BaseTable::setTag(Tag *tag) { setCodeInvalidated(this->tag != tag); this->tag=tag; } Tag *BaseTable::getTag(void) { return(tag); } bool BaseTable::isBaseTable(ObjectType obj_type) { return(obj_type == ObjectType::Table || obj_type == ObjectType::ForeignTable || obj_type == ObjectType::View); } QString BaseTable::getAlterDefinition(BaseObject *object) { try { return(BaseObject::getAlterDefinition(object)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void BaseTable::operator = (BaseTable &tab) { (*dynamic_cast(this))=dynamic_cast(tab); this->tag=tab.tag; } CollapseMode BaseTable::getCollapseMode(void) { return(collapse_mode); } void BaseTable::setPaginationEnabled(bool value) { setCodeInvalidated(pagination_enabled != value); pagination_enabled = value; if(!pagination_enabled) resetCurrentPages(); } bool BaseTable::isPaginationEnabled(void) { return(pagination_enabled); } void BaseTable::setCurrentPage(unsigned section_id, unsigned value) { if(section_id > ExtAttribsSection) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(curr_page[section_id] != value); curr_page[section_id] = value; } unsigned BaseTable::getCurrentPage(unsigned section_id) { if(section_id > ExtAttribsSection) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(curr_page[section_id]); } void BaseTable::setCollapseMode(CollapseMode coll_mode) { setCodeInvalidated(collapse_mode != coll_mode); collapse_mode = coll_mode; } pgmodeler-0.9.2/libpgmodeler/src/basetable.h000066400000000000000000000126361360462764600210550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class BaseTable \brief Base class used to define table like objects (views and tables) \note Creation date: 09/04/2008 */ #ifndef BASE_TABLE_H #define BASE_TABLE_H #include "basegraphicobject.h" #include "tag.h" //! \brief This enum is used to control the collapsing of the tables enum class CollapseMode: unsigned { AllAttribsCollapsed, //Columns (attributes) and extended attributes are collapsed ExtAttribsCollapsed, //Extended attributes are collapsed NotCollapsed //Table is fully expanded (columns and extended attributes) }; class BaseTable: public BaseGraphicObject { protected: Tag *tag; //! \brief Indicates if the pagination is enabled for the table bool pagination_enabled; //! \brief Stores the current collpase mode for the table CollapseMode collapse_mode; //! \brief Stores the current page visible on the table unsigned curr_page[2]; public: static constexpr unsigned AttribsSection = 0, ExtAttribsSection = 1; BaseTable(void); virtual void setTag(Tag *tag); virtual Tag *getTag(void); //! \brief Returns true if the provided table is considered a base table (Table, ForeignTable, View) static bool isBaseTable(ObjectType obj_type); //! \brief Adds an object to the table. It can be inserted at a specified index 'obj_idx'. virtual void addObject(BaseObject *obj, int obj_idx=-1)=0; //! \brief Gets a object from table through its index and type virtual BaseObject *getObject(unsigned obj_idx, ObjectType obj_type)=0; //! \brief Gets a object from table through its name and type virtual BaseObject *getObject(const QString &name, ObjectType obj_type)=0; //! \brief Removes a object from table through its index and type virtual void removeObject(unsigned obj_idx, ObjectType obj_type)=0; //! \brief Removes a object from table through its name and type virtual void removeObject(const QString &name, ObjectType obj_type)=0; //! \brief Removes the specified object from table virtual void removeObject(BaseObject *obj)=0; /*! \brief Gets the the count for the specified object type. The boolean parameter indicates that objects added by relationship must be counted */ virtual unsigned getObjectCount(ObjectType obj_type, bool inc_added_by_rel=true)=0; //! \brief Gets the object index using its name and type virtual int getObjectIndex(const QString &name, ObjectType obj_type)=0; //! \brief Returns the index for the specified table object virtual int getObjectIndex(BaseObject *obj)=0; //! \brief Returns all children objects of the table but excluding the ones of the provided type virtual vector getObjects(const vector &excl_types = {})=0; virtual QString getCodeDefinition(unsigned tipo_def)=0; virtual QString getAlterDefinition(BaseObject *object); /*! \brief Set the initial capacity of the objects list for a optimized memory usage. * This method should be called prior to adding the first object to the table because, depending o the capacity, * there'll be memory reallocations which can degradate the performance */ virtual void setObjectListsCapacity(unsigned capacity) = 0; //! \brief Returns the maximum item count from all of the objects lists virtual unsigned getMaxObjectCount(void) = 0; //! \brief Copy the attributes between two tables void operator = (BaseTable &tab); /*! \brief Defines the current collapse mode for the table. Calling this method direclty * will not update the geometry of the graphical representation of this object. For that, * the setModified(true) should be called */ void setCollapseMode(CollapseMode coll_mode); CollapseMode getCollapseMode(void); /*! \brief Defines the pagination enabling for the table. Calling this method direclty * will not update the geometry of the graphical representation of this object. For that, * the setModified(true) should be called */ void setPaginationEnabled(bool value); bool isPaginationEnabled(void); /*! \brief Defines the current page visible on the table. Calling this method direclty * will not update the geometry of the graphical representation of this object. For that, * the setModified(true) should be called */ void setCurrentPage(unsigned section_id, unsigned value); void resetCurrentPages(void); unsigned getCurrentPage(unsigned section_id); /*! \brief Returns the data dictionary definition of the table (in HTML format). * The splitted parameter is used to inform the generation process that the dicts are being * saved in separated files. This changes the way links are generated inside the data dictionaries */ virtual QString getDataDictionary(bool splitted, attribs_map extra_attribs = {}) = 0; friend class DatabaseModel; }; #endif pgmodeler-0.9.2/libpgmodeler/src/cast.cpp000066400000000000000000000154761360462764600204250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "cast.h" Cast::Cast(void) { obj_type=ObjectType::Cast; cast_function=nullptr; cast_type=Explicit; is_in_out=false; attributes[Attributes::SourceType]=QString(); attributes[Attributes::DestType]=QString(); attributes[Attributes::CastType]=QString(); attributes[Attributes::IoCast]=QString(); attributes[Attributes::Function]=QString(); } void Cast::setDataType(unsigned type_idx, PgSqlType type) { //Check if the type index is valid if(type_idx<=DstType) { //Raises an error if the passed data type is null if((*type).isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNullTypeObject) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Cast)), ErrorCode::AsgNullTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->types[type_idx] != type); this->types[type_idx]=type; } else //Raises an error if the type index is invalid throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Configures the cast name (in form of signature: cast(src_type, dst_type) ) this->obj_name=QString("cast(%1,%2)").arg(~types[SrcType]).arg(~types[DstType]); } void Cast::setCastType(unsigned cast_type) { //Raises an error if the user tries to assign an invalid cast type if(cast_type > Implicit) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->cast_type != cast_type); this->cast_type=cast_type; } void Cast::setInOut(bool value) { setCodeInvalidated(is_in_out != value); is_in_out=value; } void Cast::setCastFunction(Function *cast_func) { unsigned param_count; bool error=false; PgSqlType ret_type; if(!cast_func) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Cast)), ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Retrieve the cast function parameter count for specific validations param_count=cast_func->getParameterCount(); //Raises an error if the function don't have at least 1 parameter or a maximum of 3 if(param_count==0 || param_count > 3) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Cast)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { /* Error condition 1: Check if the first function parameter data type differs from cast source data type */ error=(cast_func->getParameter(0).getType()!=this->types[SrcType] && !cast_func->getParameter(0).getType().canCastTo(this->types[SrcType])); /* Error condition 2: Check if the second function parameter data type is different from 'integer' */ if(!error && param_count>=2) error=(cast_func->getParameter(1).getType()!=QString("integer")); /* Error condition 3: Check if the third function parameter data type is different from 'boolean' */ if(!error && param_count==3) error=(cast_func->getParameter(2).getType()!=QString("boolean")); //In case some error condition is reached raises an error if(error) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParameters) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Cast)), ErrorCode::AsgFunctionInvalidParameters,__PRETTY_FUNCTION__,__FILE__,__LINE__); } /* Raises an error if the return type of the function differs from the destination data type. If the types can be casted between them no error is returned */ ret_type=cast_func->getReturnType(); if(ret_type!=this->types[DstType] && !ret_type.canCastTo(this->types[DstType])) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidReturnType) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Cast)), ErrorCode::AsgFunctionInvalidReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(cast_function != cast_func); this->cast_function=cast_func; } PgSqlType Cast::getDataType(unsigned type_idx) { if(type_idx > DstType) throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(this->types[type_idx]); } bool Cast::isInOut(void) { return(is_in_out); } Function *Cast::getCastFunction(void) { return(cast_function); } unsigned Cast::getCastType(void) { return(cast_type); } QString Cast::getDropDefinition(bool cascade) { attributes[Attributes::Signature].replace(QString(","), QString(" AS ")); return(BaseObject::getDropDefinition(cascade)); } QString Cast::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); if(def_type==SchemaParser::SqlDefinition) { attributes[Attributes::SourceType]=(*types[SrcType]); attributes[Attributes::DestType]=(*types[DstType]); } else { attributes[Attributes::SourceType]=types[SrcType].getCodeDefinition(def_type); attributes[Attributes::DestType]=types[DstType].getCodeDefinition(def_type); } if(!is_in_out && cast_function) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Function]=cast_function->getSignature(); else attributes[Attributes::Function]=cast_function->getCodeDefinition(def_type, true); } else attributes[Attributes::IoCast]=(is_in_out ? Attributes::True : QString()); if(cast_type==Assignment) attributes[Attributes::CastType]=Attributes::Assignment; else if(cast_type==Implicit) attributes[Attributes::CastType]=Attributes::Implicit; else attributes[Attributes::CastType]=QString(); if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::CastType]=attributes[Attributes::CastType].toUpper(); return(BaseObject::__getCodeDefinition(def_type)); } QString Cast::getSignature(bool) { attributes[Attributes::Signature]=this->getName().remove(QString("cast")); return(BaseObject::getSignature(false)); } void Cast::configureSearchAttributes(void) { QStringList arg_types; BaseObject::configureSearchAttributes(); arg_types += *types[0]; arg_types += *types[1]; search_attribs[Attributes::Type] = arg_types.join("; "); } pgmodeler-0.9.2/libpgmodeler/src/cast.h000066400000000000000000000056011360462764600200570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Cast \brief Implements the operations to manipulate data type cast on the database \note Creation date: 03/06/2008 */ #ifndef CAST_H #define CAST_H #include "baseobject.h" #include "function.h" class Cast: public BaseObject { private: /*! \brief Data types used on the cast: 0 -> Source data type 1 -> Destination data type */ PgSqlType types[2]; //! \brief Conversion type (ASSIGNMENT or IMPLICIT) unsigned cast_type; //! \brief Function used to do the type cast Function *cast_function; /*! \brief Indicates that the type cast is inout, this means that the function used to cast the types will be the 'output' function of the source data type */ bool is_in_out; protected: virtual void configureSearchAttributes(void); public: //! \brief Constants used to access the data types envolved in the cast static constexpr unsigned SrcType=0, DstType=1, //! \brief Constants used to define the cast type Explicit=0, Assignment=1, Implicit=2; Cast(void); /*! \brief Defines one of the data types envolved on the cast (using constants SRC_TYPE | DST_TYPE) */ void setDataType(unsigned type_idx, PgSqlType type); //! \brief Defines the cast type (using constants ASSINGMENT | IMPLICIT) void setCastType(unsigned cast_type); //! \brief Defines the function used to do the type cast void setCastFunction(Function *cast_func); /*! \brief Defines if the conversion is inout. If so the conversion function assigned to the cast is ignored since the PostgreSQL will use the output function of the source type. */ void setInOut(bool value); //! \brief Returns one of the cast envolved data types PgSqlType getDataType(unsigned type_idx); //! \brief Returns the cast type unsigned getCastType(void); //! \brief Returns the cast function Function *getCastFunction(void); //! \brief Returs whether the cast is inout or not bool isInOut(void); //! \brief Returns the SQL/XML code definition for the cast virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool=false) final; QString getDropDefinition(bool cascade) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/collation.cpp000066400000000000000000000100271360462764600214420ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "collation.h" Collation::Collation(void) { obj_type=ObjectType::Collation; encoding=BaseType::Null; attributes[Attributes::LcCtype]=QString(); attributes[Attributes::LcCollate]=QString(); attributes[Attributes::Locale]=QString(); attributes[Attributes::Encoding]=QString(); } void Collation::setLocale(const QString &locale) { setLocalization(LcCtype, locale); setLocalization(LcCollate, locale); this->locale=locale; } void Collation::setLocalization(unsigned lc_id, QString lc_name) { if(locale.isEmpty()) { if(lc_id > LcCollate) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Removes encoding specification from localization e.g 'aa_BB.ENC' will turn into 'aa_BB' since the encoding is appended on code generation */ lc_name.remove(lc_name.indexOf('.'), lc_name.size()); setCodeInvalidated(localization[lc_id] != lc_name); localization[lc_id]=lc_name; } } void Collation::setEncoding(EncodingType encoding) { this->encoding=encoding; } void Collation::setCollation(BaseObject *collation) { if(collation==this) throw Exception(Exception::getErrorMessage(ErrorCode::ObjectReferencingItself) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::ObjectReferencingItself,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObject::setCollation(collation); encoding=BaseType::Null; locale.clear(); localization[0]=localization[1]=QString(); } QString Collation::getLocale(void) { return(locale); } QString Collation::getLocalization(unsigned lc_id) { if(lc_id > LcCollate) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(localization[lc_id]); } EncodingType Collation::getEncoding(void) { return(encoding); } QString Collation::getCodeDefinition(unsigned def_type) { return(getCodeDefinition(def_type, false)); } QString Collation::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); if(!locale.isEmpty()) { attributes[Attributes::Locale]=locale; if(def_type==SchemaParser::SqlDefinition && encoding!=BaseType::Null) attributes[Attributes::Locale]=locale + "." + (~encoding).toLower(); } else if(collation) attributes[Attributes::Collation]=collation->getName(true); else { QString lc_attribs[2]={ Attributes::LcCtype, Attributes::LcCollate }; if(localization[LcCtype].isEmpty() && localization[LcCollate].isEmpty()) throw Exception(ErrorCode::EmptyLCCollationAttributes,__PRETTY_FUNCTION__,__FILE__,__LINE__); for(unsigned int i=LcCtype; i <= LcCollate; i++) { attributes[lc_attribs[i]]=getLocalization(i); if(def_type==SchemaParser::SqlDefinition && encoding!=BaseType::Null && !attributes[lc_attribs[i]].isEmpty()) attributes[lc_attribs[i]]+="." + (~encoding).toLower(); } } attributes[Attributes::Encoding]=~encoding; return(BaseObject::getCodeDefinition(def_type, reduced_form)); } QString Collation::getAlterDefinition(BaseObject *object) { try { attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, false)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/collation.h000066400000000000000000000053011360462764600211060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Collation \brief Implements the operations to manipulate collations on the database. **/ #ifndef COLLATION_H #define COLLATION_H #include "baseobject.h" #include "pgsqltypes.h" class Collation : public BaseObject { private: /*! \brief Base encoding for the collation. When setting the locale or lc_??? attributes the encoding name will be appended to the attributes. Example: encoding=UTF8 locale=pt_BR LC_TYPE=pt_BR.utf8 LC_CTYPE=pt_BR.utf8 */ EncodingType encoding; //! \brief LC_CTYPE and LC_COLLATE attributes QString localization[2], /*! \brief This attribute sets at once the localization attribute. Using this attribute user cannot change localization attributes */ locale; public: static constexpr unsigned LcCtype=0, LcCollate=1; Collation(void); /*! \brief Sets the collation locale and the base encoding. This method specifies at once the LC_CTYPE and LC_COLLATE attributes. When the user calls this method with 'locale' set the use of setLocalization() has no effect. To use custom localizations the user must reset 'locale' to a empty value. */ void setLocale(const QString &locale); //! \brief Configures the LC_CTYPE and LC_COLLATE attributes and the default encoding for them. void setLocalization(unsigned lc_id, QString lc_name); /*! \brief Sets the collation from which this collation will copy attributes. The use of this method nullifies all the other collation's attributes */ void setCollation(BaseObject *collation); //! \brief Defines the base encoding for the collation void setEncoding(EncodingType encoding); QString getLocale(void); QString getLocalization(unsigned lc_id); EncodingType getEncoding(void); //! \brief Returns the SQL / XML definition for the collation. virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getAlterDefinition(BaseObject *object); }; #endif pgmodeler-0.9.2/libpgmodeler/src/column.cpp000066400000000000000000000267441360462764600207700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "column.h" Column::Column(void) { obj_type=ObjectType::Column; not_null=seq_cycle=false; attributes[Attributes::Type]=QString(); attributes[Attributes::DefaultValue]=QString(); attributes[Attributes::NotNull]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::Sequence]=QString(); attributes[Attributes::DeclInTable]=QString(); attributes[Attributes::IdentityType]=QString(); attributes[Attributes::Increment]=QString(); attributes[Attributes::MinValue]=QString(); attributes[Attributes::MaxValue]=QString(); attributes[Attributes::Start]=QString(); attributes[Attributes::Cache]=QString(); attributes[Attributes::Cycle]=QString(); parent_rel=sequence=nullptr; identity_type=BaseType::Null; } void Column::setName(const QString &name) { try { QString prev_name; //The current column name will be used as the old name prev_name=this->obj_name; //Tries to define the new name to column BaseObject::setName(name); /* Case no error is raised stored the old name on the respective column attribute */ this->old_name=prev_name; } catch(Exception &e) { throw Exception(e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Column::setType(PgSqlType type) { //An error is raised if the column receive a pseudo-type as data type. if(type.isPseudoType()) throw Exception(ErrorCode::AsgPseudoTypeColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(this->identity_type != BaseType::Null && !type.isIntegerType()) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidIdentityColumn).arg(getSignature()), ErrorCode::InvalidIdentityColumn, __PRETTY_FUNCTION__, __FILE__, __LINE__); } setCodeInvalidated(this->type != type); this->type=type; } void Column::setIdentityType(IdentityType id_type) { if(id_type != BaseType::Null && !type.isIntegerType()) { throw Exception(Exception::getErrorMessage(ErrorCode::InvalidIdentityColumn).arg(getSignature()), ErrorCode::InvalidIdentityColumn, __PRETTY_FUNCTION__, __FILE__, __LINE__); } setCodeInvalidated(identity_type != id_type); identity_type = id_type; default_value.clear(); sequence = nullptr; //Identity column implies NOT NULL constraint if(id_type != BaseType::Null) setNotNull(true); } void Column::setDefaultValue(const QString &value) { setCodeInvalidated(default_value != value); default_value=value.trimmed(); sequence=nullptr; identity_type=BaseType::Null; } void Column::setNotNull(bool value) { setCodeInvalidated(not_null != value); not_null=value; } PgSqlType Column::getType(void) { return(type); } IdentityType Column::getIdentityType(void) { return(identity_type); } bool Column::isNotNull(void) { return(not_null); } bool Column::isIdentity(void) { return(identity_type != BaseType::Null); } QString Column::getTypeReference(void) { if(getParentTable()) return(getParentTable()->getName(true) + QString(".") + this->getName(true) + QString("%TYPE")); else return(QString()); } QString Column::getDefaultValue(void) { return(default_value); } QString Column::getOldName(bool format) { if(format) return(BaseObject::formatName(old_name)); else return(old_name); } void Column::setParentRelationship(BaseObject *parent_rel) { if(parent_rel && parent_rel->getObjectType()!=ObjectType::Relationship) throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->parent_rel=parent_rel; } BaseObject *Column::getParentRelationship(void) { return(parent_rel); } void Column::setSequence(BaseObject *seq) { if(seq) { if(seq->getObjectType()!=ObjectType::Sequence) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidObjectType) .arg(this->obj_name) .arg(this->getTypeName()) .arg(BaseObject::getTypeName(ObjectType::Sequence)), ErrorCode::AsgInvalidObjectType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!type.isIntegerType()) throw Exception(Exception::getErrorMessage(ErrorCode::IncompColumnTypeForSequence) .arg(seq->getName(true)) .arg(this->obj_name), ErrorCode::IncompColumnTypeForSequence,__PRETTY_FUNCTION__,__FILE__,__LINE__); default_value=QString(); identity_type=BaseType::Null; } setCodeInvalidated(sequence != seq); sequence=seq; } BaseObject *Column::getSequence(void) { return(sequence); } bool Column::isIdSeqCycle(void) { return(seq_cycle); } QString Column::getIdSeqMaxValue(void) { return(seq_max_value); } QString Column::getIdSeqMinValue(void) { return(seq_min_value); } QString Column::getIdSeqIncrement(void) { return(seq_increment); } QString Column::getIdSeqStart(void) { return(seq_start); } QString Column::getIdSeqCache(void) { return(seq_cache); } void Column::setIdSeqAttributes(QString minv, QString maxv, QString inc, QString start, QString cache, bool cycle) { seq_min_value = minv; seq_max_value = maxv; seq_increment = inc; seq_start = start; seq_cache = cache; seq_cycle = cycle; } QString Column::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); if(getParentTable()) attributes[Attributes::Table]=getParentTable()->getName(true); attributes[Attributes::Type]=type.getCodeDefinition(def_type); attributes[Attributes::DefaultValue]=QString(); attributes[Attributes::IdentityType]=QString(); if(identity_type != BaseType::Null) { attributes[Attributes::IdentityType] = ~identity_type; attributes[Attributes::Increment]=seq_increment; attributes[Attributes::MinValue]=seq_min_value; attributes[Attributes::MaxValue]=seq_max_value; attributes[Attributes::Start]=seq_start; attributes[Attributes::Cache]=seq_cache; attributes[Attributes::Cycle]=(seq_cycle ? Attributes::True : QString()); } else { if(!sequence) attributes[Attributes::DefaultValue]=default_value; else { //Configuring the default value of the column to get the next value of the sequence if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::DefaultValue]=QString("nextval('%1'::regclass)").arg(sequence->getSignature()); attributes[Attributes::Sequence]=sequence->getName(true); } } attributes[Attributes::NotNull]=(!not_null ? QString() : Attributes::True); attributes[Attributes::DeclInTable]=(isDeclaredInTable() ? Attributes::True : QString()); return(BaseObject::__getCodeDefinition(def_type)); } QString Column::getAlterDefinition(BaseObject *object) { Column *col=dynamic_cast(object); if(!col) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { attribs_map attribs; QString def_val, alter_def; bool ident_seq_changed = false; BaseObject::setBasicAttributes(true); if(getParentTable()) attribs[Attributes::Table]=getParentTable()->getName(true); if(!this->type.isEquivalentTo(col->type) || (this->type.isEquivalentTo(col->type) && ((this->type.hasVariableLength() && (this->type.getLength()!=col->type.getLength())) || (this->type.acceptsPrecision() && (this->type.getPrecision()!=col->type.getPrecision()))))) attribs[Attributes::Type]=col->type.getCodeDefinition(SchemaParser::SqlDefinition); if(col->sequence) def_val=QString("nextval('%1'::regclass)").arg(col->sequence->getSignature()); else def_val=col->default_value; if(this->default_value!=def_val) attribs[Attributes::DefaultValue]=(def_val.isEmpty() ? Attributes::Unset : def_val); if(this->not_null!=col->not_null) attribs[Attributes::NotNull]=(!col->not_null ? Attributes::Unset : Attributes::True); attribs[Attributes::NewIdentityType] = QString(); if(this->identity_type == BaseType::Null && col->identity_type != BaseType::Null) attribs[Attributes::IdentityType] = ~col->identity_type; else if(this->identity_type != BaseType::Null && col->identity_type == BaseType::Null) attribs[Attributes::IdentityType] = Attributes::Unset; else if(this->identity_type != BaseType::Null && col->identity_type != BaseType::Null && this->identity_type != col->identity_type) attribs[Attributes::NewIdentityType] = ~col->identity_type; attribs[Attributes::CurIdentityType] = QString(); attribs[Attributes::MinValue] = QString(); attribs[Attributes::MaxValue] = QString(); attribs[Attributes::Start] = QString(); attribs[Attributes::Increment] = QString(); attribs[Attributes::Cache] = QString(); attribs[Attributes::Cycle] = QString(); //Checking differences in the underlying sequence (identity col) if(attribs[Attributes::IdentityType] != Attributes::Unset) { if(!col->seq_min_value.isEmpty() && this->seq_min_value != col->seq_min_value) { attribs[Attributes::MinValue] = col->seq_min_value; ident_seq_changed = true; } if(!col->seq_max_value.isEmpty() && this->seq_max_value != col->seq_max_value) { attribs[Attributes::MaxValue] = col->seq_max_value; ident_seq_changed = true; } if(!col->seq_start.isEmpty() && this->seq_start != col->seq_start) { attribs[Attributes::Start] = col->seq_start; ident_seq_changed = true; } if(!col->seq_increment.isEmpty() && this->seq_increment != col->seq_increment) { attribs[Attributes::Increment] = col->seq_increment; ident_seq_changed = true; } if(!col->seq_cache.isEmpty() && this->seq_cache != col->seq_cache) { attribs[Attributes::Cache] = col->seq_cache; ident_seq_changed = true; } if(this->seq_cycle != col->seq_cycle) { attribs[Attributes::Cycle] = (col->seq_cycle ? Attributes::True : Attributes::False); ident_seq_changed = true; } if(ident_seq_changed) attribs[Attributes::CurIdentityType] = ~this->identity_type; } copyAttributes(attribs); alter_def = BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true); alter_def += getAlterCommentDefinition(object, attributes); return(alter_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Column::configureSearchAttributes(void) { BaseObject::configureSearchAttributes(); search_attribs[Attributes::Type] = *type; } void Column::operator = (Column &col) { this->comment=col.comment; this->is_protected=col.is_protected; this->obj_name=col.obj_name; this->alias=col.alias; this->old_name=col.old_name; this->type=col.type; this->default_value=col.default_value; this->not_null=col.not_null; this->parent_rel=col.parent_rel; this->sequence=col.sequence; this->identity_type=col.identity_type; this->seq_cache = col.seq_cache; this->seq_cycle = col.seq_cycle; this->seq_increment = col.seq_increment; this->seq_max_value = col.seq_max_value; this->seq_min_value = col.seq_min_value; this->seq_start = col.seq_start; this->setParentTable(col.getParentTable()); this->setAddedByCopy(false); this->setAddedByGeneralization(false); this->setAddedByLinking(false); this->setCodeInvalidated(true); } pgmodeler-0.9.2/libpgmodeler/src/column.h000066400000000000000000000121571360462764600204260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Column \brief Implements basic operations to manipulate table columns. \note Creation date: 12/09/2006 */ #ifndef COLUMN_H #define COLUMN_H #include "tableobject.h" class Column: public TableObject{ protected: /*! \brief Stores the previous name of the column before its name has changed. This attribute assists in the process of reference columns added by relationships. */ QString old_name; //! \brief Indicate that the column accpets null values or not bool not_null; //! \brief Data type of the column PgSqlType type; /*! \brief Default value of the column. Note: The user must format the default value in accordance with the requirements for each data type. E.g.: for a varchar(10) default value should be 'abcdef' (including apostrophe) for a date the defaul value should be '2006-09-12 ' and so on. */ QString default_value; //! \brief Stores a reference to the relationship that generates the column BaseObject *parent_rel; /*! \brief Stores a reference to the sequence used to generate the default value. This attribute is used only the data type is integer, smallint or bigint */ BaseObject *sequence; //! \brief Identity type of the column (GENERATED BY DEFAULT | ALWAYS) IdentityType identity_type; /*! \brief Indicates that the underlying sequence is cyclic (the counter resets when maximum value is reached) (only for identity column) */ bool seq_cycle; //! \brief Underlying sequence's minimum value (only for identity column) QString seq_min_value, //! \brief Underlying sequence's maximum value (only for identity column) seq_max_value, //! \brief Underlying sequence's current sequence value (only for identity column) seq_start, //! \brief Underlying sequence's value increment (only for identity column) seq_increment, //! \brief Underlying sequence's cache value (only for identity column) seq_cache; virtual void configureSearchAttributes(void); public: Column(void); //! \brief Defines if the column accepts null values or not void setNotNull(bool value); //! \brief Defines the column data type void setType(PgSqlType type); //! \brief Defines the identity mode of the column void setIdentityType(IdentityType id_type); /*! \brief Sets the default value of the column. Must be informed together with the value the particularities of each type, such as quotation marks, hyphens, etc. */ void setDefaultValue(const QString &value); /*! \brief Defines the column name. This method keeps the last column name stored to assist the objects like constraints / indixes and sequences that is referencing the column by its old name. */ void setName(const QString &name); //! \brief Returns the not null state of the column bool isNotNull(void); //! \brief Returns wheter the column is identity or not (GENERATED BY DEFAULT | ALWAYS) bool isIdentity(void); //! \brief Returns the data type of the column PgSqlType getType(void); //! \brief Returns the identity mode of the column IdentityType getIdentityType(void); //! \brief Returns the default value of the column QString getDefaultValue(void); //! \brief Returns the SQL/XML code definition for the column virtual QString getCodeDefinition(unsigned def_type); virtual QString getAlterDefinition(BaseObject *object); /*! \brief Returns the old column name. The parameter 'format' indicates whether the name must be formatted or not */ QString getOldName(bool format=false); //! \brief Returns the reference to the column type in the form [schema].table.column_name%TYPE QString getTypeReference(void); void setParentRelationship(BaseObject *parent_rel); BaseObject *getParentRelationship(void); //! \brief Set the sequence that will generate the default value for the column void setSequence(BaseObject *seq); //! \brief Returns the sequence generator of default value BaseObject *getSequence(void); //! \brief Sets at once all the necessary fields to define the underlying sequence's attributes void setIdSeqAttributes(QString minv, QString maxv, QString inc, QString start, QString cache, bool cycle); bool isIdSeqCycle(void); QString getIdSeqMaxValue(void); QString getIdSeqMinValue(void); QString getIdSeqIncrement(void); QString getIdSeqStart(void); QString getIdSeqCache(void); //! \brief Copies on column to other void operator = (Column &col); }; #endif pgmodeler-0.9.2/libpgmodeler/src/constraint.cpp000066400000000000000000000457371360462764600216620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "constraint.h" Constraint::Constraint(void) { ref_table=nullptr; obj_type=ObjectType::Constraint; deferrable=false; no_inherit=false; fill_factor=0; index_type=BaseType::Null; attributes[Attributes::PkConstr]=QString(); attributes[Attributes::FkConstr]=QString(); attributes[Attributes::CkConstr]=QString(); attributes[Attributes::UqConstr]=QString(); attributes[Attributes::ExConstr]=QString(); attributes[Attributes::RefTable]=QString(); attributes[Attributes::SrcColumns]=QString(); attributes[Attributes::DstColumns]=QString(); attributes[Attributes::DelAction]=QString(); attributes[Attributes::UpdAction]=QString(); attributes[Attributes::Expression]=QString(); attributes[Attributes::Type]=QString(); attributes[Attributes::ComparisonType]=QString(); attributes[Attributes::DeferType]=QString(); attributes[Attributes::IndexType]=QString(); attributes[Attributes::Deferrable]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::DeclInTable]=QString(); attributes[Attributes::Factor]=QString(); attributes[Attributes::NoInherit]=QString(); attributes[Attributes::Elements]=QString(); } Constraint::~Constraint(void) { columns.clear(); ref_columns.clear(); } void Constraint::setConstraintType(ConstraintType constr_type) { this->constr_type=constr_type; } void Constraint::setActionType(ActionType action_type, unsigned act_id) { if(act_id==DeleteAction) { setCodeInvalidated(this->del_action != action_type); this->del_action=action_type; } else { setCodeInvalidated(this->upd_action != action_type); this->upd_action=action_type; } } void Constraint::setExpression(const QString &expr) { setCodeInvalidated(expression != expr); expression=expr; } bool Constraint::isColumnExists(Column *column, unsigned col_type) { vector::iterator itr, itr_end; bool found=false; //Raises an error if the column is not allocated if(!column) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Gets the iterators from the specified internal list if(col_type==SourceCols) { itr=columns.begin(); itr_end=columns.end(); } else { itr=ref_columns.begin(); itr_end=ref_columns.end(); } //Tries to find the column on the internal list while(itr!=itr_end && !found) { found=((*itr)==column); itr++; } return(found); } bool Constraint::isColumnReferenced(Column *column, bool search_only_ref_cols) { bool found=false; vector::iterator itr, itr_end; if(constr_type == ConstraintType::PrimaryKey || constr_type == ConstraintType::Unique || constr_type == ConstraintType::ForeignKey) { if(!search_only_ref_cols) found=isColumnExists(column, SourceCols); if(!found && constr_type==ConstraintType::ForeignKey) found=isColumnExists(column, ReferencedCols); } else if(constr_type==ConstraintType::Exclude) { //Iterates over the exclude elements itr=excl_elements.begin(); itr_end=excl_elements.end(); while(itr!=itr_end && !found) { found=((*itr).getColumn() == column); itr++; } } return(found); } void Constraint::addColumn(Column *column, unsigned col_type) { //Raises an error if the column is not allocated if(!column) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedColumn) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Constraint)), ErrorCode::AsgNotAllocatedColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(constr_type!=ConstraintType::Check) { //Adds the column only if the column doesn't exists on the internal list if(!isColumnExists(column,col_type)) { if(col_type==ReferencedCols) ref_columns.push_back(column); else { columns.push_back(column); setColumnsNotNull(true); } setCodeInvalidated(true); } } } void Constraint::setTablespace(BaseObject *tabspc) { try { if(tabspc && constr_type!=ConstraintType::PrimaryKey && constr_type!=ConstraintType::Unique) throw Exception(ErrorCode::AsgTablespaceInvalidConstraintType,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObject::setTablespace(tabspc); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Constraint::setColumnsAttribute(unsigned col_type, unsigned def_type, bool inc_addedbyrel) { vector *col_vector=nullptr; Column *col=nullptr; QString str_cols, attrib; unsigned i, count; bool format=(def_type==SchemaParser::SqlDefinition); if(col_type==ReferencedCols) { col_vector=&ref_columns; attrib=Attributes::DstColumns; } else { col_vector=&columns; attrib=Attributes::SrcColumns; } count=col_vector->size(); for(i=0; i < count; i++) { col=col_vector->at(i); /* For XML definition the columns added to the constraint through relationship can not be included because they are inserted to the restriction on the time of creation of the relationship from its XML so the parameter 'inc_addedbyrel' can be used to solve this case. */ if((def_type==SchemaParser::SqlDefinition) || ((def_type==SchemaParser::XmlDefinition) && ((inc_addedbyrel && col->isAddedByRelationship()) || (inc_addedbyrel && !col->isAddedByRelationship()) || (!inc_addedbyrel && !col->isAddedByRelationship())))) { str_cols+=col->getName(format); str_cols+=','; } } str_cols.remove(str_cols.size()-1,1); attributes[attrib]=str_cols; } void Constraint::setReferencedTable(BaseTable *tab_ref) { this->ref_table=tab_ref; } void Constraint::setDeferralType(DeferralType deferral_type) { this->deferral_type=deferral_type; } void Constraint::setDeferrable(bool value) { deferrable=value; } void Constraint::setMatchType(MatchType match_type) { this->match_type=match_type; } void Constraint::setFillFactor(unsigned factor) { if(factor!=0 && factor < 10) factor=10; else if(factor > 100) factor=100; fill_factor=factor; } void Constraint::setNoInherit(bool value) { no_inherit=value; } unsigned Constraint::getFillFactor(void) { return(fill_factor); } ConstraintType Constraint::getConstraintType(void) { return(constr_type); } ActionType Constraint::getActionType(unsigned act_id) { if(act_id==DeleteAction) return(del_action); else return(upd_action); } vector Constraint::getColumns(unsigned col_type) { return(col_type==SourceCols ? columns : ref_columns); } QString Constraint::getExpression(void) { return(expression); } Column *Constraint::getColumn(unsigned col_idx, unsigned col_type) { vector *col_list=nullptr; col_list=(col_type==SourceCols ? &columns : &ref_columns); //Raises an error if the column index is invalid (out of bound) if(col_idx>=col_list->size()) throw Exception(ErrorCode::RefColumnInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(col_list->at(col_idx)); } Column *Constraint::getColumn(const QString &name, unsigned col_type) { bool found=false; vector *col_list=nullptr; vector::iterator itr_col, itr_end_col; col_list=(col_type==SourceCols? &columns : &ref_columns); itr_col=col_list->begin(); itr_end_col=col_list->end(); while(itr_col!=itr_end_col) { found=((*itr_col)->getName()==name); if(!found) itr_col++; else break; } if(found) return(*itr_col); else return(nullptr); } BaseTable *Constraint::getReferencedTable(void) { return(ref_table); } unsigned Constraint::getColumnCount(unsigned col_type) { if(col_type==ReferencedCols) return(ref_columns.size()); else return(columns.size()); } void Constraint::removeColumns(void) { setColumnsNotNull(false); columns.clear(); ref_columns.clear(); setCodeInvalidated(true); } void Constraint::removeColumn(const QString &name, unsigned col_type) { vector::iterator itr, itr_end; vector *cols=nullptr; Column *col=nullptr; //Gets the column list using the specified internal list type if(col_type==ReferencedCols) cols=&ref_columns; else cols=&columns; itr=cols->begin(); itr_end=cols->end(); while(itr!=itr_end) { col=(*itr); //Case the column is found if(col->getName()==name) { if(constr_type==ConstraintType::PrimaryKey) col->setNotNull(false); //Remove its iterator from the list cols->erase(itr); setCodeInvalidated(true); break; } else itr++; } } DeferralType Constraint::getDeferralType(void) { return(deferral_type); } bool Constraint::isDeferrable(void) { return(deferrable); } bool Constraint::isNoInherit(void) { return(no_inherit); } bool Constraint::isReferRelationshipAddedColumn(void) { vector::iterator itr, itr_end; vector::iterator itr1, itr1_end; Column *col=nullptr; bool found=false; //First iterates over the source columns list itr=columns.begin(); itr_end=columns.end(); while(itr!=itr_end && !found) { col=(*itr); //Check if the current column were added by relationship found=col->isAddedByRelationship(); itr++; /* Case the source column list is completely iterated steps to the referenced columns list iteration */ if(itr==itr_end && itr_end!=ref_columns.end() && !found) { itr=ref_columns.begin(); itr_end=ref_columns.end(); } } //Iterates over the exclude elements itr1=excl_elements.begin(); itr1_end=excl_elements.end(); while(itr1!=itr1_end && !found) { col=(*itr1).getColumn(); found=(col && col->isAddedByRelationship()); itr1++; } return(found); } vector Constraint::getRelationshipAddedColumns(void) { Column *column=nullptr; vector cols; vector *> lists = { &columns, &ref_columns }; for(auto &p_lst : lists) { for(auto &col : (*p_lst)) { if(col->isAddedByRelationship()) cols.push_back(col); } } for(auto &excl_elem : excl_elements) { column=excl_elem.getColumn(); if(column && column->isAddedByRelationship()) cols.push_back(column); } return(cols); } MatchType Constraint::getMatchType(void) { return(match_type); } int Constraint::getExcludeElementIndex(ExcludeElement elem) { int idx=0; bool found=false; while(idx < static_cast(excl_elements.size()) && !found) { found=(excl_elements[idx]==elem); if(!found) idx++; } return(found ? idx : -1); } vector Constraint::getExcludeElements(void) { return(excl_elements); } void Constraint::addExcludeElements(vector &elems) { vector elems_bkp=excl_elements; try { excl_elements.clear(); for(unsigned i=0; i < elems.size(); i++) addExcludeElement(elems[i]); } catch(Exception &e) { excl_elements = elems_bkp; throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Constraint::addExcludeElement(ExcludeElement elem) { if(getExcludeElementIndex(elem) >= 0) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(elem.getExpression().isEmpty() && !elem.getColumn()) throw Exception(ErrorCode::AsgInvalidExpressionObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); excl_elements.push_back(elem); setCodeInvalidated(true); } void Constraint::addExcludeElement(const QString &expr, Operator *oper, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first) { try { ExcludeElement elem; //Raises an error if the expression is empty if(expr.isEmpty()) throw Exception(ErrorCode::AsgInvalidExpressionObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Configures the element elem.setExpression(expr); elem.setOperatorClass(op_class); elem.setOperator(oper); elem.setSortingEnabled(use_sorting); elem.setSortingAttribute(ExcludeElement::NullsFirst, nulls_first); elem.setSortingAttribute(ExcludeElement::AscOrder, asc_order); if(getExcludeElementIndex(elem) >= 0) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); excl_elements.push_back(elem); setCodeInvalidated(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Constraint::addExcludeElement(Column *column, Operator *oper, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first) { try { ExcludeElement elem; //Case the column is not allocated raises an error if(!column) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedColumn) .arg(this->getName()) .arg(this->getTypeName()), ErrorCode::AsgNotAllocatedColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Configures the element elem.setColumn(column); elem.setOperatorClass(op_class); elem.setOperator(oper); elem.setSortingEnabled(use_sorting); elem.setSortingAttribute(ExcludeElement::NullsFirst, nulls_first); elem.setSortingAttribute(ExcludeElement::AscOrder, asc_order); if(getExcludeElementIndex(elem) >= 0) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); excl_elements.push_back(elem); setCodeInvalidated(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Constraint::removeExcludeElement(unsigned elem_idx) { if(elem_idx >= excl_elements.size()) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); excl_elements.erase(excl_elements.begin() + elem_idx); setCodeInvalidated(true); } void Constraint::removeExcludeElements(void) { excl_elements.clear(); setCodeInvalidated(true); } void Constraint::setColumnsNotNull(bool value) { if(constr_type==ConstraintType::PrimaryKey) { for(auto &col : columns) { //if(!col->isAddedByRelationship()) col->setNotNull(value); } } } ExcludeElement Constraint::getExcludeElement(unsigned elem_idx) { if(elem_idx >= excl_elements.size()) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(excl_elements[elem_idx]); } unsigned Constraint::getExcludeElementCount(void) { return(excl_elements.size()); } void Constraint::setExcludeElementsAttribute(unsigned def_type) { QString str_elem; unsigned i, count; count=excl_elements.size(); for(i=0; i < count; i++) { str_elem+=excl_elements[i].getCodeDefinition(def_type); if(i < (count-1) && def_type==SchemaParser::SqlDefinition) str_elem+=','; } attributes[Attributes::Elements]=str_elem; } void Constraint::setIndexType(IndexingType index_type) { this->index_type=index_type; } IndexingType Constraint::getIndexType(void) { return(index_type); } QString Constraint::getCodeDefinition(unsigned def_type) { return(getCodeDefinition(def_type, false)); } void Constraint::setDeclInTableAttribute(void) { if(!isDeclaredInTable() || (constr_type==ConstraintType::ForeignKey && !isAddedByLinking())) attributes[Attributes::DeclInTable]=QString(); else if(!isReferRelationshipAddedColumn() || constr_type==ConstraintType::PrimaryKey) attributes[Attributes::DeclInTable]=Attributes::True; } QString Constraint::getCodeDefinition(unsigned def_type, bool inc_addedbyrel) { QString code_def=getCachedCode(def_type, false); if(!inc_addedbyrel && !code_def.isEmpty()) return(code_def); QString attrib; attributes[Attributes::PkConstr]=QString(); attributes[Attributes::FkConstr]=QString(); attributes[Attributes::CkConstr]=QString(); attributes[Attributes::UqConstr]=QString(); attributes[Attributes::ExConstr]=QString(); switch(!constr_type) { case ConstraintType::Check: attrib=Attributes::CkConstr; break; case ConstraintType::PrimaryKey: attrib=Attributes::PkConstr; break; case ConstraintType::ForeignKey: attrib=Attributes::FkConstr; break; case ConstraintType::Unique: attrib=Attributes::UqConstr; break; default: attrib=Attributes::ExConstr; break; } attributes[attrib]=Attributes::True; attributes[Attributes::Type]=attrib; attributes[Attributes::UpdAction]=(~upd_action); attributes[Attributes::DelAction]=(~del_action); attributes[Attributes::Expression]=expression; if(constr_type!=ConstraintType::Check) { if(constr_type!=ConstraintType::Exclude) setColumnsAttribute(SourceCols, def_type, inc_addedbyrel); else setExcludeElementsAttribute(def_type); /* Only generates the definition of the foreign key referenced columns if the number of columns of the source and referenced cols list are equal, this means the constraint is configured correctly, otherwise don't generates the attribute forcing the schema parser to return an error because the foreign key is misconfigured. */ if(constr_type==ConstraintType::ForeignKey && columns.size() == ref_columns.size()) setColumnsAttribute(ReferencedCols, def_type, inc_addedbyrel); } attributes[Attributes::RefTable]=(ref_table ? ref_table->getName(true) : QString()); attributes[Attributes::Deferrable]=(deferrable ? Attributes::True : QString()); attributes[Attributes::NoInherit]=(no_inherit ? Attributes::True : QString()); attributes[Attributes::ComparisonType]=(~match_type); attributes[Attributes::DeferType]=(~deferral_type); attributes[Attributes::IndexType]=(~ index_type); if(getParentTable()) attributes[Attributes::Table]=getParentTable()->getName(true); setDeclInTableAttribute(); if(fill_factor!=0 && (constr_type==ConstraintType::PrimaryKey || constr_type==ConstraintType::Unique)) attributes[Attributes::Factor]=QString("%1").arg(fill_factor); else attributes[Attributes::Factor]=QString(); return(BaseObject::__getCodeDefinition(def_type)); } QString Constraint::getDropDefinition(bool cascade) { setDeclInTableAttribute(); return(TableObject::getDropDefinition(cascade)); } QString Constraint::getSignature(bool format) { if(!getParentTable()) return(BaseObject::getSignature(format)); return(QString("%1 ON %2 ").arg(this->getName(format)).arg(getParentTable()->getSignature(true))); } bool Constraint::isCodeDiffersFrom(BaseObject *object, const vector &ignored_attribs, const vector &ignored_tags) { if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(object->getObjectType()!=this->getObjectType()) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { return(BaseObject::isCodeDiffersFrom(this->getCodeDefinition(SchemaParser::XmlDefinition, true), object->getCodeDefinition(SchemaParser::XmlDefinition, true), ignored_attribs, ignored_tags)); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler/src/constraint.h000066400000000000000000000254011360462764600213110ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Constraint \brief Implements the operations to manipulate table constraints (primary keys, foreign key, unique and check). \note Creation date: 17/09/2006 */ #ifndef CONSTRAINT_H #define CONSTRAINT_H #include "tableobject.h" #include "tablespace.h" #include "column.h" #include "excludeelement.h" class Constraint: public TableObject{ private: //! \brief Type of the constraint (primary key, foreign key, unique or check) ConstraintType constr_type; //! \brief Indicates if the constraint is deferrable (except for check contraints) bool deferrable, //! \brief Indicates if the constraint will be copied or not to the child tables of the contraint's table (only for check constraint) no_inherit; //! \brief Deferral type for the constraint (except for check contraints) DeferralType deferral_type; //! \brief Matching method used by the constraint (only for foreign key) MatchType match_type; //! \brief Indexing type used by the constraint (only for exclude constraints) IndexingType index_type; /*! \brief This factor is used to indicate the space usage for the index generated by the constraint. Generally there is no need do fill this attribute but for more refined tuning this can be set. This is applicable only on primary keys and unique. */ unsigned fill_factor; /*! \brief Actions taken when delete and update event occurs. This is applicable only for foreign keys */ ActionType del_action, upd_action; //! \brief Stores the columns that is referenced by the constraint (except for check constraints) vector columns; //! \brief Stores the referenced columns from the referenced table primary key vector ref_columns; //! \brief Stores the exclude elements of the exclude constraint vector excl_elements; //! \brief Stores the check expression or the exclude predicate (only for check and exclude constraints) QString expression; //! \brief Stores the referenced table (only for foreign keys) BaseTable *ref_table; //! \brief Formats the string for constraint columns to be used by the SchemaParser void setColumnsAttribute(unsigned col_type, unsigned def_type, bool inc_addedbyrel=false); //! \brief Formats the exclude elements string used by the SchemaParser void setExcludeElementsAttribute(unsigned def_type); void setDeclInTableAttribute(void); public: /*! \brief Access the source columns that means the columns that constrais is applied (from the constraint's parent table) */ static constexpr unsigned SourceCols=0, /*! \brief Access the referenced columns that means the columns from the referenced table primary key (only for foreign keys) */ ReferencedCols=1; static constexpr unsigned DeleteAction=0, UpdateAction=1; Constraint(void); ~Constraint(void); /*! \brief Adds one column to the internal column list referenced by the constants SOURCE_COLS or REFERENCED_COLS */ void addColumn(Column *column, unsigned col_type); //! \brief Adds several elements to the constraint using a defined vector void addExcludeElements(vector &elems); //! \brief Defines the constraint type void setConstraintType(ConstraintType constr_type); //! \brief Defines the type of action on foreign keys (ON DELETE and ON UPDATE). (only for foreign key) void setActionType(ActionType action_type, unsigned act_id); //! \brief Defines the deferral type for the constraint (except for check contraints) void setDeferralType(DeferralType deferral_type); //! \brief Defines whether the constraint is deferrable (except for check contraints) void setDeferrable(bool value); //! \brief Defines the matching type used by the constraint (only for foreign key) void setMatchType(MatchType constr_type); //! \brief Defines the indexing type used by the constraint (only for exclude) void setIndexType(IndexingType index_type); //! \brief Defines the expresion used by the constraint (only for check and exclude constraint) void setExpression(const QString &expr); //! \brief Defines the referenced table (only for foreign key) void setReferencedTable(BaseTable *tab_ref); //! \brief Defines the tablespace used by the constraint (only for primary keys and unique) void setTablespace(BaseObject *tabspc); /*! \brief Defines the constraint fill factor (only for primary keys and unique). Values less than 10 (except 0) or above 100 will be adjusted to accepted values. To use the default settings specify 0 as fill factor */ void setFillFactor(unsigned factor); //! \brief Defines if the constraints is propagated to child tables (only for exclude constraints) void setNoInherit(bool value); //! \brief Returns the constraint fill factor unsigned getFillFactor(void); //! \brief Retuns the action type (ON DELETE or ON UPDATE) of a foreign key ActionType getActionType(unsigned act_id); //! \brief Returns the list of columns of the specified type SOURCE_COLS or REFERENCED_COLS vector getColumns(unsigned col_type); /*! \brief Returns one column (using its index) from the internal constraint column lists. Use the constants SOURCE_COLS or REFERENCED_COLS to access the lists */ Column *getColumn(unsigned col_idx, unsigned col_type); /*! \brief Returns one column (using its name) from the internal constraint column lists. Use the constants SOURCE_COLS or REFERENCED_COLS to access the lists */ Column *getColumn(const QString &name, unsigned col_type); /*! \brief Returns the column count for one internal list. Use the constants SOURCE_COLS or REFERENCED_COLS to access the lists */ unsigned getColumnCount(unsigned col_type); //! \brief Returns the exclude constraint element count unsigned getExcludeElementCount(void); //! \brief Returns a list of exclude elements vector getExcludeElements(void); /*! \brief Removes one column from internal list using its name. Use the constants SOURCE_COLS or REFERENCED_COLS to access the lists */ void removeColumn(const QString &name, unsigned col_type); //! \brief Remove all columns from the internal lists void removeColumns(void); //! \brief Returns the constraint type ConstraintType getConstraintType(void); //! \brief Returns the check expression QString getExpression(void); //! \brief Returns the referenced table BaseTable *getReferencedTable(void); //! \brief Returns the constraint's deferral type DeferralType getDeferralType(void); //! \brief Indicates whether the constraint is deferrable bool isDeferrable(void); //! \brief Returns if the constraints will propagated to child tables bool isNoInherit(void); /*! \brief Returns whether the constraint references columns added by relationship. This method is used as auxiliary to control which constraints reference columns added by the relationship in order to avoid referece breaking due constants connections and disconnections of relationships */ bool isReferRelationshipAddedColumn(void); /*! \brief Returns the list of all columns that is created by relationships. This method is slower than isReferRelationshipAddedColumn() so it's not recommended to use it only check if the object is referencing columns added by relationship */ vector getRelationshipAddedColumns(void); //! \brief Returns the matching type adopted by the constraint MatchType getMatchType(void); //! \brief Returns the indexing type adopted by the constraint IndexingType getIndexType(void); /*! \brief Returns the SQL / XML definition for the constraint. This method calls getCodeDefintion(unsigned, bool) with the second parameter as false */ virtual QString getCodeDefinition(unsigned def_type) final; /*! \brief Returns the SQL / XML definition for the constraint. The boolean parameter indicates whether the columns added by relationship must appear on the code definition */ virtual QString getCodeDefinition(unsigned def_type, bool inc_addedbyrel) final; virtual QString getDropDefinition(bool cascade) final; //! \brief Indicates whether the column exists on the specified internal column list bool isColumnExists(Column *column, unsigned col_type); /*! \brief Indicates whether the column is referenced in internal column list or exclude element list. The second parameter is useful to permit or not the search of column only on referenced columns list. */ bool isColumnReferenced(Column *column, bool search_only_ref_cols = false); //! \brief Adds an exclude element to the constraint using an column (only exclude constraint) void addExcludeElement(Column *column, Operator *oper, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first); //! \brief Adds an exclude element to the constraint using an expression (only exclude constraint) void addExcludeElement(const QString &expr, Operator *oper, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first); //! \brief Adds an exclude element to the constraint using other pre-configured element (only exclude constraint) void addExcludeElement(ExcludeElement elem); //! \brief Returns one exclude element using its index ExcludeElement getExcludeElement(unsigned elem_idx); //! \brief Returns the exclude element index int getExcludeElementIndex(ExcludeElement elem); //! \brief Remove an exclude element using its index void removeExcludeElement(unsigned idx_elem); //! \brief Remove all exclude elements from the constraint void removeExcludeElements(void); //! \brief Toggles the not-null flag from source columns on primary key constraints. This methods has no effect in other constraint types void setColumnsNotNull(bool value); virtual QString getSignature(bool format) final; /*! \brief Compares two constratins XML definition and returns if they differs. This methods varies a little from BaseObject::isCodeDiffersFrom() because here we need to generate xml code including relationship added columns */ virtual bool isCodeDiffersFrom(BaseObject *object, const vector &ignored_attribs={}, const vector &ignored_tags={}); }; #endif pgmodeler-0.9.2/libpgmodeler/src/conversion.cpp000066400000000000000000000115061360462764600216460ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "conversion.h" Conversion::Conversion(void) { obj_type=ObjectType::Conversion; conversion_func=nullptr; is_default=false; attributes[Attributes::Default]=QString(); attributes[Attributes::SrcEncoding]=QString(); attributes[Attributes::DstEncoding]=QString(); attributes[Attributes::Function]=QString(); } void Conversion::setEncoding(unsigned encoding_idx, EncodingType encoding_type) { //Checks if the encoding index is valid if(encoding_idx<=DstEncoding) { //If the passed enconding type is null an error is raised if((~encoding_type).isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNullTypeObject) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Conversion)), ErrorCode::AsgNullTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Assigns the encoding to the conversion in the specified index this->encodings[encoding_idx]=encoding_type; } else //Raises an error if the encoding index is invalid throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); } void Conversion::setConversionFunction(Function *conv_func) { //Raises an error in case the passed conversion function is null if(!conv_func) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Conversion)), ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* The conversion function must have 5 parameters if it's not the case raises an error. */ else if(conv_func->getParameterCount()!=5) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Conversion)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the function parameters does not following the type order: interger, integer, cstring, internal, integer */ else if(conv_func->getParameter(0).getType()!=QString("integer") || conv_func->getParameter(1).getType()!=QString("integer") || conv_func->getParameter(2).getType()!=QString("cstring") || conv_func->getParameter(3).getType()!=QString("internal") || conv_func->getParameter(4).getType()!=QString("integer")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParameters) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Conversion)), ErrorCode::AsgFunctionInvalidParameters,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the conversion function return type is not 'void' else if(conv_func->getReturnType()!=QString("void")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidReturnType) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Conversion)), ErrorCode::AsgFunctionInvalidReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(conversion_func != conv_func); this->conversion_func=conv_func; } void Conversion::setDefault(bool value) { setCodeInvalidated(is_default != value); is_default=value; } EncodingType Conversion::getEncoding(unsigned encoding_idx) { if(encoding_idx > DstEncoding) throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(this->encodings[encoding_idx]); } Function *Conversion::getConversionFunction(void) { return(conversion_func); } bool Conversion::isDefault(void) { return(is_default); } QString Conversion::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Default]=(is_default ? Attributes::True : QString()); attributes[Attributes::SrcEncoding]=(~encodings[SrcEncoding]); attributes[Attributes::DstEncoding]=(~encodings[DstEncoding]); if(conversion_func) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Function]=conversion_func->getName(true); else attributes[Attributes::Function]=conversion_func->getCodeDefinition(def_type, true); } return(BaseObject::__getCodeDefinition(def_type)); } pgmodeler-0.9.2/libpgmodeler/src/conversion.h000066400000000000000000000046331360462764600213160ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Conversion \brief Implements the operations to manipulate character encoding conversion on the database \note Creation date: 04/06/2008 */ #ifndef CONVERSION_H #define CONVERSION_H #include "baseobject.h" #include "function.h" #include "role.h" class Conversion: public BaseObject { private: /*! \brief Encoding types vector: 0 -> Source encoding 1 -> Destination encoding */ EncodingType encodings[2]; //! \brief Function used to perform the conversion between the encodings Function *conversion_func; //! \brief Indicates whether the conversion is the default for the envolved encodings bool is_default; public: //! \brief Constants used to access the conversion encodings static constexpr unsigned SrcEncoding=0, DstEncoding=1; Conversion(void); //! \brief Defines whether the conversion is the default for the encodings void setDefault(bool value); //! \brief Sets one of the conversion encodings (using the encoding index constants) void setEncoding(unsigned encoding_idx, EncodingType encoding_type); //! \brief Sets the conversion function used to convert character between encodings void setConversionFunction(Function *conv_func); //! \brief Returns the encoding related to the index (using the encoding index constants) EncodingType getEncoding(unsigned encoding_idx); //! \brief Returns the current used conversion function Function *getConversionFunction(void); //! \brief Returns if the conversion is the default for the envolved encodings bool isDefault(void); //! \brief Returns the SQL/XML code definition for the conversion virtual QString getCodeDefinition(unsigned def_type) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/copyoptions.cpp000066400000000000000000000056641360462764600220570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "copyoptions.h" #include "baseobject.h" CopyOptions::CopyOptions(void) { copy_mode = copy_op_ids = 0; } CopyOptions::CopyOptions(unsigned copy_mode, unsigned copy_op_ids) { if((copy_mode!=0 && copy_mode!=Including && copy_mode!=Excluding) || copy_op_ids > All) throw Exception(ErrorCode::RefInvalidLikeOptionType,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->copy_mode = copy_mode; this->copy_op_ids = copy_op_ids; } unsigned CopyOptions::getCopyMode(void) { return(copy_mode); } bool CopyOptions::isOptionSet(unsigned op) { if(op > All) throw Exception(ErrorCode::RefInvalidLikeOptionType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return((copy_op_ids & op) == op); } bool CopyOptions::isIncluding(void) { return(copy_mode & Including); } bool CopyOptions::isExcluding(void) { return(copy_mode & Excluding); } unsigned CopyOptions::getCopyOptionsIds(void) { return(copy_op_ids); } QString CopyOptions::getSQLDefinition(void) { QString def, mode, op_name; unsigned op_id, ids[]={All, Defaults, Constraints, Indexes, Storage, Comments, Identity, Statistics }, cnt = sizeof(ids) / sizeof(unsigned); mode = (copy_mode == Including ? QString(" INCLUDING") : QString(" EXCLUDING")); if(copy_mode!=0 && copy_op_ids!=0) { for(unsigned i=0; i < cnt; i++) { op_id = copy_op_ids & ids[i]; switch(op_id) { case All: op_name=QString(" ALL"); break; case Defaults: op_name=QString(" DEFAULTS"); break; case Constraints: op_name=QString(" CONSTRAINTS"); break; case Indexes: op_name=QString(" INDEXES"); break; case Storage: op_name=QString(" STORAGE"); break; case Comments: op_name=QString(" COMMENTS"); break; case Identity: op_name=(BaseObject::getPgSQLVersion().toFloat() > PgSqlVersions::PgSqlVersion96.toFloat() ? QString(" IDENTITY") : QString()); break; case Statistics: op_name=(BaseObject::getPgSQLVersion().toFloat() > PgSqlVersions::PgSqlVersion96.toFloat() ? QString(" STATISTICS") : QString()); break; } if(!op_name.isEmpty()) { def += mode + op_name; op_name.clear(); } if(op_id==All) break; } } return(def); } bool CopyOptions::operator != (CopyOptions &cp) { return(this->copy_mode!= cp.copy_mode && this->copy_op_ids!=cp.copy_op_ids); } pgmodeler-0.9.2/libpgmodeler/src/copyoptions.h000066400000000000000000000027411360462764600215150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class CopyOptions \brief Auxiliary class that helps to control LIKE (Copy tables) options */ #ifndef COPY_OPTIONS_H #define COPY_OPTIONS_H #include "baseobject.h" #include class CopyOptions { private: unsigned copy_mode, copy_op_ids; public: static constexpr unsigned Defaults=1, Constraints=2, Indexes=4, Storage=8, Comments=16, Identity=32, Statistics=64, All=127, Including=256, Excluding=512; CopyOptions(void); CopyOptions(unsigned copy_mode, unsigned copy_op_ids); unsigned getCopyMode(void); unsigned getCopyOptionsIds(void); bool isOptionSet(unsigned op); bool isIncluding(void); bool isExcluding(void); QString getSQLDefinition(void); bool operator != (CopyOptions &cp); }; #endif pgmodeler-0.9.2/libpgmodeler/src/databasemodel.cpp000066400000000000000000012270141360462764600222520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "databasemodel.h" #include "pgmodelerns.h" #include unsigned DatabaseModel::dbmodel_id=2000; DatabaseModel::DatabaseModel(void) { this->model_wgt=nullptr; object_id=DatabaseModel::dbmodel_id++; obj_type=ObjectType::Database; is_template = false; allow_conns = true; encoding=BaseType::Null; BaseObject::setName(QObject::trUtf8("new_database")); default_objs[ObjectType::Schema]=nullptr; default_objs[ObjectType::Role]=nullptr; default_objs[ObjectType::Tablespace]=nullptr; default_objs[ObjectType::Collation]=nullptr; conn_limit=-1; last_zoom=1; loading_model=invalidated=append_at_eod=prepend_at_bod=false; attributes[Attributes::Encoding]=QString(); attributes[Attributes::TemplateDb]=QString(); attributes[Attributes::ConnLimit]=QString(); attributes[Attributes::LcCollate]=QString(); attributes[Attributes::LcCtype]=QString(); attributes[Attributes::AppendAtEod]=QString(); attributes[Attributes::PrependAtBod]=QString(); attributes[Attributes::AllowConns]=QString(); attributes[Attributes::IsTemplate]=QString(); obj_lists = { { ObjectType::Textbox, &textboxes }, { ObjectType::Table, &tables }, { ObjectType::Function, &functions }, { ObjectType::Aggregate, &aggregates }, { ObjectType::Schema, &schemas }, { ObjectType::View, &views }, { ObjectType::Type, &types }, { ObjectType::Role, &roles }, { ObjectType::Tablespace, &tablespaces }, { ObjectType::Language, &languages }, { ObjectType::Cast, &casts }, { ObjectType::Conversion, &conversions }, { ObjectType::Operator, &operators }, { ObjectType::OpClass, &op_classes }, { ObjectType::OpFamily, &op_families }, { ObjectType::Domain, &domains }, { ObjectType::Sequence, &sequences }, { ObjectType::BaseRelationship, &base_relationships }, { ObjectType::Relationship, &relationships }, { ObjectType::Permission, &permissions }, { ObjectType::Collation, &collations }, { ObjectType::Extension, &extensions }, { ObjectType::Tag, &tags }, { ObjectType::EventTrigger, &eventtriggers }, { ObjectType::GenericSql, &genericsqls }, { ObjectType::ForeignDataWrapper, &fdata_wrappers }, { ObjectType::ForeignServer, &foreign_servers }, { ObjectType::UserMapping, &usermappings }, { ObjectType::ForeignTable, &foreign_tables } }; } DatabaseModel::DatabaseModel(ModelWidget *model_wgt):DatabaseModel() { this->model_wgt=model_wgt; } DatabaseModel::~DatabaseModel(void) { this->blockSignals(true); destroyObjects(); } ModelWidget *DatabaseModel::getModelWidget(void) { return(model_wgt); } void DatabaseModel::setEncoding(EncodingType encod) { encoding=encod; } void DatabaseModel::setLocalization(unsigned localiz_id, const QString &value) { if(localiz_id > Collation::LcCollate) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); localizations[localiz_id]=value; } void DatabaseModel::setConnectionLimit(int conn_lim) { if(conn_lim < -1) conn_lim=-1; this->conn_limit=conn_lim; } void DatabaseModel::setTemplateDB(const QString &temp_db) { if(!temp_db.isEmpty() && !BaseObject::isValidName(temp_db)) throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->template_db=temp_db; } void DatabaseModel::setAuthor(const QString &author) { this->author=author; } vector *DatabaseModel::getObjectList(ObjectType obj_type) { if(obj_lists.count(obj_type) == 0) return(nullptr); return(obj_lists[obj_type]); } void DatabaseModel::addObject(BaseObject *object, int obj_idx) { ObjectType obj_type; if(!object) return; try { obj_type=object->getObjectType(); if(obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship) addRelationship(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Textbox) addTextbox(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Table) addTable(dynamic_cast
(object), obj_idx); else if(obj_type==ObjectType::Function) addFunction(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Aggregate) addAggregate(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Schema) addSchema(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::View) addView(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Type) addType(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Role) addRole(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Tablespace) addTablespace(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Language) addLanguage(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Cast) addCast(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Conversion) addConversion(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Operator) addOperator(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::OpClass) addOperatorClass(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::OpFamily) addOperatorFamily(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Domain) addDomain(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Sequence) addSequence(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Collation) addCollation(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Extension) addExtension(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Tag) addTag(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Permission) addPermission(dynamic_cast(object)); else if(obj_type==ObjectType::EventTrigger) addEventTrigger(dynamic_cast(object)); else if(obj_type==ObjectType::GenericSql) addGenericSQL(dynamic_cast(object)); else if(obj_type==ObjectType::ForeignDataWrapper) addForeignDataWrapper(dynamic_cast(object)); else if(obj_type==ObjectType::ForeignServer) addForeignServer(dynamic_cast(object)); else if(obj_type==ObjectType::UserMapping) addUserMapping(dynamic_cast(object)); else if(obj_type==ObjectType::ForeignTable) addForeignTable(dynamic_cast(object)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeObject(BaseObject *object, int obj_idx) { ObjectType obj_type; if(!object) return; try { obj_type=object->getObjectType(); if(obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship) removeRelationship(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Textbox) removeTextbox(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Table) removeTable(dynamic_cast
(object), obj_idx); else if(obj_type==ObjectType::Function) removeFunction(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Aggregate) removeAggregate(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Schema) removeSchema(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::View) removeView(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Type) removeType(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Role) removeRole(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Tablespace) removeTablespace(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Language) removeLanguage(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Cast) removeCast(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Conversion) removeConversion(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Operator) removeOperator(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::OpClass) removeOperatorClass(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::OpFamily) removeOperatorFamily(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Domain) removeDomain(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Sequence) removeSequence(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Collation) removeCollation(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Extension) removeExtension(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Tag) removeTag(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Permission) removePermission(dynamic_cast(object)); else if(obj_type==ObjectType::EventTrigger) removeEventTrigger(dynamic_cast(object)); else if(obj_type==ObjectType::GenericSql) removeGenericSQL(dynamic_cast(object)); else if(obj_type==ObjectType::ForeignDataWrapper) removeForeignDataWrapper(dynamic_cast(object)); else if(obj_type==ObjectType::ForeignServer) removeForeignServer(dynamic_cast(object)); else if(obj_type==ObjectType::UserMapping) removeUserMapping(dynamic_cast(object)); else if(obj_type==ObjectType::ForeignTable) removeForeignTable(dynamic_cast(object)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeObject(unsigned obj_idx, ObjectType obj_type) { if(TableObject::isTableObject(obj_type) || obj_type==ObjectType::BaseObject || obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Database) throw Exception(ErrorCode::RemObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); vector *obj_list=nullptr; BaseObject *object=nullptr; obj_list=getObjectList(obj_type); if(obj_idx >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); object=(*obj_list)[obj_idx]; if(obj_type==ObjectType::Textbox) removeTextbox(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Table) removeTable(dynamic_cast
(object), obj_idx); else if(obj_type==ObjectType::Function) removeFunction(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Aggregate) removeAggregate(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Schema) removeSchema(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::View) removeView(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Type) removeType(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Role) removeRole(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Tablespace) removeTablespace(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Language) removeLanguage(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Cast) removeCast(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Conversion) removeConversion(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Operator) removeOperator(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::OpClass) removeOperatorClass(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::OpFamily) removeOperatorFamily(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Domain) removeDomain(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Sequence) removeSequence(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Collation) removeCollation(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship) removeRelationship(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::Permission) removePermission(dynamic_cast(object)); else if(obj_type==ObjectType::EventTrigger) removeEventTrigger(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::GenericSql) removeGenericSQL(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::ForeignDataWrapper) removeForeignDataWrapper(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::UserMapping) removeUserMapping(dynamic_cast(object), obj_idx); else if(obj_type==ObjectType::ForeignTable) removeForeignTable(dynamic_cast(object), obj_idx); } void DatabaseModel::__addObject(BaseObject *object, int obj_idx) { int idx; ObjectType obj_type; vector *obj_list=nullptr; vector::iterator itr, itr_end; if(!object) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); obj_type=object->getObjectType(); #ifdef DEMO_VERSION #warning "DEMO VERSION: database model object creation limit." obj_list=getObjectList(obj_type); if(obj_list && obj_list->size() >= GlobalAttributes::MaxObjectCount) throw Exception(trUtf8("The demonstration version can create only `%1' instances of each object type! You've reach this limit for the type: `%2'") .arg(GlobalAttributes::MaxObjectCount) .arg(BaseObject::getTypeName(obj_type)), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); #endif if(obj_type==ObjectType::Tablespace) { Tablespace *tabspc=nullptr, *aux_tabspc=nullptr; obj_list=getObjectList(obj_type); itr=obj_list->begin(); itr_end=obj_list->end(); tabspc=dynamic_cast(object); while(itr!=itr_end) { aux_tabspc=dynamic_cast(*itr); /* Raises an error if the object to be added is a tablespace and there is some other tablespace pointing to the same directory */ if(tabspc->getDirectory()==aux_tabspc->getDirectory()) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgTablespaceDuplicatedDirectory) .arg(tabspc->getName()) .arg(aux_tabspc->getName()), ErrorCode::AsgTablespaceDuplicatedDirectory,__PRETTY_FUNCTION__,__FILE__,__LINE__); } itr++; } } /* Raises an error if there is an object with the same name. Special cases are for: functions/operator that are search by signature and views that are search on tables and views list */ if(((obj_type==ObjectType::View || obj_type==ObjectType::Table || obj_type==ObjectType::ForeignTable) && (getObject(object->getName(true), ObjectType::View, idx) || getObject(object->getName(true), ObjectType::Table, idx) || getObject(object->getName(true), ObjectType::ForeignTable, idx))) || (obj_type==ObjectType::Extension && (getObject(object->getName(false), obj_type, idx))) || (getObject(object->getSignature(), obj_type, idx))) { QString str_aux; str_aux=Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(object->getName(obj_type != ObjectType::Extension)) .arg(object->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()); throw Exception(str_aux,ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } try { if(obj_type==ObjectType::Textbox || obj_type==ObjectType::BaseRelationship) object->getCodeDefinition(SchemaParser::XmlDefinition); else object->getCodeDefinition(SchemaParser::SqlDefinition); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } obj_list=getObjectList(object->getObjectType()); if(obj_idx < 0 || obj_idx >= static_cast(obj_list->size())) obj_list->push_back(object); else { if(obj_idx >=0 && idx < 0) idx=obj_idx; else if(obj_idx < 0 && idx < 0) idx=0; if(obj_list->size() > 0) obj_list->insert((obj_list->begin() + idx), object); else obj_list->push_back(object); } object->setDatabase(this); emit s_objectAdded(object); this->setInvalidated(true); } void DatabaseModel::__removeObject(BaseObject *object, int obj_idx, bool check_refs) { if(!object) throw Exception(ErrorCode::RemNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { vector *obj_list=nullptr; ObjectType obj_type; obj_type=object->getObjectType(); obj_list=getObjectList(obj_type); if(!obj_list) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { vector refs; //Get the table references if(check_refs) getObjectReferences(object, refs, true, true); //If there are objects referencing the table if(!refs.empty()) { ErrorCode err_code; //Raises an error indicating the object that is referencing the table if(!dynamic_cast(refs[0])) { err_code=ErrorCode::RemDirectReference; throw Exception(Exception::getErrorMessage(err_code) .arg(object->getName(true)) .arg(object->getTypeName()) .arg(refs[0]->getName(true)) .arg(refs[0]->getTypeName()), err_code,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { BaseObject *ref_obj_parent=dynamic_cast(refs[0])->getParentTable(); err_code=ErrorCode::RemInderectReference; throw Exception(Exception::getErrorMessage(err_code) .arg(object->getName(true)) .arg(object->getTypeName()) .arg(refs[0]->getName(true)) .arg(refs[0]->getTypeName()) .arg(ref_obj_parent->getName(true)) .arg(ref_obj_parent->getTypeName()), err_code,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } if(obj_idx < 0 || obj_idx >= static_cast(obj_list->size())) getObject(object->getSignature(), obj_type, obj_idx); if(obj_idx >= 0) { if(Permission::acceptsPermission(obj_type)) removePermissions(object); obj_list->erase(obj_list->begin() + obj_idx); } } object->setDatabase(nullptr); emit s_objectRemoved(object); } } vector DatabaseModel::getObjects(ObjectType obj_type, BaseObject *schema) { vector *obj_list=nullptr, sel_list; vector::iterator itr, itr_end; BaseRelationship *rel=nullptr; obj_list=getObjectList(obj_type); if(!obj_list) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end) { rel=dynamic_cast(*itr); if((!rel && (*itr)->getSchema()==schema) || (rel && (rel->getTable(BaseRelationship::SrcTable)->getSchema()==schema || rel->getTable(BaseRelationship::DstTable)->getSchema()==schema))) sel_list.push_back(*itr); itr++; } return(sel_list); } vector DatabaseModel::getObjects(BaseObject *schema) { vector *obj_list=nullptr, sel_list; vector types = BaseObject::getChildObjectTypes(ObjectType::Schema); for(auto &type : types) { obj_list = getObjectList(type); for(auto &obj : *obj_list) { if(obj->getSchema() == schema) sel_list.push_back(obj); } } return(sel_list); } BaseObject *DatabaseModel::getObject(const QString &name, ObjectType obj_type, int &obj_idx) { BaseObject *object=nullptr; vector *obj_list=nullptr; vector::iterator itr, itr_end; bool found=false; QString aux_name1; obj_list=getObjectList(obj_type); if(!obj_list) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { QString signature; itr=obj_list->begin(); itr_end=obj_list->end(); obj_idx=-1; aux_name1=QString(name).remove('"'); while(itr!=itr_end && !found) { signature=(*itr)->getSignature().remove("\""); found=(signature==aux_name1); if(!found) itr++; } if(found) { object=(*itr); obj_idx=(itr - obj_list->begin()); } else obj_idx=-1; } return(object); } BaseObject *DatabaseModel::getObject(const QString &name, const vector &types) { BaseObject *object = nullptr; for(auto &type : types) { object = getObject(name, type); if(object) break; } return(object); } BaseObject *DatabaseModel::getObject(unsigned obj_idx, ObjectType obj_type) { vector *obj_list=nullptr; obj_list=getObjectList(obj_type); if(!obj_list) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(obj_idx >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); else return(obj_list->at(obj_idx)); } unsigned DatabaseModel::getObjectCount(ObjectType obj_type) { vector *obj_list=nullptr; obj_list=getObjectList(obj_type); if(!obj_list) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else return(obj_list->size()); } unsigned DatabaseModel::getMaxObjectCount(void) { vector types = getObjectTypes(false, {ObjectType::Database}); unsigned count = 0, max = 0; for(auto &type : types) { count = getObjectList(type)->size(); if(count > max) max = count; } return(max); } unsigned DatabaseModel::getObjectCount(void) { vector types= getObjectTypes(false, {ObjectType::Database}); unsigned count=0; for(auto &type : types) count+=getObjectList(type)->size(); return(count); } QString DatabaseModel::getLocalization(unsigned localiz_id) { if(localiz_id > Collation::LcCollate) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(localizations[localiz_id]); } int DatabaseModel::getConnectionLimit(void) { return(conn_limit); } QString DatabaseModel::getTemplateDB(void) { return(template_db); } EncodingType DatabaseModel::getEncoding(void) { return(encoding); } BaseObject *DatabaseModel::getDefaultObject(ObjectType obj_type) { if(default_objs.count(obj_type)==0) throw Exception(ErrorCode::RefObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); return(default_objs[obj_type]); } QString DatabaseModel::getAuthor(void) { return(author); } void DatabaseModel::setProtected(bool value) { for(auto &itr : obj_lists) { for(auto &object : *itr.second) { object->setProtected(value); } } BaseObject::setProtected(value); } void DatabaseModel::destroyObjects(void) { ObjectType graph_types[]={ ObjectType::Schema, ObjectType::BaseRelationship, ObjectType::Relationship, ObjectType::Table, ObjectType::ForeignTable, ObjectType::View }; BaseObject *object=nullptr; map objects; map::reverse_iterator ritr, ritr_end; vector rem_obj_types; BaseGraphicObject *graph_obj = nullptr; //Blocking signals of all graphical objects to avoid uneeded updates in the destruction this->blockSignals(true); for(unsigned i=0; i < 5; i++) { for(auto &object : *this->getObjectList(graph_types[i])) { graph_obj = dynamic_cast(object); if(graph_obj) dynamic_cast(object)->blockSignals(true); } } try { //Removing the special objects first storeSpecialObjectsXML(); disconnectRelationships(); } catch(Exception &e) { /* DEBUG: An exception at this point shouldn't never occur but if * it is raised, we spit out the error to the stdout in order to try to * find out the problem! */ qDebug() << "** FAIL TO DESTROY ALL OBJECTS **" << endl; qDebug() << e.getExceptionsText().toStdString().c_str() << endl; } objects = getCreationOrder(SchemaParser::XmlDefinition, true); ritr = objects.rbegin(); ritr_end = objects.rend(); while(ritr != ritr_end) { object = ritr->second; ritr++; // We ignore the database itself, permission objects (destroyed separetely) and table children objects if(object->getObjectType() == ObjectType::Database || object->getObjectType() == ObjectType::Permission || TableObject::isTableObject(object->getObjectType())) continue; // Register the type of the object being removed so the respective list can be cleaned in the end rem_obj_types.push_back(object->getObjectType()); /* If the object is graphical destroy using the __removeObject in order emit the signal to object scene to remove the graphical representation of the to-be-destroyed object */ if(dynamic_cast(object)) { __removeObject(object,-1,false); if(object->getObjectType()==ObjectType::Relationship) dynamic_cast(object)->destroyObjects(); } delete(object); } PgSqlType::removeUserTypes(this); for(auto &perm : permissions) delete(perm); permissions.clear(); //Cleaning out the list of removed objects to avoid segfaults while calling this method again if(!rem_obj_types.empty()) { std::sort(rem_obj_types.begin(), rem_obj_types.end()); vector::iterator end = std::unique(rem_obj_types.begin(), rem_obj_types.end()); rem_obj_types.erase(end, rem_obj_types.end()); for(auto type : rem_obj_types) getObjectList(type)->clear(); } } void DatabaseModel::addTable(Table *table, int obj_idx) { try { __addObject(table, obj_idx); PgSqlType::addUserType(table->getName(true), table, this, UserTypeConfig::TableType); updateTableFKRelationships(table); dynamic_cast(table->getSchema())->setModified(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Table *DatabaseModel::getTable(unsigned obj_idx) { return(dynamic_cast
(getObject(obj_idx, ObjectType::Table))); } Table *DatabaseModel::getTable(const QString &name) { return(dynamic_cast
(getObject(name, ObjectType::Table))); } void DatabaseModel::removeTable(Table *table, int obj_idx) { try { __removeObject(table, obj_idx); PgSqlType::removeUserType(table->getName(true), table); updateTableFKRelationships(table); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addSequence(Sequence *sequence, int obj_idx) { try { __addObject(sequence, obj_idx); PgSqlType::addUserType(sequence->getName(true), sequence, this, UserTypeConfig::SequenceType); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Sequence *DatabaseModel::getSequence(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Sequence))); } Sequence *DatabaseModel::getSequence(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Sequence))); } void DatabaseModel::removeSequence(Sequence *sequence, int obj_idx) { try { removeUserType(sequence, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addCollation(Collation *collation, int obj_idx) { try { __addObject(collation, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Collation *DatabaseModel::getCollation(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Collation))); } Collation *DatabaseModel::getCollation(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Collation))); } void DatabaseModel::removeCollation(Collation *collation, int obj_idx) { try { __removeObject(collation, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::addExtension(Extension *extension, int obj_idx) { try { __addObject(extension, obj_idx); if(extension->handlesType()) PgSqlType::addUserType(extension->getName(true), extension, this, UserTypeConfig::ExtensionType); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Extension *DatabaseModel::getExtension(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Collation))); } Extension *DatabaseModel::getExtension(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Extension))); } void DatabaseModel::addTag(Tag *tag, int obj_idx) { try { __addObject(tag, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeTag(Tag *tag, int obj_idx) { try { __removeObject(tag, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Tag *DatabaseModel::getTag(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Tag))); } Tag *DatabaseModel::getTag(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Tag))); } void DatabaseModel::addEventTrigger(EventTrigger *evnttrig, int obj_idx) { try { __addObject(evnttrig, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeEventTrigger(EventTrigger *evnttrig, int obj_idx) { try { __removeObject(evnttrig, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } EventTrigger *DatabaseModel::getEventTrigger(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::EventTrigger))); } EventTrigger *DatabaseModel::getEventTrigger(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::EventTrigger))); } void DatabaseModel::addGenericSQL(GenericSQL *genericsql, int obj_idx) { try { __addObject(genericsql, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeGenericSQL(GenericSQL *genericsql, int obj_idx) { try { __removeObject(genericsql, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } GenericSQL *DatabaseModel::getGenericSQL(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::GenericSql))); } GenericSQL *DatabaseModel::getGenericSQL(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::GenericSql))); } void DatabaseModel::addForeignDataWrapper(ForeignDataWrapper *fdata_wrapper, int obj_idx) { try { __addObject(fdata_wrapper, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeForeignDataWrapper(ForeignDataWrapper *fdata_wrapper, int obj_idx) { try { __removeObject(fdata_wrapper, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } ForeignDataWrapper *DatabaseModel::getForeignDataWrapper(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::ForeignDataWrapper))); } ForeignDataWrapper *DatabaseModel::getForeignDataWrapper(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::ForeignDataWrapper))); } void DatabaseModel::addForeignServer(ForeignServer *server, int obj_idx) { try { __addObject(server, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeForeignServer(ForeignServer *server, int obj_idx) { try { __removeObject(server, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } ForeignServer *DatabaseModel::getForeignServer(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::ForeignServer))); } ForeignServer *DatabaseModel::getForeignServer(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::ForeignServer))); } void DatabaseModel::addUserMapping(UserMapping *usrmap, int obj_idx) { try { __addObject(usrmap, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeUserMapping(UserMapping *usrmap, int obj_idx) { try { __removeObject(usrmap, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } UserMapping *DatabaseModel::getUserMapping(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::UserMapping))); } UserMapping *DatabaseModel::getUserMapping(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::UserMapping))); } void DatabaseModel::addForeignTable(ForeignTable *table, int obj_idx) { try { __addObject(table, obj_idx); PgSqlType::addUserType(table->getName(true), table, this, UserTypeConfig::ForeignTableType); dynamic_cast(table->getSchema())->setModified(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } ForeignTable *DatabaseModel::getForeignTable(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::ForeignTable))); } ForeignTable *DatabaseModel::getForeignTable(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::ForeignTable))); } void DatabaseModel::removeForeignTable(ForeignTable *table, int obj_idx) { try { __removeObject(table, obj_idx); PgSqlType::removeUserType(table->getName(true), table); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removeExtension(Extension *extension, int obj_idx) { try { if(extension->handlesType()) removeUserType(extension, obj_idx); else __removeObject(extension, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::addView(View *view, int obj_idx) { try { __addObject(view, obj_idx); PgSqlType::addUserType(view->getName(true), view, this, UserTypeConfig::ViewType); updateViewRelationships(view); dynamic_cast(view->getSchema())->setModified(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } View *DatabaseModel::getView(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::View))); } View *DatabaseModel::getView(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::View))); } void DatabaseModel::removeView(View *view, int obj_idx) { try { //The relationships that links tables to the view must be removed before erase the view itself updateViewRelationships(view, true); __removeObject(view, obj_idx); PgSqlType::removeUserType(view->getName(true), view); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::updateTableFKRelationships(Table *table) { if(!table) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(table->getDatabase()==this) { Table *ref_tab=nullptr; BaseRelationship *rel=nullptr; unsigned idx; vector fks; vector::iterator itr1, itr1_end; table->getForeignKeys(fks); /* First remove the invalid relationships (the foreign key that generates the relationship no longer exists) */ itr1=base_relationships.begin(); itr1_end=base_relationships.end(); idx=0; while(itr1!=itr1_end) { rel=dynamic_cast(*itr1); if(rel->getRelationshipType()==BaseRelationship::RelationshipFk && (rel->getTable(BaseRelationship::SrcTable)==table || rel->getTable(BaseRelationship::DstTable)==table)) { Constraint *fk = rel->getReferenceForeignKey(); if(rel->getTable(BaseRelationship::SrcTable)==table) ref_tab=dynamic_cast
(rel->getTable(BaseRelationship::DstTable)); else ref_tab=dynamic_cast
(rel->getTable(BaseRelationship::SrcTable)); /* Removes the relationship if the following cases happen: * 1) The foreign key references a table different from ref_tab, which means, the user * have changed the fk manually by setting a new referenced table but the relationship tied to the fk * does not reflect the new reference. * * 2) The fk references the correct table but the source table does not own the fk anymore, which means, * the fk as removed manually by the user. */ if((table->getObjectIndex(fk) >= 0 && fk->getReferencedTable() != ref_tab) || (table->getObjectIndex(fk) < 0 && fk->getReferencedTable() == ref_tab)) { removeRelationship(rel); itr1=base_relationships.begin() + idx; itr1_end=base_relationships.end(); } else { rel->setModified(!loading_model); itr1++; idx++; } } else { itr1++; idx++; } } //Creating the relationships from the foreign keys for(auto &fk : fks) { ref_tab=dynamic_cast
(fk->getReferencedTable()); //Only creates the relationship if does'nt exist one between the tables rel=getRelationship(table, ref_tab, fk); if(!rel && ref_tab->getDatabase()==this) { rel=new BaseRelationship(BaseRelationship::RelationshipFk, table, ref_tab, false, false); rel->setReferenceForeignKey(fk); rel->setCustomColor(Qt::transparent); /* Workaround: In some cases the combination of the two tablenames can generate a duplicated relationship name so it`s necessary to check if a relationship with the same name already exists. If exists changes the name of the new one */ if(getObjectIndex(rel->getName(), ObjectType::BaseRelationship) >= 0) rel->setName(PgModelerNs::generateUniqueName(rel, base_relationships)); addRelationship(rel); } } } } void DatabaseModel::updateTablesFKRelationships(void) { vector::iterator itr=tables.begin(); while(itr!=tables.end()) { updateTableFKRelationships(dynamic_cast
(*itr)); itr++; } } void DatabaseModel::updateViewRelationships(View *view, bool force_rel_removal) { PhysicalTable *table=nullptr; BaseRelationship *rel=nullptr; Reference ref; unsigned i, ref_count, idx; vector::iterator itr, itr_end; vector tables; if(!view) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(getObjectIndex(view) < 0 || force_rel_removal) { //Remove all the relationship related to the view when this latter no longer exists itr=base_relationships.begin(); itr_end=base_relationships.end(); idx=0; while(itr!=itr_end) { rel=dynamic_cast(*itr); if(rel->getTable(BaseRelationship::SrcTable)==view || rel->getTable(BaseRelationship::DstTable)==view) { removeRelationship(rel); itr=base_relationships.begin() + idx; itr_end=base_relationships.end(); } else { itr++; idx++; } } } else { /* Remove the relationships between tables and the view when this latter doesn't reference the first */ itr=base_relationships.begin(); itr_end=base_relationships.end(); idx=0; while(itr!=itr_end) { rel=dynamic_cast(*itr); if(rel->getTable(BaseRelationship::SrcTable)==view || rel->getTable(BaseRelationship::DstTable)==view) { if(rel->getTable(BaseRelationship::SrcTable)->getObjectType()==ObjectType::Table) table=dynamic_cast(rel->getTable(BaseRelationship::SrcTable)); else table=dynamic_cast(rel->getTable(BaseRelationship::DstTable)); if(!view->isReferencingTable(table)) { removeRelationship(rel); itr=base_relationships.begin() + idx; itr_end=base_relationships.end(); } else { itr++; idx++; } } else { itr++; idx++; } } /* Creates the relationships from the view references * First we try to create relationship from referecences in SELECT portion of view's definition */ ref_count=view->getReferenceCount(Reference::SqlReferSelect); for(i=0; i < ref_count; i++) { table = view->getReference(i, Reference::SqlReferSelect).getTable(); if(table) tables.push_back(table); } /* If the view does have tables referenced from SELECT portion we check if * the table was constructed from a single reference (Reference::SqlViewDefinition). In * that case we use the list of referenced tables configured in that view reference object */ if(tables.empty() && view->getReferenceCount(Reference::SqlViewDefinition) > 0) tables = view->getReference(0, Reference::SqlViewDefinition).getReferencedTables(); // Effectively creating the relationships for(auto &tab : tables) { rel = getRelationship(view, tab); if(!rel) { rel=new BaseRelationship(BaseRelationship::RelationshipDep, view, tab, false, false); rel->setName(PgModelerNs::generateUniqueName(rel, base_relationships)); addRelationship(rel); } } } } void DatabaseModel::disconnectRelationships(void) { try { BaseRelationship *base_rel=nullptr; Relationship *rel=nullptr; vector::reverse_iterator ritr_rel, ritr_rel_end; //The relationships must be disconnected from the last to the first ritr_rel=relationships.rbegin(); ritr_rel_end=relationships.rend(); while(ritr_rel!=ritr_rel_end) { base_rel=dynamic_cast(*ritr_rel); ritr_rel++; base_rel->blockSignals(loading_model); if(base_rel->getObjectType()==ObjectType::Relationship) { rel=dynamic_cast(base_rel); rel->disconnectRelationship(); } else base_rel->disconnectRelationship(); base_rel->blockSignals(false); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::validateRelationships(void) { vector::iterator itr, itr_end, itr_ant; Relationship *rel=nullptr; BaseRelationship *base_rel=nullptr; vector vet_rel, vet_rel_inv, rels, fail_rels; bool found_inval_rel, valid_fail_rels=false; vector errors; map::iterator itr1, itr1_end; map error_map; map::iterator itr2, itr2_end; map conn_tries; unsigned idx, rels_gen_pk=0; vector schemas; BaseTable *tab1=nullptr, *tab2=nullptr; itr=relationships.begin(); itr_end=relationships.end(); /* Calculates the quantity of referece tables which has primary keys added by relationship. This type of primary key may cause unexpected relationship invalidation during the validation process because all relationship are disconnected and when reconnecting them the primary key sometimes is not yet created causing other relationships to be broken. This counter is used to try revalidate any relationship that emits ERR_LINK_TABLES_NO_PK exception during its connection */ while(itr!=itr_end) { rel=dynamic_cast(*itr); itr++; if(rel && (rel->getRelationshipType()==Relationship::Relationship11 || rel->getRelationshipType()==Relationship::Relationship1n) && rel->getReferenceTable()->getPrimaryKey() && rel->getReferenceTable()->getPrimaryKey()->isAddedByRelationship()) rels_gen_pk++; } itr=relationships.begin(); itr_end=relationships.end(); do { //Initializes the flag that indicates that some invalid relatioship was found. found_inval_rel=false; while(itr!=itr_end) { base_rel=dynamic_cast(*itr); itr++; //Validates only table-table relationships if(base_rel->getObjectType()==ObjectType::Relationship) { //Makes a cast to the correct object class rel=dynamic_cast(base_rel); //If the relationships is invalid if(rel->isInvalidated()) { //Inserts it to the invalid relationship vector vet_rel_inv.push_back(base_rel); //Marks the flag indicating the at least one relationship was found invalidated found_inval_rel=true; } else //Otherwise inserts the relationship on the valid relationships vet_rel.push_back(base_rel); } } //If there is some invalidated relationship or special objects to be recreated if(found_inval_rel || !xml_special_objs.empty()) { //Stores the special objects definition if there is some invalidated relationships if(!loading_model && xml_special_objs.empty()) storeSpecialObjectsXML(); if(found_inval_rel) { //Disconnects all the relationship disconnectRelationships(); /* Merges the two lists (valid and invalid relationships), taking care to insert the invalid ones at the end of the list */ rels=vet_rel; rels.insert(rels.end(), vet_rel_inv.begin(), vet_rel_inv.end()); vet_rel.clear(); vet_rel_inv.clear(); //Walking through the created list connecting the relationships itr=rels.begin(); itr_end=rels.end(); idx=0; while(itr!=itr_end) { rel=dynamic_cast(*itr); //Stores the current iterator in a auxiliary one to remove from list in case of error itr_ant=itr; itr++; try { //Try to connect the relationship rel->connectRelationship(); //Storing the schemas on a auxiliary vector to update them later tab1=rel->getTable(BaseRelationship::SrcTable); tab2=rel->getTable(BaseRelationship::DstTable); if(std::find(schemas.begin(), schemas.end(), tab1->getSchema())==schemas.end()) schemas.push_back(dynamic_cast(tab1->getSchema())); else if(tab2!=tab1 && std::find(schemas.begin(), schemas.end(), tab1->getSchema())==schemas.end()) schemas.push_back(dynamic_cast(tab2->getSchema())); idx++; /* Removes the relationship from the current position and inserts it into the next position after the next relationship to try the reconnection */ rels.erase(itr_ant); idx=0; /* If the list was emptied and there is relationship that fails to validate, the method will try to validate them one last time */ if(rels.size()==0 && !fail_rels.empty() && !valid_fail_rels) { rels.insert(rels.end(), fail_rels.begin(), fail_rels.end()); //Check this flag indicates that the fail_rels list must be copied only one time valid_fail_rels=true; } itr=rels.begin(); itr_end=rels.end(); } /* Case some error is raised during the connection the relationship is permanently invalidated and need to be removed from the model */ catch(Exception &e) { /* If the relationship connection failed after 'rels_gen_pk' times at the different errors or exists on the fail_rels vector (already tried to be validated) it will be deleted from model */ if((e.getErrorCode() != ErrorCode::InvLinkTablesNoPrimaryKey && conn_tries[rel] > rels_gen_pk) || (std::find(fail_rels.begin(), fail_rels.end(), rel)!=fail_rels.end())) { //Removes the relationship __removeObject(rel); //Removes the iterator that stores the relationship from the list rels.erase(itr_ant); //Stores the error raised in a list errors.push_back(e); } /* If the relationship connection fails with the ERR_LINK_TABLES_NO_PK error and the connection tries exceed the size of the relationship the relationship is isolated on a "failed to validate" list. This list will be appended to the main rel list when there is only one relationship to be validated */ else if(e.getErrorCode()==ErrorCode::InvLinkTablesNoPrimaryKey && (conn_tries[rel] > rels.size() || rel->getRelationshipType()==BaseRelationship::RelationshipNn)) { fail_rels.push_back(rel); rels.erase(itr_ant); conn_tries[rel]=0; /* If the list was emptied and there is relationship that fails to validate, the method will try to validate them one last time */ if(rels.size()==0 && !valid_fail_rels) { rels.insert(rels.end(), fail_rels.begin(), fail_rels.end()); valid_fail_rels=true; } } else { //Increments the connection tries conn_tries[rel]++; /* Removes the relationship from the current position and inserts it into the next position after the next relationship to try the reconnection */ rels.erase(itr_ant); //If the next index doesn't extrapolates the list size insert it on the next position if(idx+1 < rels.size()) rels.insert(rels.begin() + idx + 1,rel); else rels.push_back(rel); } /* Points the searching to the iterator immediately after the removed iterator evicting to walk on the list from the first item */ itr_end=rels.end(); itr=rels.begin() + idx; } } itr=rels.begin(); } //Recreating the special objects itr1=xml_special_objs.begin(); itr1_end=xml_special_objs.end(); //The special objects are created only when the model is not being loaded if(!loading_model && itr1!=itr1_end) { do { try { //Try to create the special object createSpecialObject(itr1->second, itr1->first); /* If the special object is successfully created, remove the errors related to a previous attempt to create it */ if(error_map.count(itr1->first)) error_map.erase(error_map.find(itr1->first)); //Removes the definition of the special object when it is created successfully xml_special_objs.erase(itr1); //Restart the special object creation itr1=xml_special_objs.begin(); itr1_end=xml_special_objs.end(); } catch(Exception &e) { //If some error related to the special object is raised, stores it for latter creation attempts error_map[itr1->first]=e; itr1++; idx++; } } while(itr1!=itr1_end); } } } //The validation continues until there is some invalid relationship while(found_inval_rel); if(!loading_model) { //Updates the schemas to ajdust its sizes due to the tables resizings while(!schemas.empty()) { schemas.back()->setModified(true); schemas.pop_back(); } } //Stores the errors related to creation of special objects on the general error vector itr2=error_map.begin(); itr2_end=error_map.end(); while(itr2!=itr2_end) { errors.push_back(itr2->second); itr2++; } //If errors were caught on the above executions they will be redirected to the user if(!errors.empty()) { if(!loading_model) xml_special_objs.clear(); /* Revalidates the fk relationships at this points because some fks must be removed due to special object invalidation */ itr=base_relationships.begin(); itr_end=base_relationships.end(); while(itr!=itr_end) { base_rel=dynamic_cast(*itr); if(base_rel->getRelationshipType()==BaseRelationship::RelationshipFk) this->updateTableFKRelationships(dynamic_cast
(base_rel->getTable(BaseRelationship::SrcTable))); itr++; } //Set all the model objects as modified to force the redraw of the entire model this->setObjectsModified(); //Redirects all the errors captured on the revalidation throw Exception(ErrorCode::RemInvalidatedObjects,__PRETTY_FUNCTION__,__FILE__,__LINE__,errors); } if(!loading_model) { for(auto &tab : tables) dynamic_cast(tab)->restoreRelObjectsIndexes(); for(auto &tab : foreign_tables) dynamic_cast(tab)->restoreRelObjectsIndexes(); xml_special_objs.clear(); } } void DatabaseModel::checkRelationshipRedundancy(Relationship *rel) { try { unsigned rel_type; //Raises an error if the user try to check the redundancy starting from a unnallocated relationship if(!rel) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); rel_type=rel->getRelationshipType(); /* Only identifier relationships or relationship that has identifier attributes (primary keys) are checked */ if((!rel->isSelfRelationship() && (rel->isIdentifier() || rel->hasIndentifierAttribute())) || (rel_type==Relationship::RelationshipGen || rel_type==Relationship::RelationshipDep || rel_type==Relationship::RelationshipPart)) { BaseTable *ref_table=nullptr, *src_table=nullptr; PhysicalTable *recv_table=nullptr; Relationship *rel_aux=nullptr; BaseRelationship *base_rel=nullptr; vector::iterator itr, itr_end; bool found_cycle=false; unsigned aux_rel_type; QString str_aux, msg; //Gets the tables from the relationship recv_table=rel->getReceiverTable(); ref_table=rel->getReferenceTable(); itr=relationships.begin(); itr_end=relationships.end(); /* Based on the obtained tables, scans the list of relationships in search of the cycle. A cycle is detected when a reference table from a relationship is the receiver table of the relationship used in the validation. */ while(itr!=itr_end && !found_cycle) { base_rel=dynamic_cast(*itr); itr++; if(base_rel->getObjectType()==ObjectType::Relationship) { rel_aux=dynamic_cast(base_rel); aux_rel_type=rel_aux->getRelationshipType(); src_table=rel_aux->getReferenceTable(); /* Case the reference table is equal to the receiver table of the relationship used as the start of validation and the current relationship type is the same as the latter relationship, this can indicate a principle of closing cycle, in this way the validation will proceed with the receiver table from the current relationship until que receiver table is the reference table of the initial relationship */ if(recv_table==src_table && aux_rel_type==rel_type && ((!rel_aux->isSelfRelationship() && (rel_aux->isIdentifier() || rel_aux->hasIndentifierAttribute())) || (aux_rel_type==Relationship::RelationshipGen || aux_rel_type==Relationship::RelationshipDep || aux_rel_type==Relationship::RelationshipPart))) { //The receiver table will be the receiver from the current relationship recv_table=rel_aux->getReceiverTable(); //Stores the relationship name to raise an error in case of closing cycle str_aux+=rel_aux->getName() + QString(", "); //Checking the closing cycle found_cycle=(recv_table==ref_table); //Restart the validation itr=relationships.begin(); } } } //Raises an error indicating the relationship names that close the cycle if(found_cycle) { str_aux+=rel->getName(); msg=Exception::getErrorMessage(ErrorCode::InsRelationshipRedundancy) .arg(rel->getName()) .arg(str_aux); throw Exception(msg,ErrorCode::InsRelationshipRedundancy,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::storeSpecialObjectsXML(void) { unsigned count=0, i=0, type_id=0; vector::iterator itr, itr_end; Sequence *sequence=nullptr; Permission *permission=nullptr; PhysicalTable *table=nullptr; TableObject *tab_obj=nullptr; Constraint *constr=nullptr; Index *index=nullptr; Trigger *trigger=nullptr; View *view=nullptr; BaseRelationship *rel=nullptr; GenericSQL *generic_sql=nullptr; Reference ref; ObjectType tab_obj_type[3]={ ObjectType::Constraint, ObjectType::Trigger, ObjectType::Index }; bool found=false; vector objects, rem_objects, upd_tables_rels, aux_tables; try { aux_tables = tables; aux_tables.insert(aux_tables.end(), foreign_tables.begin(), foreign_tables.end()); itr=aux_tables.begin(); itr_end=aux_tables.end(); /* Check on tables if there is some constraint/index/trigger that is referencing some column added by relationship */ while(itr!=itr_end) { table=dynamic_cast(*itr); itr++; for(type_id=0; type_id < 3; type_id++) { // Ignoring index type if we are dealing with foreign table if(table->getObjectType() == ObjectType::ForeignTable && tab_obj_type[type_id] == ObjectType::Index) continue; //Gets the table object count for the curret object type count=table->getObjectCount(tab_obj_type[type_id]); for(i=0; i < count; i++) { tab_obj=dynamic_cast(table->getObject(i, tab_obj_type[type_id])); found=false; if(tab_obj_type[type_id]==ObjectType::Constraint) { constr=dynamic_cast(tab_obj); /* A constraint is considered special in this case when it is referencing relationship added column and the constraint itself was not added by relationship (created manually by the user) */ found=(!constr->isAddedByRelationship() && constr->isReferRelationshipAddedColumn() && constr->getConstraintType()!=ConstraintType::PrimaryKey); //When found some special object, stores is xml definition if(found) xml_special_objs[constr->getObjectId()]=constr->getCodeDefinition(SchemaParser::XmlDefinition, true); } else if(tab_obj_type[type_id]==ObjectType::Trigger) { trigger=dynamic_cast(tab_obj); found=trigger->isReferRelationshipAddedColumn(); if(found) xml_special_objs[trigger->getObjectId()]=trigger->getCodeDefinition(SchemaParser::XmlDefinition); } else { index=dynamic_cast(tab_obj); found=index->isReferRelationshipAddedColumn(); if(found) xml_special_objs[index->getObjectId()]=index->getCodeDefinition(SchemaParser::XmlDefinition); } if(found) { constr = dynamic_cast(tab_obj); //When found the special object must be removed from the parent table table->removeObject(tab_obj->getName(), tab_obj->getObjectType()); //We need to store the table which fk was referencing relationship added columns in order to update the fk relationships of that table if(constr && constr->getConstraintType() == ConstraintType::ForeignKey) upd_tables_rels.push_back(table); //Removes the permission from the table object removePermissions(tab_obj); i--; count--; } } } } //Updating fk rels of tables which had fks referencing relationship added columns if(!upd_tables_rels.empty()) { vector::iterator end; if(upd_tables_rels.size() > 1) { std::sort(upd_tables_rels.begin(), upd_tables_rels.end()); end = std::unique(upd_tables_rels.begin(), upd_tables_rels.end()); upd_tables_rels.erase(end, upd_tables_rels.end()); } for(auto &tab : upd_tables_rels) updateTableFKRelationships(dynamic_cast
(tab)); } //Making a copy of the sequences list to avoid iterator invalidation when removing an object rem_objects.assign(sequences.begin(), sequences.end()); itr=rem_objects.begin(); itr_end=rem_objects.end(); while(itr!=itr_end) { sequence=dynamic_cast(*itr); itr++; if(sequence->isReferRelationshipAddedColumn()) { xml_special_objs[sequence->getObjectId()]=sequence->getCodeDefinition(SchemaParser::XmlDefinition); removeSequence(sequence); delete(sequence); } } //Making a copy of the view list to avoid iterator invalidation when removing an object rem_objects.assign(views.begin(), views.end()); itr=rem_objects.begin(); itr_end=rem_objects.end(); while(itr!=itr_end) { view=dynamic_cast(*itr); itr++; if(view->isReferRelationshipAddedColumn()) { xml_special_objs[view->getObjectId()]=view->getCodeDefinition(SchemaParser::XmlDefinition); /* Relationships linking the view and the referenced tables are considered as special objects in this case only to be recreated more easely latter */ count=view->getReferenceCount(Reference::SqlReferSelect); for(i=0; i < count; i++) { ref=view->getReference(i, Reference::SqlReferSelect); table=ref.getTable(); if(table) { //Get the relationship between the view and the referenced table rel=getRelationship(view, table); if(rel) { xml_special_objs[rel->getObjectId()]=rel->getCodeDefinition(SchemaParser::XmlDefinition); removeRelationship(rel); delete(rel); } } } /* Removing child objects from view and including them in the list of objects to be recreated, this will avoid errors when removing the view from model */ objects=view->getObjects(); for(auto &obj : objects) { xml_special_objs[obj->getObjectId()]=obj->getCodeDefinition(SchemaParser::XmlDefinition); view->removeObject(obj); delete(obj); } removeView(view); delete(view); } } //Making a copy of the permissions list to avoid iterator invalidation when removing an object rem_objects.assign(permissions.begin(), permissions.end()); itr=rem_objects.begin(); itr_end=rem_objects.end(); while(itr!=itr_end) { permission=dynamic_cast(*itr); tab_obj=dynamic_cast(permission->getObject()); itr++; if(tab_obj) { xml_special_objs[permission->getObjectId()]=permission->getCodeDefinition(SchemaParser::XmlDefinition); removePermission(permission); delete(permission); } } //Making a copy of the generic SQL objects list to avoid iterator invalidation when removing an object rem_objects.assign(genericsqls.begin(), genericsqls.end()); itr=rem_objects.begin(); itr_end=rem_objects.end(); while(itr!=itr_end) { generic_sql = dynamic_cast(*itr); itr++; if(generic_sql->isReferRelationshipAddedObject()) { xml_special_objs[generic_sql->getObjectId()] = generic_sql->getCodeDefinition(SchemaParser::XmlDefinition); removeGenericSQL(generic_sql); delete(generic_sql); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::createSpecialObject(const QString &xml_def, unsigned obj_id) { ObjectType obj_type; BaseObject *object=nullptr; try { //Restart the XML parser to read the passed xml buffer xmlparser.restartParser(); xmlparser.loadXMLBuffer(xml_def); //Identifies the object type through the start element on xml buffer obj_type=BaseObject::getObjectType(xmlparser.getElementName()); if(obj_type==ObjectType::Sequence) object=createSequence(true); else object=createObject(obj_type); if(obj_type==ObjectType::Sequence) addSequence(dynamic_cast(object)); else if(obj_type==ObjectType::View) addView(dynamic_cast(object)); else if(obj_type==ObjectType::Permission) addPermission(createPermission()); /* When the special object is recreated it receive a new id but to maintain the correct creation order, the object has its id restored with the passed id (obj_id) if it is specified */ if(object && obj_id!=0) object->object_id=obj_id; } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, xml_def); } } void DatabaseModel::addRelationship(BaseRelationship *rel, int obj_idx) { try { BaseTable *tab1=nullptr, *tab2=nullptr; QString msg; if(rel) { tab1=rel->getTable(BaseRelationship::SrcTable); tab2=rel->getTable(BaseRelationship::DstTable); //Raises an error if already exists an relationship between the tables if(rel->getRelationshipType() != Relationship::Relationship1n && rel->getRelationshipType() != Relationship::RelationshipNn && rel->getRelationshipType() != Relationship::RelationshipFk && getRelationship(tab1,tab2)) { msg=Exception::getErrorMessage(ErrorCode::InsDuplicatedRelationship) .arg(tab1->getName(true)) .arg(tab1->getTypeName()) .arg(tab2->getName(true)) .arg(tab2->getTypeName()); throw Exception(msg,ErrorCode::InsDuplicatedRelationship,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } //Before add the relationship, checks if a redundancy can occur case the relationship is added if(rel->getObjectType()==ObjectType::Relationship) checkRelationshipRedundancy(dynamic_cast(rel)); rel->blockSignals(loading_model); __addObject(rel, obj_idx); if(rel->getObjectType()==ObjectType::Relationship) { dynamic_cast(rel)->connectRelationship(); validateRelationships(); } else rel->connectRelationship(); rel->blockSignals(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeRelationship(BaseRelationship *rel, int obj_idx) { try { if(getObjectIndex(rel) >= 0) { PhysicalTable *recv_tab=nullptr; if(rel->getObjectType()==ObjectType::Relationship) { /* If the relationship is not a many-to-many we store the receiver table in order to * update the fk relationships (if there are any) */ if(rel->getRelationshipType()!=Relationship::RelationshipNn) recv_tab=dynamic_cast(rel)->getReceiverTable(); storeSpecialObjectsXML(); disconnectRelationships(); } else if(rel->getObjectType()==ObjectType::BaseRelationship) { rel->blockSignals(loading_model); rel->disconnectRelationship(); rel->blockSignals(false); } __removeObject(rel, obj_idx); if(rel->getObjectType()==ObjectType::Relationship) validateRelationships(); //Updating the fk relationships for the receiver table after removing the old relationship if(recv_tab && recv_tab->getObjectType() == ObjectType::Table) updateTableFKRelationships(dynamic_cast
(recv_tab)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } BaseRelationship *DatabaseModel::getRelationship(unsigned obj_idx, ObjectType rel_type) { //Raises an error if the object type used to get a relationship is invalid if(rel_type!=ObjectType::Relationship && rel_type!=ObjectType::BaseRelationship) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(dynamic_cast(getObject(obj_idx, rel_type))); } BaseRelationship *DatabaseModel::getRelationship(const QString &name) { BaseRelationship *rel=dynamic_cast(getObject(name, ObjectType::BaseRelationship)); if(!rel) rel=dynamic_cast(getObject(name, ObjectType::Relationship)); return(rel); } BaseRelationship *DatabaseModel::getRelationship(BaseTable *src_tab, BaseTable *dst_tab, Constraint *ref_fk) { vector::iterator itr, itr_end; vector rel_list; BaseRelationship *rel=nullptr; bool found=false, search_uniq_tab=false; BaseTable *tab1=nullptr, *tab2=nullptr; if(src_tab) { if(!dst_tab) { dst_tab=src_tab; search_uniq_tab=true; } if(ref_fk || src_tab->getObjectType()==ObjectType::View || dst_tab->getObjectType()==ObjectType::View) { itr=base_relationships.begin(); itr_end=base_relationships.end(); } else { rel_list.assign(base_relationships.begin(), base_relationships.end()); rel_list.insert(rel_list.end(), relationships.begin(), relationships.end()); itr=rel_list.begin(); itr_end=rel_list.end(); } while(itr!=itr_end && !found) { rel=dynamic_cast(*itr); tab1=rel->getTable(BaseRelationship::SrcTable); tab2=rel->getTable(BaseRelationship::DstTable); found=((!ref_fk || (ref_fk && rel->getReferenceForeignKey() == ref_fk)) && ((tab1==src_tab && tab2==dst_tab) || (tab2==src_tab && tab1==dst_tab) || (search_uniq_tab && (tab1==src_tab || tab2==src_tab)))); if(!found) { rel=nullptr; itr++; } } } return(rel); } vector DatabaseModel::getRelationships(BaseTable *tab) { vector aux_rels; vector rels; BaseRelationship *base_rel=nullptr; rels=base_relationships; rels.insert(rels.end(), relationships.begin(), relationships.end()); for(auto &obj : rels) { base_rel=dynamic_cast(obj); if(base_rel->getTable(BaseRelationship::SrcTable)==tab || base_rel->getTable(BaseRelationship::DstTable)==tab) aux_rels.push_back(base_rel); } return(aux_rels); } void DatabaseModel::addTextbox(Textbox *txtbox, int obj_idx) { try { __addObject(txtbox, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeTextbox(Textbox *txtbox, int obj_idx) { try { __removeObject(txtbox, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Textbox *DatabaseModel::getTextbox(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Textbox))); } Textbox *DatabaseModel::getTextbox(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Textbox))); } void DatabaseModel::addSchema(Schema *schema, int obj_idx) { try { __addObject(schema, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Schema *DatabaseModel::getSchema(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Schema))); } Schema *DatabaseModel::getSchema(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Schema))); } void DatabaseModel::removeSchema(Schema *schema, int obj_idx) { try { __removeObject(schema, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addRole(Role *role, int obj_idx) { try { __addObject(role, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Role *DatabaseModel::getRole(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Role))); } Role *DatabaseModel::getRole(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Role))); } void DatabaseModel::removeRole(Role *role, int obj_idx) { try { __removeObject(role, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addTablespace(Tablespace *tabspc, int obj_idx) { try { __addObject(tabspc, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Tablespace *DatabaseModel::getTablespace(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Tablespace))); } Tablespace *DatabaseModel::getTablespace(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Tablespace))); } void DatabaseModel::removeTablespace(Tablespace *tabspc, int obj_idx) { try { __removeObject(tabspc, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addCast(Cast *cast, int obj_idx) { try { __addObject(cast, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeCast(Cast *cast, int obj_idx) { try { __removeObject(cast, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Cast *DatabaseModel::getCast(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Cast))); } Cast *DatabaseModel::getCast(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Cast))); } void DatabaseModel::addConversion(Conversion *conv, int obj_idx) { try { __addObject(conv, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeConversion(Conversion *conv, int obj_idx) { try { __removeObject(conv, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Conversion *DatabaseModel::getConversion(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Conversion))); } Conversion *DatabaseModel::getConversion(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Conversion))); } void DatabaseModel::addLanguage(Language *lang, int obj_idx) { try { __addObject(lang, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Language *DatabaseModel::getLanguage(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Language))); } Language *DatabaseModel::getLanguage(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Language))); } void DatabaseModel::removeLanguage(Language *lang, int obj_idx) { try { __removeObject(lang, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addFunction(Function *func, int obj_idx) { try { __addObject(func, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Function *DatabaseModel::getFunction(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Function))); } Function *DatabaseModel::getFunction(const QString &signature) { return(dynamic_cast(getObject(signature, ObjectType::Function))); } void DatabaseModel::removeFunction(Function *func, int obj_idx) { try { __removeObject(func, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addAggregate(Aggregate *aggreg, int obj_idx) { try { __addObject(aggreg, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Aggregate *DatabaseModel::getAggregate(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Aggregate))); } Aggregate *DatabaseModel::getAggregate(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Aggregate))); } void DatabaseModel::removeAggregate(Aggregate *aggreg, int obj_idx) { try { __removeObject(aggreg, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addDomain(Domain *domain, int obj_idx) { if(domain) { vector::iterator itr, itr_end; bool found=false; QString str_aux; /* Before insert the domain checks if there is some user defined type with the same name as the domain. */ itr=types.begin(); itr_end=types.end(); while(itr!=itr_end && !found) { found=((*itr)->getName(true)==domain->getName(true)); itr++; } //Raises an error if found a type with the same name as the domain if(found) { str_aux=Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(domain->getName(true)) .arg(domain->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()); throw Exception(str_aux, ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } try { __addObject(domain, obj_idx); //When added to the model the domain is inserted on the pgsql base type list to be used as a column type PgSqlType::addUserType(domain->getName(true), domain, this, UserTypeConfig::DomainType); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } } void DatabaseModel::removeDomain(Domain *domain, int obj_idx) { try { removeUserType(domain, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Domain *DatabaseModel::getDomain(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Domain))); } Domain *DatabaseModel::getDomain(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Domain))); } void DatabaseModel::addOperatorFamily(OperatorFamily *op_family, int obj_idx) { try { __addObject(op_family, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } OperatorFamily *DatabaseModel::getOperatorFamily(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::OpFamily))); } OperatorFamily *DatabaseModel::getOperatorFamily(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::OpFamily))); } void DatabaseModel::removeOperatorFamily(OperatorFamily *op_family, int obj_idx) { try { __removeObject(op_family, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addOperatorClass(OperatorClass *op_class, int obj_idx) { try { __addObject(op_class, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeOperatorClass(OperatorClass *op_class, int obj_idx) { try { __removeObject(op_class, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } OperatorClass *DatabaseModel::getOperatorClass(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::OpClass))); } OperatorClass *DatabaseModel::getOperatorClass(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::OpClass))); } void DatabaseModel::addOperator(Operator *oper, int obj_idx) { try { __addObject(oper, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removeOperator(Operator *oper, int obj_idx) { try { __removeObject(oper, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Operator *DatabaseModel::getOperator(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Operator))); } Operator *DatabaseModel::getOperator(const QString &signature) { return(dynamic_cast(getObject(signature, ObjectType::Operator))); } void DatabaseModel::addType(Type *type, int obj_idx) { if(type) { vector::iterator itr, itr_end; bool found=false; QString str_aux; /* Before insert the type checks if there is some domain with the same name as the type. */ itr=domains.begin(); itr_end=domains.end(); while(itr!=itr_end && !found) { found=((*itr)->getName(true)==type->getName(true)); itr++; } if(found) { str_aux=Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(type->getName(true)) .arg(type->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()); throw Exception(str_aux, ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } try { __addObject(type, obj_idx); //When added to the model the user type is inserted on the pgsql base type list to be used as a column type PgSqlType::addUserType(type->getName(true), type, this, UserTypeConfig::BaseType); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } } void DatabaseModel::removeType(Type *type, int obj_idx) { try { removeUserType(type, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Type *DatabaseModel::getType(unsigned obj_idx) { return(dynamic_cast(getObject(obj_idx, ObjectType::Type))); } Type *DatabaseModel::getType(const QString &name) { return(dynamic_cast(getObject(name, ObjectType::Type))); } void DatabaseModel::removeUserType(BaseObject *object, int obj_idx) { try { __removeObject(object, obj_idx); //Removes the user type from the list of base types of pgsql PgSqlType::removeUserType(object->getName(true), object); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addPermissions(const vector &perms) { vector::const_iterator itr=perms.cbegin(), itr_end=perms.cend(); try { while(itr!=itr_end) { addPermission(*itr); itr++; } } catch(Exception &e) { //In case of errors removes the added permissions itr=perms.begin(); itr_end=perms.end(); while(itr!=itr_end) { removePermission(*itr); itr++; } throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::addPermission(Permission *perm) { try { if(!perm) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); TableObject *tab_obj=dynamic_cast(perm->getObject()); if(getPermissionIndex(perm, false) >=0) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedPermission) .arg(perm->getObject()->getName()) .arg(perm->getObject()->getTypeName()), ErrorCode::AsgDuplicatedPermission,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the permission is referencing an object that does not exists on model else if(perm->getObject()!=this && ((tab_obj && (getObjectIndex(tab_obj->getParentTable()) < 0)) || (!tab_obj && (getObjectIndex(perm->getObject()) < 0)))) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(perm->getName()) .arg(perm->getObject()->getTypeName()) .arg(perm->getObject()->getName()) .arg(perm->getObject()->getTypeName()), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); permissions.push_back(perm); perm->setDatabase(this); } catch(Exception &e) { if(e.getErrorCode()==ErrorCode::AsgDuplicatedObject) throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedPermission) .arg(perm->getObject()->getName()) .arg(perm->getObject()->getTypeName()), ErrorCode::AsgDuplicatedPermission,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseModel::removePermission(Permission *perm) { try { __removeObject(perm); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::removePermissions(BaseObject *object) { vector::iterator itr, itr_end; Permission *perm=nullptr; unsigned idx=0; if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=permissions.begin(); itr_end=permissions.end(); while(itr!=itr_end) { perm=dynamic_cast(*itr); if(perm->getObject()==object) { permissions.erase(itr); itr=itr_end=permissions.end(); if(!permissions.empty()) itr=permissions.begin() + idx; } else { itr++; idx++; } } } void DatabaseModel::getPermissions(BaseObject *object, vector &perms) { vector::iterator itr, itr_end; Permission *perm=nullptr; if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=permissions.begin(); itr_end=permissions.end(); perms.clear(); while(itr!=itr_end) { perm=dynamic_cast(*itr); if(perm->getObject()==object) perms.push_back(perm); itr++; } } int DatabaseModel::getPermissionIndex(Permission *perm, bool exact_match) { int perm_idx=-1; if(perm) { Permission *perm_aux=nullptr; vector::iterator itr, itr_end; itr=permissions.begin(); itr_end=permissions.end(); if(exact_match) { while(itr!=itr_end) { perm_aux=dynamic_cast(*itr); if(perm->isSimilarTo(perm_aux)) { perm_idx=itr-permissions.begin(); break; } itr++; } } else { BaseObject *object=nullptr; Role *role=nullptr; unsigned count, i; bool ref_role=false; object=perm->getObject(); while(itr!=itr_end) { perm_aux=dynamic_cast(*itr); /* When the object of the auxiliary permission is the same as the specified permission it will be check if the existant roles are the same on both permissions */ if(object==perm_aux->getObject()) { count=perm->getRoleCount(); for(i=0; i < count && !ref_role; i++) { role=perm->getRole(i); ref_role=perm_aux->isRoleExists(role); } } //If the permissions references the same roles but one is a REVOKE and other GRANT they a considered different if(perm==perm_aux || (ref_role && perm->isRevoke()==perm_aux->isRevoke())) { perm_idx=itr-permissions.begin(); break; } itr++; } } } return(perm_idx); } BaseObject *DatabaseModel::getObject(const QString &name, ObjectType obj_type) { int idx; return(getObject(name, obj_type, idx)); } int DatabaseModel::getObjectIndex(const QString &name, ObjectType obj_type) { int idx; getObject(name, obj_type, idx); return(idx); } int DatabaseModel::getObjectIndex(BaseObject *object) { if(!object) return(-1); else { ObjectType obj_type=object->getObjectType(); vector *obj_list=nullptr; vector::iterator itr, itr_end; bool found=false; obj_list=getObjectList(obj_type); if(!obj_list) throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && !found) { found=((*itr)==object); if(!found) itr++; } if(found) return(itr-obj_list->begin()); else return(-1); } } } void DatabaseModel::configureDatabase(attribs_map &attribs) { encoding=attribs[Attributes::Encoding]; template_db=attribs[Attributes::TemplateDb]; localizations[0]=attribs[Attributes::LcCtype]; localizations[1]=attribs[Attributes::LcCollate]; append_at_eod=attribs[Attributes::AppendAtEod]==Attributes::True; prepend_at_bod=attribs[Attributes::PrependAtBod]==Attributes::True; is_template=attribs[Attributes::IsTemplate]==Attributes::True; allow_conns=attribs[Attributes::AllowConns] != Attributes::False; if(!attribs[Attributes::ConnLimit].isEmpty()) conn_limit=attribs[Attributes::ConnLimit].toInt(); setBasicAttributes(this); } void DatabaseModel::loadModel(const QString &filename) { if(!filename.isEmpty()) { QString dtd_file, str_aux, elem_name; ObjectType obj_type; attribs_map attribs; BaseObject *object=nullptr; bool protected_model=false, found_inh_rel = false; QStringList pos_str; map def_objs; //Configuring the path to the base path for objects DTD dtd_file=GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectDTDDir + GlobalAttributes::DirSeparator; try { loading_model=true; xmlparser.restartParser(); //Loads the root DTD xmlparser.setDTDFile(dtd_file + GlobalAttributes::RootDTD + GlobalAttributes::ObjectDTDExt, GlobalAttributes::RootDTD); //Loads the file validating it against the root DTD xmlparser.loadXMLFile(filename); //Gets the basic model information xmlparser.getElementAttributes(attribs); setObjectListsCapacity(attribs[Attributes::MaxObjCount].toUInt()); this->author=attribs[Attributes::ModelAuthor]; pos_str=attribs[Attributes::LastPosition].split(','); if(pos_str.size()>=2) this->last_pos=QPoint(pos_str[0].toUInt(),pos_str[1].toUInt()); this->last_zoom=attribs[Attributes::LastZoom].toDouble(); if(this->last_zoom <= 0) this->last_zoom=1; this->is_template = attribs[Attributes::IsTemplate] == Attributes::True; this->allow_conns = (attribs[Attributes::AllowConns].isEmpty() || attribs[Attributes::AllowConns] == Attributes::True); layers = attribs[Attributes::Layers].split(';', QString::SkipEmptyParts); active_layers.clear(); /* Compatibility with models created prior the layers features: * If the "active-layers" is absent we make the default layer always visible */ if(!attribs.count(Attributes::ActiveLayers)) active_layers.push_back(0); else { for(auto &layer_id : attribs[Attributes::ActiveLayers].split(';', QString::SkipEmptyParts)) active_layers.push_back(layer_id.toInt()); } protected_model=(attribs[Attributes::Protected]==Attributes::True); def_objs[ObjectType::Schema]=attribs[Attributes::DefaultSchema]; def_objs[ObjectType::Role]=attribs[Attributes::DefaultOwner]; def_objs[ObjectType::Collation]=attribs[Attributes::DefaultCollation]; def_objs[ObjectType::Tablespace]=attribs[Attributes::DefaultTablespace]; if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem_name=xmlparser.getElementName(); //Indentifies the object type to be load according to the current element on the parser obj_type=getObjectType(elem_name); if(obj_type==ObjectType::Database) { xmlparser.getElementAttributes(attribs); configureDatabase(attribs); } else { try { //Saves the current position of the parser before create any object xmlparser.savePosition(); object=createObject(obj_type); if(object) { if(!dynamic_cast(object) && obj_type!=ObjectType::Relationship && obj_type!=ObjectType::BaseRelationship) addObject(object); /* If there is at least one inheritance relationship we need to flag this situation in order to do an addtional rel. validation in the end of loading */ if(!found_inh_rel && object->getObjectType()==ObjectType::Relationship && dynamic_cast(object)->getRelationshipType()==BaseRelationship::RelationshipGen) found_inh_rel=true; emit s_objectLoaded((xmlparser.getCurrentBufferLine()/static_cast(xmlparser.getBufferLineCount()))*100, trUtf8("Loading: `%1' (%2)") .arg(object->getName()) .arg(object->getTypeName()), enum_cast(obj_type)); } xmlparser.restorePosition(); } catch(Exception &e) { QString info_adicional=QString(QObject::trUtf8("%1 (line: %2)")).arg(xmlparser.getLoadedFilename()).arg(xmlparser.getCurrentElement()->line); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, info_adicional); } } } } while(xmlparser.accessElement(XmlParser::NextElement)); } this->BaseObject::setProtected(protected_model); //Validating default objects for(auto &itr : def_objs) { if(!itr.second.isEmpty()) { object=this->getObject(itr.second, itr.first); if(!object) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(this->getName()) .arg(this->getTypeName()) .arg(itr.second) .arg(BaseObject::getTypeName(itr.first)), ErrorCode::AsgDuplicatedPermission,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->setDefaultObject(object); } else this->setDefaultObject(nullptr, itr.first); } loading_model=false; //If there are relationship make a relationship validation to recreate any special object left behind if(!relationships.empty()) { emit s_objectLoaded(100, trUtf8("Validating relationships..."), enum_cast(ObjectType::Relationship)); storeSpecialObjectsXML(); disconnectRelationships(); validateRelationships(); } this->setInvalidated(false); emit s_objectLoaded(100, trUtf8("Validating relationships..."), enum_cast(ObjectType::Relationship)); //Doing another relationship validation when there are inheritances to avoid incomplete tables if(found_inh_rel) { emit s_objectLoaded(100, trUtf8("Validating relationships..."), enum_cast(ObjectType::Relationship)); validateRelationships(); } updateTablesFKRelationships(); emit s_objectLoaded(100, trUtf8("Rendering database model..."), enum_cast(ObjectType::BaseObject)); this->setObjectsModified(); } catch(Exception &e) { QString extra_info; loading_model=false; if(xmlparser.getCurrentElement()) extra_info=QString(QObject::trUtf8("%1 (line: %2)")).arg(xmlparser.getLoadedFilename()).arg(xmlparser.getCurrentElement()->line); if(e.getErrorCode()>=ErrorCode::InvalidSyntax) { str_aux=Exception::getErrorMessage(ErrorCode::InvModelFileNotLoaded).arg(filename); throw Exception(str_aux,ErrorCode::InvModelFileNotLoaded,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, extra_info); } else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, extra_info); } } } BaseObject *DatabaseModel::createObject(ObjectType obj_type) { BaseObject *object=nullptr; if(obj_type!=ObjectType::BaseObject) { if(obj_type==ObjectType::Role) object=createRole(); else if(obj_type==ObjectType::Tablespace) object=createTablespace(); else if(obj_type==ObjectType::Schema) object=createSchema(); else if(obj_type==ObjectType::Language) object=createLanguage(); else if(obj_type==ObjectType::Function) object=createFunction(); else if(obj_type==ObjectType::Type) object=createType(); else if(obj_type==ObjectType::Domain) object=createDomain(); else if(obj_type==ObjectType::Cast) object=createCast(); else if(obj_type==ObjectType::Conversion) object=createConversion(); else if(obj_type==ObjectType::Operator) object=createOperator(); else if(obj_type==ObjectType::OpFamily) object=createOperatorFamily(); else if(obj_type==ObjectType::OpClass) object=createOperatorClass(); else if(obj_type==ObjectType::Aggregate) object=createAggregate(); else if(obj_type==ObjectType::Table) object=createTable(); else if(obj_type==ObjectType::Sequence) object=createSequence(); else if(obj_type==ObjectType::View) object=createView(); else if(obj_type==ObjectType::Textbox) object=createTextbox(); else if(obj_type==ObjectType::Constraint) object=createConstraint(nullptr); else if(obj_type==ObjectType::Trigger) object=createTrigger(); else if(obj_type==ObjectType::Index) object=createIndex(); else if(obj_type==ObjectType::Column) object=createColumn(); else if(obj_type==ObjectType::Rule) object=createRule(); else if(obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship) object=createRelationship(); else if(obj_type==ObjectType::Collation) object=createCollation(); else if(obj_type==ObjectType::Extension) object=createExtension(); else if(obj_type==ObjectType::Tag) object=createTag(); else if(obj_type==ObjectType::Permission) object=createPermission(); else if(obj_type==ObjectType::EventTrigger) object=createEventTrigger(); else if(obj_type==ObjectType::GenericSql) object=createGenericSQL(); else if(obj_type==ObjectType::Policy) object=createPolicy(); else if(obj_type==ObjectType::ForeignDataWrapper) object=createForeignDataWrapper(); else if(obj_type==ObjectType::ForeignServer) object=createForeignServer(); else if(obj_type==ObjectType::UserMapping) object=createUserMapping(); else if(obj_type==ObjectType::ForeignTable) object=createForeignTable(); } return(object); } void DatabaseModel::setBasicAttributes(BaseObject *object) { attribs_map attribs, attribs_aux; QString elem_name; BaseObject *tabspc=nullptr, *owner=nullptr, *collation=nullptr; Schema *schema=nullptr; ObjectType obj_type=ObjectType::BaseObject, obj_type_aux; bool has_error=false, protected_obj=false, sql_disabled=false; ForeignObject *frn_object = dynamic_cast(object); if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); xmlparser.getElementAttributes(attribs); obj_type_aux=object->getObjectType(); if(obj_type_aux!=ObjectType::Cast && obj_type_aux != ObjectType::UserMapping) object->setName(attribs[Attributes::Name]); if(BaseObject::acceptsAlias(obj_type_aux)) object->setAlias(attribs[Attributes::Alias]); protected_obj=attribs[Attributes::Protected]==Attributes::True; sql_disabled=attribs[Attributes::SqlDisabled]==Attributes::True; if(frn_object) { QStringList opt_val; for(auto &option : attribs[Attributes::Options].split(ForeignObject::OptionsSeparator)) { opt_val = option.split(UserMapping::OptionValueSeparator); if(opt_val.size() < 2) continue; frn_object->setOption(opt_val[0], opt_val[1]); } } xmlparser.savePosition(); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem_name=xmlparser.getElementName(); //Defines the object's comment if(elem_name==Attributes::Comment) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); object->setComment(xmlparser.getElementContent()); xmlparser.restorePosition(); } //Defines the object's schema else if(elem_name==Attributes::Schema) { obj_type=ObjectType::Schema; xmlparser.getElementAttributes(attribs_aux); schema=dynamic_cast(getObject(attribs_aux[Attributes::Name], obj_type)); object->setSchema(schema); has_error=(!schema && !attribs_aux[Attributes::Name].isEmpty()); } //Defines the object's tablespace else if(elem_name==Attributes::Tablespace) { obj_type=ObjectType::Tablespace; xmlparser.getElementAttributes(attribs_aux); tabspc=getObject(attribs_aux[Attributes::Name], obj_type); object->setTablespace(tabspc); has_error=(!tabspc && !attribs_aux[Attributes::Name].isEmpty()); } //Defines the object's owner else if(elem_name==Attributes::Role) { obj_type=ObjectType::Role; xmlparser.getElementAttributes(attribs_aux); owner=getObject(attribs_aux[Attributes::Name], obj_type); object->setOwner(owner); has_error=(!owner && !attribs_aux[Attributes::Name].isEmpty()); } //Defines the object's schema else if(elem_name==Attributes::Collation) { obj_type=ObjectType::Collation; xmlparser.getElementAttributes(attribs_aux); collation=getObject(attribs_aux[Attributes::Name], obj_type); object->setCollation(collation); has_error=(!collation && !attribs_aux[Attributes::Name].isEmpty()); } else if(elem_name==Attributes::AppendedSql) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); object->setAppendedSQL(xmlparser.getElementContent()); xmlparser.restorePosition(); } else if(elem_name==Attributes::PrependedSql) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); object->setPrependedSQL(xmlparser.getElementContent()); xmlparser.restorePosition(); } //Defines the object's position (only for graphical objects) else if(elem_name==Attributes::Position) { xmlparser.getElementAttributes(attribs); if(elem_name==Attributes::Position && (obj_type_aux!=ObjectType::Relationship && obj_type_aux!=ObjectType::BaseRelationship)) { dynamic_cast(object)->setPosition(QPointF(attribs[Attributes::XPos].toDouble(), attribs[Attributes::YPos].toDouble())); } } } } while(!has_error && xmlparser.accessElement(XmlParser::NextElement)); } xmlparser.restorePosition(); object->setProtected(protected_obj); object->setSQLDisabled(sql_disabled); if(has_error) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(object->getName()) .arg(object->getTypeName()) .arg(attribs_aux[Attributes::Name]) .arg(BaseObject::getTypeName(obj_type)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(!object->getSchema() && (obj_type_aux==ObjectType::Function || obj_type_aux==ObjectType::Table || obj_type_aux==ObjectType::View || obj_type_aux==ObjectType::Domain || obj_type_aux==ObjectType::Aggregate || obj_type_aux==ObjectType::Operator || obj_type_aux==ObjectType::Sequence || obj_type_aux==ObjectType::Conversion || obj_type_aux==ObjectType::Type || obj_type_aux==ObjectType::OpFamily || obj_type_aux==ObjectType::OpClass)) { throw Exception(Exception::getErrorMessage(ErrorCode::InvObjectAllocationNoSchema) .arg(object->getName()) .arg(object->getTypeName()), ErrorCode::InvObjectAllocationNoSchema,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } QString DatabaseModel::getErrorExtraInfo(void) { QString extra_info; if(!xmlparser.getLoadedFilename().isEmpty()) extra_info=QString(QObject::trUtf8("%1 (line: %2)")).arg(xmlparser.getLoadedFilename()) .arg(xmlparser.getCurrentElement()->line); else extra_info=xmlparser.getXMLBuffer(); return extra_info; } void DatabaseModel::setLoadingModel(bool value) { loading_model = value; } void DatabaseModel::setObjectListsCapacity(unsigned capacity) { if(capacity < BaseObject::DefMaxObjectCount || capacity > (BaseObject::DefMaxObjectCount * 1000)) capacity = BaseObject::DefMaxObjectCount; unsigned half_cap = capacity/2, one_fourth_cap = capacity/4; views.reserve(capacity); tables.reserve(capacity); relationships.reserve(capacity); base_relationships.reserve(capacity); sequences.reserve(capacity); permissions.reserve(capacity); schemas.reserve(half_cap); roles.reserve(half_cap); functions.reserve(half_cap); types.reserve(half_cap); textboxes.reserve(half_cap); aggregates.reserve(half_cap); operators.reserve(half_cap); op_classes.reserve(half_cap); op_families.reserve(half_cap); domains.reserve(half_cap); collations.reserve(half_cap); extensions.reserve(half_cap); tags.reserve(half_cap); genericsqls.reserve(half_cap); tablespaces.reserve(one_fourth_cap); languages.reserve(one_fourth_cap); casts.reserve(one_fourth_cap); conversions.reserve(one_fourth_cap); eventtriggers.reserve(one_fourth_cap); } void DatabaseModel::setLastPosition(const QPoint &pnt) { last_pos=pnt; } QPoint DatabaseModel::getLastPosition(void) { return(last_pos); } void DatabaseModel::setLastZoomFactor(double zoom) { last_zoom=zoom; } double DatabaseModel::getLastZoomFactor(void) { return(last_zoom); } Role *DatabaseModel::createRole(void) { attribs_map attribs, attribs_aux; Role *role=nullptr, *ref_role=nullptr; int i, len; bool marked; QStringList list; QString elem_name; unsigned role_type; QString op_attribs[]={ Attributes::Superuser, Attributes::CreateDb, Attributes::CreateRole, Attributes::Inherit, Attributes::Login, Attributes::Encrypted, Attributes::Replication, Attributes::BypassRls }; unsigned op_vect[]={ Role::OpSuperuser, Role::OpCreateDb, Role::OpCreateRole, Role::OpInherit, Role::OpLogin, Role::OpEncrypted, Role::OpReplication, Role::OpBypassRls }; try { role=new Role; setBasicAttributes(role); //Gets all the attributes values from the XML xmlparser.getElementAttributes(attribs); role->setPassword(attribs[Attributes::Password]); role->setValidity(attribs[Attributes::Validity]); if(!attribs[Attributes::ConnLimit].isEmpty()) role->setConnectionLimit(attribs[Attributes::ConnLimit].toInt()); //Setting up the role options according to the configured on the XML for(i=0; i < 8; i++) { marked=attribs[op_attribs[i]]==Attributes::True; role->setOption(op_vect[i], marked); } if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem_name=xmlparser.getElementName(); //Getting the member roles if(elem_name==Attributes::Roles) { //Gets the member roles attributes xmlparser.getElementAttributes(attribs_aux); //The member roles names are separated by comma, so it is needed to split them list=attribs_aux[Attributes::Names].split(','); len=list.size(); //Identifying the member role type if(attribs_aux[Attributes::RoleType]==Attributes::Refer) role_type=Role::RefRole; else if(attribs_aux[Attributes::RoleType]==Attributes::Member) role_type=Role::MemberRole; else role_type=Role::AdminRole; for(i=0; i < len; i++) { //Gets the role using the name from the model using the name from the list ref_role=dynamic_cast(getObject(list[i].trimmed(),ObjectType::Role)); //Raises an error if the roles doesn't exists if(!ref_role) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(role->getName()) .arg(BaseObject::getTypeName(ObjectType::Role)) .arg(list[i]) .arg(BaseObject::getTypeName(ObjectType::Role)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } role->addRole(role_type, ref_role); } } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(role) delete(role); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(role); } Tablespace *DatabaseModel::createTablespace(void) { attribs_map attribs; Tablespace *tabspc=nullptr; try { tabspc=new Tablespace; setBasicAttributes(tabspc); xmlparser.getElementAttributes(attribs); tabspc->setDirectory(attribs[Attributes::Directory]); } catch(Exception &e) { if(tabspc) delete(tabspc); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(tabspc); } Schema *DatabaseModel::createSchema(void) { Schema *schema=nullptr; attribs_map attribs; try { schema=new Schema; xmlparser.getElementAttributes(attribs); setBasicAttributes(schema); schema->setFillColor(QColor(attribs[Attributes::FillColor])); schema->setRectVisible(attribs[Attributes::RectVisible]==Attributes::True); schema->setFadedOut(attribs[Attributes::FadedOut]==Attributes::True); schema->setLayer(attribs[Attributes::Layer].toUInt()); } catch(Exception &e) { if(schema) delete(schema); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(schema); } Language *DatabaseModel::createLanguage(void) { attribs_map attribs; Language *lang=nullptr; BaseObject *func=nullptr; QString signature, ref_type; ObjectType obj_type; try { lang=new Language; xmlparser.getElementAttributes(attribs); setBasicAttributes(lang); lang->setTrusted(attribs[Attributes::Trusted]==Attributes::True); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { obj_type=BaseObject::getObjectType(xmlparser.getElementName()); if(obj_type==ObjectType::Function) { xmlparser.getElementAttributes(attribs); //Gets the function reference type ref_type=attribs[Attributes::RefType]; //Only VALIDATOR, HANDLER and INLINE functions are accepted for the language if(ref_type==Attributes::ValidatorFunc || ref_type==Attributes::HandlerFunc || ref_type==Attributes::InlineFunc) { //Gets the function signature and tries to retrieve it from the model signature=attribs[Attributes::Signature]; func=getObject(signature, ObjectType::Function); //Raises an error if the function doesn't exists if(!func) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(lang->getName()) .arg(lang->getTypeName()) .arg(signature) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(ref_type==Attributes::ValidatorFunc) lang->setFunction(dynamic_cast(func), Language::ValidatorFunc); else if(ref_type==Attributes::HandlerFunc) lang->setFunction(dynamic_cast(func), Language::HandlerFunc); else lang->setFunction(dynamic_cast(func), Language::InlineFunc); } else //Raises an error if the function type is invalid throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(lang) delete(lang); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(lang); } Function *DatabaseModel::createFunction(void) { attribs_map attribs, attribs_aux; Function *func=nullptr; ObjectType obj_type; BaseObject *object=nullptr; PgSqlType type; Parameter param; QString str_aux, elem; try { func=new Function; setBasicAttributes(func); xmlparser.getElementAttributes(attribs); if(!attribs[Attributes::ReturnsSetOf].isEmpty()) func->setReturnSetOf(attribs[Attributes::ReturnsSetOf]== Attributes::True); if(!attribs[Attributes::WindowFunc].isEmpty()) func->setWindowFunction(attribs[Attributes::WindowFunc]== Attributes::True); if(!attribs[Attributes::LeakProof].isEmpty()) func->setLeakProof(attribs[Attributes::LeakProof]== Attributes::True); if(!attribs[Attributes::BehaviorType].isEmpty()) func->setBehaviorType(BehaviorType(attribs[Attributes::BehaviorType])); if(!attribs[Attributes::FunctionType].isEmpty()) func->setFunctionType(FunctionType(attribs[Attributes::FunctionType])); if(!attribs[Attributes::SecurityType].isEmpty()) func->setSecurityType(SecurityType(attribs[Attributes::SecurityType])); if(!attribs[Attributes::ExecutionCost].isEmpty()) func->setExecutionCost(attribs[Attributes::ExecutionCost].toInt()); if(!attribs[Attributes::RowAmount].isEmpty()) func->setRowAmount(attribs[Attributes::RowAmount].toInt()); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); obj_type=BaseObject::getObjectType(elem); //Gets the function return type from the XML if(elem==Attributes::ReturnType) { xmlparser.savePosition(); try { xmlparser.accessElement(XmlParser::ChildElement); do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { //when the element found is a TYPE indicates that the function return type is a single one if(xmlparser.getElementName()==Attributes::Type) { type=createPgSQLType(); func->setReturnType(type); } //when the element found is a PARAMETER indicates that the function return type is a table else if(xmlparser.getElementName()==Attributes::Parameter) { param=createParameter(); func->addReturnedTableColumn(param.getName(), param.getType()); } } } while(xmlparser.accessElement(XmlParser::NextElement)); xmlparser.restorePosition(); } catch(Exception &e) { xmlparser.restorePosition(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } //Gets the function language else if(obj_type==ObjectType::Language) { xmlparser.getElementAttributes(attribs); object=getObject(attribs[Attributes::Name], obj_type); //Raises an error if the function doesn't exisits if(!object) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(func->getName()) .arg(func->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Language)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); func->setLanguage(dynamic_cast(object)); } //Gets a function parameter else if(xmlparser.getElementName()==Attributes::Parameter) { param=createParameter(); func->addParameter(param); } //Gets the function code definition else if(xmlparser.getElementName()==Attributes::Definition) { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs_aux); if(!attribs_aux[Attributes::Library].isEmpty()) { func->setLibrary(attribs_aux[Attributes::Library]); func->setSymbol(attribs_aux[Attributes::Symbol]); } else if(xmlparser.accessElement(XmlParser::ChildElement)) func->setSourceCode(xmlparser.getElementContent()); xmlparser.restorePosition(); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(func) { str_aux=func->getName(true); delete(func); } if(e.getErrorCode()==ErrorCode::RefUserTypeInexistsModel) throw Exception(Exception::getErrorMessage(ErrorCode::AsgObjectInvalidDefinition) .arg(str_aux) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::AsgObjectInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, getErrorExtraInfo()); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(func); } Parameter DatabaseModel::createParameter(void) { Parameter param; attribs_map attribs; QString elem; try { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs); param.setName(attribs[Attributes::Name]); param.setDefaultValue(attribs[Attributes::DefaultValue]); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Type) { param.setType(createPgSQLType()); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } param.setIn(attribs[Attributes::ParamIn]==Attributes::True); param.setOut(attribs[Attributes::ParamOut]==Attributes::True); param.setVariadic(attribs[Attributes::ParamVariadic]==Attributes::True); xmlparser.restorePosition(); } catch(Exception &e) { QString extra_info=getErrorExtraInfo(); xmlparser.restorePosition(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, extra_info); } return(param); } TypeAttribute DatabaseModel::createTypeAttribute(void) { TypeAttribute tpattrib; attribs_map attribs; QString elem; BaseObject *collation=nullptr; try { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs); tpattrib.setName(attribs[Attributes::Name]); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Type) { tpattrib.setType(createPgSQLType()); } else if(elem==Attributes::Collation) { xmlparser.getElementAttributes(attribs); collation=getObject(attribs[Attributes::Name], ObjectType::Collation); //Raises an error if the operator class doesn't exists if(!collation) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(tpattrib.getName()) .arg(tpattrib.getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Collation)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } tpattrib.setCollation(collation); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } xmlparser.restorePosition(); } catch(Exception &e) { QString extra_info=getErrorExtraInfo(); xmlparser.restorePosition(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, extra_info); } return(tpattrib); } PgSqlType DatabaseModel::createPgSQLType(void) { attribs_map attribs; unsigned length=1, dimension=0, type_idx=0; int precision=-1; QString name; void *ptype=nullptr; bool with_timezone; IntervalType interv_type; SpatialType spatial_type; xmlparser.getElementAttributes(attribs); if(!attribs[Attributes::Length].isEmpty()) length=attribs[Attributes::Length].toUInt(); if(!attribs[Attributes::Dimension].isEmpty()) dimension=attribs[Attributes::Dimension].toUInt(); if(!attribs[Attributes::Precision].isEmpty()) precision=attribs[Attributes::Precision].toInt(); with_timezone=(attribs[Attributes::WithTimezone]==Attributes::True); interv_type=attribs[Attributes::IntervalType]; if(!attribs[Attributes::SpatialType].isEmpty()) spatial_type=SpatialType(attribs[Attributes::SpatialType], attribs[Attributes::Srid].toUInt(), attribs[Attributes::Variation].toUInt()); name=attribs[Attributes::Name]; /* A small tweak to detect a timestamp/date type which name contains the time zone modifier. This situation can occur mainly on reverse engineering operation where the data type of objects in most of times came as string form and need to be parsed */ if(!with_timezone && attribs[Attributes::Name].contains(QString("with time zone"), Qt::CaseInsensitive)) { with_timezone=true; name.remove(QString(" with time zone"), Qt::CaseInsensitive); } type_idx=PgSqlType::getBaseTypeIndex(name); if(type_idx!=PgSqlType::Null) { return(PgSqlType(name, dimension, length, precision, with_timezone, interv_type, spatial_type)); } else { //Raises an error if the referenced type name doesn't exists if(PgSqlType::getUserTypeIndex(name,nullptr,this) == BaseType::Null) throw Exception(ErrorCode::RefUserTypeInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); type_idx=PgSqlType::getUserTypeIndex(name, ptype); return(PgSqlType(type_idx, dimension, length, precision, with_timezone, interv_type, spatial_type)); } } Type *DatabaseModel::createType(void) { attribs_map attribs; map func_types; Type *type=nullptr; int count, i; QStringList enums; QString elem, str_aux; BaseObject *func=nullptr, *collation=nullptr; OperatorClass *op_class=nullptr; PgSqlType aux_type; try { type=new Type; setBasicAttributes(type); xmlparser.getElementAttributes(attribs); if(attribs[Attributes::Configuration]==Attributes::BaseType) { type->setConfiguration(Type::BaseType); type->setByValue(attribs[Attributes::ByValue]==Attributes::True); if(!attribs[Attributes::InternalLength].isEmpty()) type->setInternalLength(attribs[Attributes::InternalLength].toUInt()); if(!attribs[Attributes::Alignment].isEmpty()) type->setAlignment(attribs[Attributes::Alignment]); if(!attribs[Attributes::Storage].isEmpty()) type->setStorage(attribs[Attributes::Storage]); if(!attribs[Attributes::Element].isEmpty()) type->setElement(attribs[Attributes::Element]); if(!attribs[Attributes::Delimiter].isEmpty()) type->setDelimiter(attribs[Attributes::Delimiter][0].toLatin1()); if(!attribs[Attributes::DefaultValue].isEmpty()) type->setDefaultValue(attribs[Attributes::DefaultValue]); if(!attribs[Attributes::Category].isEmpty()) type->setCategory(attribs[Attributes::Category]); if(!attribs[Attributes::Preferred].isEmpty()) type->setPreferred(attribs[Attributes::Preferred]==Attributes::True); //Configuring an auxiliary map used to reference the functions used by base type func_types[Attributes::InputFunc]=Type::InputFunc; func_types[Attributes::OutputFunc]=Type::OutputFunc; func_types[Attributes::SendFunc]=Type::SendFunc; func_types[Attributes::RecvFunc]=Type::RecvFunc; func_types[Attributes::TpmodInFunc]=Type::TpmodInFunc; func_types[Attributes::TpmodOutFunc]=Type::TpmodOutFunc; func_types[Attributes::AnalyzeFunc]=Type::AnalyzeFunc; } else if(attribs[Attributes::Configuration]==Attributes::CompositeType) type->setConfiguration(Type::CompositeType); else if(attribs[Attributes::Configuration]==Attributes::EnumType) type->setConfiguration(Type::EnumerationType); else { type->setConfiguration(Type::RangeType); func_types[Attributes::CanonicalFunc]=Type::CanonicalFunc; func_types[Attributes::SubtypeDiffFunc]=Type::SubtypeDiffFunc; } if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); //Specific operations for ENUM type if(elem==Attributes::EnumType) { xmlparser.getElementAttributes(attribs); enums=attribs[Attributes::Values].split(','); count=enums.size(); for(i=0; i < count; i++) type->addEnumeration(enums[i]); } //Specific operations for COMPOSITE types else if(elem==Attributes::TypeAttribute) { type->addAttribute(createTypeAttribute()); } //Specific operations for BASE / RANGE type else if(elem==Attributes::Type) { aux_type=createPgSQLType(); if(type->getConfiguration()==Type::RangeType) type->setSubtype(aux_type); else type->setLikeType(aux_type); } else if(elem==Attributes::Collation) { xmlparser.getElementAttributes(attribs); collation=getObject(attribs[Attributes::Name], ObjectType::Collation); //Raises an error if the operator class doesn't exists if(!collation) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(type->getName()) .arg(type->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Collation)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } type->setCollation(collation); } if(elem==Attributes::OpClass) { xmlparser.getElementAttributes(attribs); op_class=dynamic_cast(getObject(attribs[Attributes::Name], ObjectType::OpClass)); //Raises an error if the operator class doesn't exists if(!op_class) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(type->getName()) .arg(type->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::OpClass)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } type->setSubtypeOpClass(op_class); } //Configuring the functions used by the type (only for BASE type) else if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); //Tries to get the function from the model func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists if(!func && !attribs[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(type->getName()) .arg(type->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the function type is invalid else if(func_types.count(attribs[Attributes::RefType])==0) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); type->setFunction(func_types[attribs[Attributes::RefType]], dynamic_cast(func)); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(type) { str_aux=type->getName(true); delete(type); } if(e.getErrorCode()==ErrorCode::RefUserTypeInexistsModel) throw Exception(Exception::getErrorMessage(ErrorCode::AsgObjectInvalidDefinition) .arg(str_aux) .arg(type->getTypeName()), ErrorCode::AsgObjectInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, getErrorExtraInfo()); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(type); } Domain *DatabaseModel::createDomain(void) { attribs_map attribs; Domain *domain=nullptr; QString elem; try { domain=new Domain; setBasicAttributes(domain); xmlparser.getElementAttributes(attribs); if(!attribs[Attributes::DefaultValue].isEmpty()) domain->setDefaultValue(attribs[Attributes::DefaultValue]); domain->setNotNull(attribs[Attributes::NotNull]==Attributes::True); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); //If a type element is found it'll be extracted an type which the domain is applied if(elem==Attributes::Type) { domain->setType(createPgSQLType()); } else if(elem==Attributes::Constraint) { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs); xmlparser.accessElement(XmlParser::ChildElement); xmlparser.accessElement(XmlParser::ChildElement); domain->addCheckConstraint(attribs[Attributes::Name], xmlparser.getElementContent()); xmlparser.restorePosition(); } } } while(xmlparser.accessElement(xmlparser.NextElement)); } } catch(Exception &e) { if(domain) delete(domain); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(domain); } Cast *DatabaseModel::createCast(void) { attribs_map attribs; Cast *cast=nullptr; QString elem; unsigned type_idx=0; PgSqlType type; BaseObject *func=nullptr; try { cast=new Cast; setBasicAttributes(cast); xmlparser.getElementAttributes(attribs); if(attribs[Attributes::CastType]==Attributes::Implicit) cast->setCastType(Cast::Implicit); else if(attribs[Attributes::CastType]==Attributes::Assignment) cast->setCastType(Cast::Assignment); else cast->setCastType(Cast::Explicit); cast->setInOut(attribs[Attributes::IoCast]==Attributes::True); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); //Extract one argument type from the XML if(elem==Attributes::Type) { type=createPgSQLType(); if(type_idx==0) cast->setDataType(Cast::SrcType, type); else cast->setDataType(Cast::DstType, type); type_idx++; } //Extracts the conversion function else if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists if(!func && !attribs[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(cast->getName()) .arg(cast->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); cast->setCastFunction(dynamic_cast(func)); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(cast) delete(cast); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(cast); } Conversion *DatabaseModel::createConversion(void) { attribs_map attribs; Conversion *conv=nullptr; QString elem; BaseObject *func=nullptr; try { conv=new Conversion; setBasicAttributes(conv); xmlparser.getElementAttributes(attribs); conv->setEncoding(Conversion::SrcEncoding, EncodingType(attribs[Attributes::SrcEncoding])); conv->setEncoding(Conversion::DstEncoding, EncodingType(attribs[Attributes::DstEncoding])); conv->setDefault(attribs[Attributes::Default]==Attributes::True); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists if(!func && !attribs[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(conv->getName()) .arg(conv->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); conv->setConversionFunction(dynamic_cast(func)); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(conv) delete(conv); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(conv); } Operator *DatabaseModel::createOperator(void) { attribs_map attribs; map func_types; map oper_types; Operator *oper=nullptr; QString elem; BaseObject *func=nullptr,*oper_aux=nullptr; unsigned arg_type; PgSqlType type; try { oper=new Operator; setBasicAttributes(oper); xmlparser.getElementAttributes(attribs); oper->setMerges(attribs[Attributes::Merges]==Attributes::True); oper->setHashes(attribs[Attributes::Hashes]==Attributes::True); func_types[Attributes::OperatorFunc]=Operator::FuncOperator; func_types[Attributes::JoinFunc]=Operator::FuncJoin; func_types[Attributes::RestrictionFunc]=Operator::FuncRestrict; oper_types[Attributes::CommutatorOp]=Operator::OperCommutator; oper_types[Attributes::NegatorOp]=Operator::OperNegator; if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==objs_schemas[enum_cast(ObjectType::Operator)]) { xmlparser.getElementAttributes(attribs); oper_aux=getObject(attribs[Attributes::Signature], ObjectType::Operator); //Raises an error if the auxiliary operator doesn't exists if(!oper_aux && !attribs[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(oper->getSignature(true)) .arg(oper->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Operator)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); oper->setOperator(dynamic_cast(oper_aux), oper_types[attribs[Attributes::RefType]]); } else if(elem==Attributes::Type) { xmlparser.getElementAttributes(attribs); if(attribs[Attributes::RefType]!=Attributes::RightType) arg_type=Operator::LeftArg; else arg_type=Operator::RightArg; type=createPgSQLType(); oper->setArgumentType(type, arg_type); } else if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists on the model if(!func && !attribs[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(oper->getName()) .arg(oper->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); oper->setFunction(dynamic_cast(func), func_types[attribs[Attributes::RefType]]); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(oper) delete(oper); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(oper); } OperatorClass *DatabaseModel::createOperatorClass(void) { attribs_map attribs, attribs_aux; map elem_types; BaseObject *object=nullptr; QString elem; PgSqlType type; OperatorClass *op_class=nullptr; OperatorClassElement class_elem; unsigned stg_number, elem_type; try { op_class=new OperatorClass; setBasicAttributes(op_class); xmlparser.getElementAttributes(attribs); op_class->setIndexingType(IndexingType(attribs[Attributes::IndexType])); op_class->setDefault(attribs[Attributes::Default]==Attributes::True); elem_types[Attributes::Function]=OperatorClassElement::FunctionElem; elem_types[Attributes::Operator]=OperatorClassElement::OperatorElem; elem_types[Attributes::Storage]=OperatorClassElement::StorageElem; if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==objs_schemas[enum_cast(ObjectType::OpFamily)]) { xmlparser.getElementAttributes(attribs); object=getObject(attribs[Attributes::Signature], ObjectType::OpFamily); //Raises an error if the operator family doesn't exists if(!object) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(op_class->getName()) .arg(op_class->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::OpFamily)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); op_class->setFamily(dynamic_cast(object)); } else if(elem==Attributes::Type) { xmlparser.getElementAttributes(attribs); type=createPgSQLType(); op_class->setDataType(type); } else if(elem==Attributes::Element) { xmlparser.getElementAttributes(attribs); stg_number=attribs[Attributes::StrategyNum].toUInt(); elem_type=elem_types[attribs[Attributes::Type]]; xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); xmlparser.getElementAttributes(attribs); if(elem_type==OperatorClassElement::StorageElem) { type=createPgSQLType(); class_elem.setStorage(type); } else if(elem_type==OperatorClassElement::FunctionElem) { object=getObject(attribs[Attributes::Signature],ObjectType::Function); class_elem.setFunction(dynamic_cast(object),stg_number); } else if(elem_type==OperatorClassElement::OperatorElem) { object=getObject(attribs[Attributes::Signature],ObjectType::Operator); class_elem.setOperator(dynamic_cast(object),stg_number); if(xmlparser.hasElement(XmlParser::NextElement)) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::NextElement); xmlparser.getElementAttributes(attribs_aux); object=getObject(attribs_aux[Attributes::Signature],ObjectType::OpFamily); if(!object && !attribs_aux[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(op_class->getName()) .arg(op_class->getTypeName()) .arg(attribs_aux[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::OpFamily)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); class_elem.setOperatorFamily(dynamic_cast(object)); xmlparser.restorePosition(); } } op_class->addElement(class_elem); xmlparser.restorePosition(); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(op_class) delete(op_class); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(op_class); } OperatorFamily *DatabaseModel::createOperatorFamily(void) { attribs_map attribs; OperatorFamily *op_family=nullptr; try { op_family=new OperatorFamily; setBasicAttributes(op_family); xmlparser.getElementAttributes(attribs); op_family->setIndexingType(IndexingType(attribs[Attributes::IndexType])); } catch(Exception &e) { if(op_family) delete(op_family); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(op_family); } Aggregate *DatabaseModel::createAggregate(void) { attribs_map attribs; BaseObject *func=nullptr; QString elem; PgSqlType type; Aggregate *aggreg=nullptr; try { aggreg=new Aggregate; setBasicAttributes(aggreg); xmlparser.getElementAttributes(attribs); aggreg->setInitialCondition(attribs[Attributes::InitialCond]); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Type) { xmlparser.getElementAttributes(attribs); type=createPgSQLType(); if(attribs[Attributes::RefType]==Attributes::StateType) aggreg->setStateType(type); else aggreg->addDataType(type); } else if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists on the model if(!func && !attribs[Attributes::Signature].isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(aggreg->getName()) .arg(aggreg->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(attribs[Attributes::RefType]==Attributes::TransitionFunc) aggreg->setFunction(Aggregate::TransitionFunc, dynamic_cast(func)); else aggreg->setFunction(Aggregate::FinalFunc, dynamic_cast(func)); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(aggreg) delete(aggreg); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(aggreg); } Table *DatabaseModel::createTable(void) { try { Table *table = nullptr; attribs_map attribs; xmlparser.getElementAttributes(attribs); table = createPhysicalTable
(); table->setUnlogged(attribs[Attributes::Unlogged]==Attributes::True); table->setRLSEnabled(attribs[Attributes::RlsEnabled]==Attributes::True); table->setRLSForced(attribs[Attributes::RlsForced]==Attributes::True); table->setWithOIDs(attribs[Attributes::Oids]==Attributes::True); return(table); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Column *DatabaseModel::createColumn(void) { attribs_map attribs; Column *column=nullptr; BaseObject *seq=nullptr; QString elem; try { column=new Column; setBasicAttributes(column); xmlparser.getElementAttributes(attribs); column->setNotNull(attribs[Attributes::NotNull]==Attributes::True); column->setDefaultValue(attribs[Attributes::DefaultValue]); column->setIdSeqAttributes(attribs[Attributes::MinValue], attribs[Attributes::MaxValue], attribs[Attributes::Increment], attribs[Attributes::Start], attribs[Attributes::Cache], attribs[Attributes::Cycle] == Attributes::True); if(!attribs[Attributes::IdentityType].isEmpty()) column->setIdentityType(IdentityType(attribs[Attributes::IdentityType])); if(!attribs[Attributes::Sequence].isEmpty()) { seq=getObject(attribs[Attributes::Sequence], ObjectType::Sequence); if(!seq) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Column)) .arg(attribs[Attributes::Sequence]) .arg(BaseObject::getTypeName(ObjectType::Sequence)), ErrorCode::PermissionRefInexistObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); column->setSequence(seq); } if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Type) { column->setType(createPgSQLType()); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(column) delete(column); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(column); } Constraint *DatabaseModel::createConstraint(BaseObject *parent_obj) { attribs_map attribs; Constraint *constr=nullptr; BaseObject *ref_table=nullptr; PhysicalTable *table=nullptr,*table_aux=nullptr; Column *column=nullptr; Relationship *rel=nullptr; QString elem, str_aux; bool deferrable, ins_constr_table=false; ConstraintType constr_type; QStringList col_list; int count, i; unsigned col_type; ObjectType obj_type; ExcludeElement exc_elem; try { xmlparser.getElementAttributes(attribs); //If the constraint parent is allocated if(parent_obj) { obj_type=parent_obj->getObjectType(); //Identifies the correct parent type if(PhysicalTable::isPhysicalTable(obj_type)) table=dynamic_cast(parent_obj); else if(obj_type==ObjectType::Relationship) rel=dynamic_cast(parent_obj); else //Raises an error if the user tries to create a constraint in a invalid parent throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { obj_type = ObjectType::Table; table = dynamic_cast(getObject(attribs[Attributes::Table], {ObjectType::Table, ObjectType::ForeignTable})); parent_obj=table; ins_constr_table=true; //Raises an error if the parent table doesn't exists if(!table) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Constraint)) .arg(attribs[Attributes::Table]) .arg(BaseObject::getTypeName(obj_type)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } constr=new Constraint; constr->setParentTable(table); //Configuring the constraint type if(attribs[Attributes::Type]==Attributes::CkConstr) constr_type=ConstraintType::Check; else if(attribs[Attributes::Type]==Attributes::PkConstr) constr_type=ConstraintType::PrimaryKey; else if(attribs[Attributes::Type]==Attributes::FkConstr) constr_type=ConstraintType::ForeignKey; else if(attribs[Attributes::Type]==Attributes::UqConstr) constr_type=ConstraintType::Unique; else constr_type=ConstraintType::Exclude; constr->setConstraintType(constr_type); if(!attribs[Attributes::Factor].isEmpty()) constr->setFillFactor(attribs[Attributes::Factor].toUInt()); setBasicAttributes(constr); //Raises an error if the constraint is a primary key and no parent object is specified if(!parent_obj && constr_type==ConstraintType::PrimaryKey) throw Exception(Exception::getErrorMessage(ErrorCode::InvPrimaryKeyAllocation) .arg(constr->getName()), ErrorCode::InvPrimaryKeyAllocation,__PRETTY_FUNCTION__,__FILE__,__LINE__); deferrable=(attribs[Attributes::Deferrable]==Attributes::True); constr->setDeferrable(deferrable); if(deferrable && !attribs[Attributes::DeferType].isEmpty()) constr->setDeferralType(attribs[Attributes::DeferType]); if(constr_type==ConstraintType::ForeignKey) { if(!attribs[Attributes::ComparisonType].isEmpty()) constr->setMatchType(attribs[Attributes::ComparisonType]); if(!attribs[Attributes::DelAction].isEmpty()) constr->setActionType(attribs[Attributes::DelAction], Constraint::DeleteAction); if(!attribs[Attributes::UpdAction].isEmpty()) constr->setActionType(attribs[Attributes::UpdAction], Constraint::UpdateAction); ref_table=getObject(attribs[Attributes::RefTable], ObjectType::Table); if(!ref_table && table->getName(true)==attribs[Attributes::RefTable]) ref_table=table; //Raises an error if the referenced table doesn't exists if(!ref_table) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(constr->getName()) .arg(constr->getTypeName()) .arg(attribs[Attributes::RefTable]) .arg(BaseObject::getTypeName(ObjectType::Table)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } constr->setReferencedTable(dynamic_cast(ref_table)); } else if(constr_type==ConstraintType::Check) { constr->setNoInherit(attribs[Attributes::NoInherit]==Attributes::True); } else if(constr_type==ConstraintType::Exclude && !attribs[Attributes::IndexType].isEmpty()) { constr->setIndexType(attribs[Attributes::IndexType]); } if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::ExcludeElement) { createElement(exc_elem, constr, parent_obj); constr->addExcludeElement(exc_elem); } else if(elem==Attributes::Expression) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); constr->setExpression(xmlparser.getElementContent()); xmlparser.restorePosition(); } else if(elem==Attributes::Columns) { xmlparser.getElementAttributes(attribs); col_list=attribs[Attributes::Names].split(','); count=col_list.count(); if(attribs[Attributes::RefType]==Attributes::SrcColumns) col_type=Constraint::SourceCols; else col_type=Constraint::ReferencedCols; for(i=0; i < count; i++) { if(col_type==Constraint::SourceCols) { if(PhysicalTable::isPhysicalTable(obj_type)) { column=table->getColumn(col_list[i]); //If the column doesn't exists tries to get it searching by the old name if(!column) column=table->getColumn(col_list[i], true); } else column=dynamic_cast(rel->getObject(col_list[i], ObjectType::Column)); } else { table_aux=dynamic_cast(ref_table); column=table_aux->getColumn(col_list[i]); //If the column doesn't exists tries to get it searching by the old name if(!column) column=table_aux->getColumn(col_list[i], true); } constr->addColumn(column, col_type); } } } } while(xmlparser.accessElement(XmlParser::NextElement)); } if(ins_constr_table) { if(constr->getConstraintType()!=ConstraintType::PrimaryKey) { table->addConstraint(constr); if(this->getObjectIndex(table) >= 0) table->setModified(!loading_model); } } } catch(Exception &e) { if(constr) delete(constr); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(constr); } void DatabaseModel::createElement(Element &elem, TableObject *tab_obj, BaseObject *parent_obj) { attribs_map attribs; Column *column=nullptr; OperatorClass *op_class=nullptr; Operator *oper=nullptr; Collation *collation=nullptr; QString xml_elem; bool is_part_key = false; xml_elem=xmlparser.getElementName(); is_part_key = xml_elem == Attributes::PartitionKey; if(xml_elem==Attributes::IndexElement || xml_elem==Attributes::ExcludeElement || is_part_key) { xmlparser.getElementAttributes(attribs); elem.setColumn(nullptr); elem.setCollation(nullptr); elem.setOperator(nullptr); elem.setOperatorClass(nullptr); elem.setSortingAttribute(Element::AscOrder, attribs[Attributes::AscOrder]==Attributes::True); elem.setSortingAttribute(Element::NullsFirst, attribs[Attributes::NullsFirst]==Attributes::True); elem.setSortingEnabled(attribs[Attributes::UseSorting]!=Attributes::False); xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); do { xml_elem=xmlparser.getElementName(); if(xmlparser.getElementType()==XML_ELEMENT_NODE) { if(xml_elem==Attributes::OpClass) { xmlparser.getElementAttributes(attribs); op_class=dynamic_cast(getObject(attribs[Attributes::Signature], ObjectType::OpClass)); //Raises an error if the operator class doesn't exists if(!op_class) { if(!is_part_key) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(tab_obj->getName()) .arg(tab_obj->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::OpClass)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { throw Exception(Exception::getErrorMessage(ErrorCode::PartKeyObjectInexistsModel) .arg(parent_obj->getName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::OpClass)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } elem.setOperatorClass(op_class); } //Checking if elem is a ExcludeElement to be able to assign an operator to it else if(xml_elem==Attributes::Operator) { xmlparser.getElementAttributes(attribs); oper=dynamic_cast(getObject(attribs[Attributes::Signature], ObjectType::Operator)); //Raises an error if the operator doesn't exists if(!oper) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(tab_obj->getName()) .arg(tab_obj->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Operator)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } elem.setOperator(oper); } else if(xml_elem==Attributes::Collation) { xmlparser.getElementAttributes(attribs); collation=dynamic_cast(getObject(attribs[Attributes::Name], ObjectType::Collation)); //Raises an error if the operator class doesn't exists if(!collation) { if(!is_part_key) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(tab_obj->getName()) .arg(tab_obj->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Collation)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { throw Exception(Exception::getErrorMessage(ErrorCode::PartKeyObjectInexistsModel) .arg(parent_obj->getName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Collation)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } elem.setCollation(collation); } else if(xml_elem==Attributes::Column) { xmlparser.getElementAttributes(attribs); if(parent_obj->getObjectType()==ObjectType::Table) { column=dynamic_cast
(parent_obj)->getColumn(attribs[Attributes::Name]); if(!column) column=dynamic_cast
(parent_obj)->getColumn(attribs[Attributes::Name], true); } else { column=dynamic_cast(dynamic_cast(parent_obj)->getObject(attribs[Attributes::Name], ObjectType::Column)); } //Raises an error if the column doesn't exists if(!column) { if(!is_part_key) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(tab_obj->getName()) .arg(tab_obj->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Column)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { throw Exception(Exception::getErrorMessage(ErrorCode::PartKeyObjectInexistsModel) .arg(parent_obj->getName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Column)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } elem.setColumn(column); } else if(xml_elem==Attributes::Expression) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); elem.setExpression(xmlparser.getElementContent()); xmlparser.restorePosition(); } } } while(xmlparser.accessElement(XmlParser::NextElement)); xmlparser.restorePosition(); } } XmlParser *DatabaseModel::getXMLParser(void) { return(&xmlparser); } QString DatabaseModel::getAlterDefinition(BaseObject *object) { DatabaseModel *db_aux=dynamic_cast(object); if(!db_aux) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { QString alter_def; attribs_map aux_attribs; aux_attribs[Attributes::Signature] = this->getSignature(); aux_attribs[Attributes::SqlObject] = this->getSQLName(); if(this->conn_limit!=db_aux->conn_limit) aux_attribs[Attributes::ConnLimit]=QString::number(db_aux->conn_limit); if(this->is_template != db_aux->is_template) aux_attribs[Attributes::IsTemplate] = (db_aux->is_template ? Attributes::True : Attributes::False); if(this->allow_conns != db_aux->allow_conns) aux_attribs[Attributes::AllowConns] = (db_aux->allow_conns ? Attributes::True : Attributes::False); alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), aux_attribs, true, false); alter_def+=BaseObject::getAlterDefinition(object); return(alter_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } Index *DatabaseModel::createIndex(void) { attribs_map attribs; Index *index=nullptr; QString elem, str_aux; IndexElement idx_elem; BaseTable *table=nullptr; try { xmlparser.getElementAttributes(attribs); table=dynamic_cast(getObject(attribs[Attributes::Table], ObjectType::Table)); if(!table) table=dynamic_cast(getObject(attribs[Attributes::Table], ObjectType::View)); //Raises an error if the parent table doesn't exists if(!table) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Index)) .arg(attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Table)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } index=new Index; setBasicAttributes(index); index->setParentTable(table); index->setIndexAttribute(Index::Concurrent, attribs[Attributes::Concurrent]==Attributes::True); index->setIndexAttribute(Index::Unique, attribs[Attributes::Unique]==Attributes::True); index->setIndexAttribute(Index::FastUpdate, attribs[Attributes::FastUpdate]==Attributes::True); index->setIndexAttribute(Index::Buffering, attribs[Attributes::Buffering]==Attributes::True); index->setIndexingType(attribs[Attributes::IndexType]); index->setFillFactor(attribs[Attributes::Factor].toUInt()); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::IndexElement) { createElement(idx_elem, index, table); index->addIndexElement(idx_elem); } else if(elem==Attributes::Predicate) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); str_aux=xmlparser.getElementContent(); xmlparser.restorePosition(); index->setPredicate(str_aux); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } table->addObject(index); table->setModified(!loading_model); } catch(Exception &e) { if(index) delete(index); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(index); } Rule *DatabaseModel::createRule(void) { attribs_map attribs; QStringList cmd_list; Rule *rule=nullptr; QString elem, str_aux; int count, i; BaseTable *table=nullptr; try { rule=new Rule; setBasicAttributes(rule); xmlparser.getElementAttributes(attribs); table=dynamic_cast(getObject(attribs[Attributes::Table], ObjectType::Table)); if(!table) table=dynamic_cast(getObject(attribs[Attributes::Table], ObjectType::View)); if(!table) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Rule)) .arg(attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); rule->setExecutionType(attribs[Attributes::ExecType]); rule->setEventType(attribs[Attributes::EventType]); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Commands || elem==Attributes::Condition) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); str_aux=xmlparser.getElementContent(); xmlparser.restorePosition(); if(elem==Attributes::Commands) { cmd_list=str_aux.split(';'); count=cmd_list.count(); for(i=0; i < count; i++) { if(!cmd_list[i].isEmpty()) rule->addCommand(cmd_list[i]); } } else rule->setConditionalExpression(str_aux); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } table->addObject(rule); table->setModified(!loading_model); } catch(Exception &e) { if(rule) delete(rule); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(rule); } Trigger *DatabaseModel::createTrigger(void) { attribs_map attribs; Trigger *trigger=nullptr; QString elem, str_aux; QStringList list_aux; int count, i; BaseObject *ref_table=nullptr, *func=nullptr; Column *column=nullptr; BaseTable *table=nullptr; PhysicalTable *aux_table = nullptr; vector table_types = { ObjectType::Table, ObjectType::ForeignTable, ObjectType::View }; try { xmlparser.getElementAttributes(attribs); for(auto &type : table_types) { table = dynamic_cast(getObject(attribs[Attributes::Table], type)); if(table) break; } if(!table) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Trigger)) .arg(attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } trigger=new Trigger; trigger->setParentTable(table); setBasicAttributes(trigger); trigger->setConstraint(attribs[Attributes::Constraint]==Attributes::True); trigger->setEvent(EventType::OnInsert, (attribs[Attributes::InsEvent]==Attributes::True)); trigger->setEvent(EventType::OnDelete, (attribs[Attributes::DelEvent]==Attributes::True)); trigger->setEvent(EventType::OnUpdate, (attribs[Attributes::UpdEvent]==Attributes::True)); trigger->setEvent(EventType::OnTruncate, (attribs[Attributes::TruncEvent]==Attributes::True)); trigger->setExecutePerRow(attribs[Attributes::PerRow]==Attributes::True); trigger->setFiringType(FiringType(attribs[Attributes::FiringType])); trigger->setTransitionTableName(Trigger::OldTableName, attribs[Attributes::OldTableName]); trigger->setTransitionTableName(Trigger::NewTableName, attribs[Attributes::NewTableName]); list_aux=attribs[Attributes::Arguments].split(','); count=list_aux.count(); for(i=0; i < count; i++) { if(!list_aux[i].isEmpty()) trigger->addArgument(list_aux[i]); } trigger->setDeferrable(attribs[Attributes::Deferrable]==Attributes::True); if(trigger->isDeferrable()) trigger->setDeferralType(attribs[Attributes::DeferType]); if(!attribs[Attributes::RefTable].isEmpty()) { ref_table=getObject(attribs[Attributes::RefTable], ObjectType::Table); if(!ref_table) ref_table=getObject(attribs[Attributes::RefTable], ObjectType::View); //Raises an error if the trigger is referencing a inexistent table if(!ref_table) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(trigger->getName()) .arg(trigger->getTypeName()) .arg(attribs[Attributes::RefTable]) .arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } trigger->setReferecendTable(dynamic_cast(ref_table)); } if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists if(!func && !attribs[Attributes::Signature].isEmpty()) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(trigger->getName()) .arg(trigger->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } trigger->setFunction(dynamic_cast(func)); } else if(elem==Attributes::Condition) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); str_aux=xmlparser.getElementContent(); xmlparser.restorePosition(); trigger->setCondition(str_aux); } else if(elem==Attributes::Columns) { xmlparser.getElementAttributes(attribs); list_aux=attribs[Attributes::Names].split(','); count=list_aux.count(); for(i=0; i < count; i++) { column=dynamic_cast(table->getObject(list_aux[i].trimmed(), ObjectType::Column)); aux_table=dynamic_cast(table); if(!column && aux_table) column=aux_table->getColumn(list_aux[i].trimmed(), true); trigger->addColumn(column); } } } } while(xmlparser.accessElement(XmlParser::NextElement)); } table->addObject(trigger); table->setModified(!loading_model); } catch(Exception &e) { if(trigger) delete(trigger); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(trigger); } Policy *DatabaseModel::createPolicy(void) { attribs_map attribs; Policy *policy=nullptr; QString elem; BaseTable *table=nullptr; try { policy=new Policy; setBasicAttributes(policy); xmlparser.getElementAttributes(attribs); table=dynamic_cast(getObject(attribs[Attributes::Table], ObjectType::Table)); if(!table) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Policy)) .arg(attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); policy->setPermissive(attribs[Attributes::Permissive] == Attributes::True); policy->setPolicyCommand(PolicyCmdType(attribs[Attributes::Command])); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Expression) { xmlparser.getElementAttributes(attribs); xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); if(attribs[Attributes::Type] == Attributes::UsingExp) policy->setUsingExpression(xmlparser.getElementContent()); else if(attribs[Attributes::Type] == Attributes::CheckExp) policy->setCheckExpression(xmlparser.getElementContent()); xmlparser.restorePosition(); } else if(xmlparser.getElementName()==Attributes::Roles) { QStringList rol_names; Role *role = nullptr; xmlparser.getElementAttributes(attribs); rol_names = attribs[Attributes::Names].split(','); for(auto &name : rol_names) { role=dynamic_cast(getObject(name.trimmed(), ObjectType::Role)); //Raises an error if the referenced role doesn't exists if(!role) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(policy->getName()) .arg(policy->getTypeName()) .arg(name) .arg(BaseObject::getTypeName(ObjectType::Role)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } policy->addRole(role); } } } } while(xmlparser.accessElement(XmlParser::NextElement)); } table->addObject(policy); table->setModified(!loading_model); } catch(Exception &e) { if(policy) delete(policy); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(policy); } EventTrigger *DatabaseModel::createEventTrigger(void) { attribs_map attribs; EventTrigger *event_trig=nullptr; BaseObject *func=nullptr; QString elem; try { event_trig=new EventTrigger; setBasicAttributes(event_trig); xmlparser.getElementAttributes(attribs); event_trig->setEvent(EventTriggerType(attribs[Attributes::Event])); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Function) { xmlparser.getElementAttributes(attribs); func=getObject(attribs[Attributes::Signature], ObjectType::Function); //Raises an error if the function doesn't exists if(!func && !attribs[Attributes::Signature].isEmpty()) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(event_trig->getName()) .arg(event_trig->getTypeName()) .arg(attribs[Attributes::Signature]) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } event_trig->setFunction(dynamic_cast(func)); } else if(elem==Attributes::Filter) { xmlparser.getElementAttributes(attribs); event_trig->setFilter(attribs[Attributes::Variable], attribs[Attributes::Values].split(',')); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(event_trig) delete(event_trig); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(event_trig); } GenericSQL *DatabaseModel::createGenericSQL(void) { GenericSQL *genericsql=nullptr; attribs_map attribs; QString elem, parent_name, obj_name; ObjectType obj_type; PhysicalTable *parent_table = nullptr; BaseObject *object = nullptr; try { genericsql = new GenericSQL; setBasicAttributes(genericsql); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem = xmlparser.getElementName(); if(elem == Attributes::Definition) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); genericsql->setDefinition(xmlparser.getElementContent()); xmlparser.restorePosition(); } else if(elem == Attributes::Object) { xmlparser.getElementAttributes(attribs); obj_type = BaseObject::getObjectType(attribs[Attributes::Type]); obj_name = attribs[Attributes::Name]; //If the object is a column its needed to get the parent table if(obj_type == ObjectType::Column) { QStringList names = obj_name.split('.'); if(names.size() > 2) { parent_name = QString("%1.%2").arg(names[0]).arg(names[1]); obj_name = names[2]; } parent_table = dynamic_cast(getObject(parent_name, {ObjectType::Table, ObjectType::ForeignTable})); if(parent_table) object = parent_table->getColumn(obj_name); } else object = getObject(obj_name, obj_type); //Raises an error if the generic object references an object that does not exist if(!object) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(genericsql->getName()) .arg(genericsql->getTypeName()) .arg(obj_name) .arg(BaseObject::getTypeName(obj_type)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); genericsql->addObjectReference(object, attribs[Attributes::RefName], attribs[Attributes::UseSignature] == Attributes::True, attribs[Attributes::FormatName] == Attributes::True); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(genericsql) delete(genericsql); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(genericsql); } ForeignDataWrapper *DatabaseModel::createForeignDataWrapper(void) { attribs_map attribs; ForeignDataWrapper *fdw=nullptr; BaseObject *func=nullptr; QString signature, ref_type; ObjectType obj_type; try { fdw = new ForeignDataWrapper; xmlparser.getElementAttributes(attribs); setBasicAttributes(fdw); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType() == XML_ELEMENT_NODE) { obj_type = BaseObject::getObjectType(xmlparser.getElementName()); if(obj_type == ObjectType::Function) { xmlparser.getElementAttributes(attribs); //Gets the function reference type ref_type = attribs[Attributes::RefType]; //Try to retrieve one the functions of the fdw if(ref_type == Attributes::ValidatorFunc || ref_type == Attributes::HandlerFunc) { //Gets the function signature and tries to retrieve it from the model signature = attribs[Attributes::Signature]; func = getObject(signature, ObjectType::Function); //Raises an error if the function doesn't exists if(!func) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(fdw->getName()) .arg(fdw->getTypeName()) .arg(signature) .arg(BaseObject::getTypeName(ObjectType::Function)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(ref_type == Attributes::ValidatorFunc) fdw->setValidatorFunction(dynamic_cast(func)); else if(ref_type == Attributes::HandlerFunc) fdw->setHandlerFunction(dynamic_cast(func)); } else //Raises an error if the function type is invalid throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(fdw) delete(fdw); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(fdw); } ForeignServer *DatabaseModel::createForeignServer(void) { attribs_map attribs; ForeignServer *server = nullptr; BaseObject *fdw = nullptr; ObjectType obj_type; try { server = new ForeignServer; xmlparser.getElementAttributes(attribs); setBasicAttributes(server); server->setType(attribs[Attributes::Type]); server->setVersion(attribs[Attributes::Version]); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType() == XML_ELEMENT_NODE) { obj_type = BaseObject::getObjectType(xmlparser.getElementName()); if(obj_type == ObjectType::ForeignDataWrapper) { xmlparser.getElementAttributes(attribs); fdw = getObject(attribs[Attributes::Name], ObjectType::ForeignDataWrapper); //Raises an error if the fdw doesn't exists if(!fdw) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(server->getName()) .arg(server->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::ForeignDataWrapper)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); server->setForeignDataWrapper(dynamic_cast(fdw)); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(server) delete(server); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(server); } UserMapping *DatabaseModel::createUserMapping(void) { attribs_map attribs; UserMapping *user_map = nullptr; ForeignServer *server = nullptr; ObjectType obj_type; try { user_map = new UserMapping; xmlparser.getElementAttributes(attribs); setBasicAttributes(user_map); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType() == XML_ELEMENT_NODE) { obj_type = BaseObject::getObjectType(xmlparser.getElementName()); if(obj_type == ObjectType::ForeignServer) { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs); server = dynamic_cast(getObject(attribs[Attributes::Name], ObjectType::ForeignServer)); //Raises an error if the server doesn't exists if(!server) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(user_map->getName()) .arg(user_map->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::ForeignServer)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); user_map->setForeignServer(server); xmlparser.restorePosition(); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(user_map) delete(user_map); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(user_map); } ForeignTable *DatabaseModel::createForeignTable(void) { ForeignTable *ftable = nullptr; try { ForeignServer *fserver = nullptr; attribs_map attribs; ObjectType obj_type; xmlparser.savePosition(); ftable = createPhysicalTable(); xmlparser.restorePosition(); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType() == XML_ELEMENT_NODE) { obj_type = BaseObject::getObjectType(xmlparser.getElementName()); if(obj_type == ObjectType::ForeignServer) { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs); fserver = dynamic_cast(getObject(attribs[Attributes::Name], ObjectType::ForeignServer)); //Raises an error if the server doesn't exists if(!fserver) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(ftable->getName()) .arg(ftable->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::ForeignServer)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); ftable->setForeignServer(fserver); xmlparser.restorePosition(); break; } } } while(xmlparser.accessElement(XmlParser::NextElement)); } return(ftable); } catch(Exception &e) { if(ftable) delete(ftable); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::updateViewsReferencingTable(PhysicalTable *table) { BaseRelationship *rel = nullptr; View *view = nullptr; PhysicalTable *tab = nullptr; if(!table) return; for(auto obj : base_relationships) { rel = dynamic_cast(obj); if(rel->getRelationshipType() != BaseRelationship::RelationshipDep) continue; view = dynamic_cast(rel->getTable(BaseRelationship::SrcTable)); tab = dynamic_cast(rel->getTable(BaseRelationship::DstTable)); if(view && tab == table) { view->generateColumns(); view->setCodeInvalidated(true); view->setModified(true); dynamic_cast(view->getSchema())->setModified(true); } } } Sequence *DatabaseModel::createSequence(bool ignore_onwer) { attribs_map attribs; Sequence *sequence=nullptr; BaseObject *table=nullptr; Column *column=nullptr; QString str_aux, tab_name, col_name; QStringList elem_list; int count; try { sequence=new Sequence; setBasicAttributes(sequence); xmlparser.getElementAttributes(attribs); sequence->setValues(attribs[Attributes::MinValue], attribs[Attributes::MaxValue], attribs[Attributes::Increment], attribs[Attributes::Start], attribs[Attributes::Cache]); sequence->setCycle(attribs[Attributes::Cycle]==Attributes::True); //Getting the sequence's owner column if(!attribs[Attributes::OwnerColumn].isEmpty()) { elem_list=attribs[Attributes::OwnerColumn].split('.'); count=elem_list.count(); if(count==3) { tab_name=elem_list[0] + QString(".") + elem_list[1]; col_name=elem_list[2]; } else if(count==2) { tab_name=elem_list[0]; col_name=elem_list[1]; } table=getObject(tab_name, {ObjectType::Table, ObjectType::ForeignTable}); //Raises an error if the column parent table doesn't exists if(!table) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(sequence->getName()) .arg(BaseObject::getTypeName(ObjectType::Sequence)) .arg(tab_name) .arg(BaseObject::getTypeName(ObjectType::Table)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } column=dynamic_cast(table)->getColumn(col_name); if(!column) column=dynamic_cast(table)->getColumn(col_name, true); //Raises an error if the column doesn't exists if(!column && !ignore_onwer) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInexistentSeqOwnerColumn) .arg(sequence->getName(true)), ErrorCode::AsgInexistentSeqOwnerColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); sequence->setOwnerColumn(column); } } catch(Exception &e) { if(sequence) delete(sequence); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(sequence); } View *DatabaseModel::createView(void) { attribs_map attribs, aux_attribs; View *view=nullptr; Column *column=nullptr; PhysicalTable *table=nullptr; QString elem, str_aux; QStringList list_aux; vector refs; BaseObject *tag=nullptr; unsigned type; int ref_idx, i, count; bool refs_in_expr=false; Reference reference; try { view=new View; setBasicAttributes(view); xmlparser.getElementAttributes(attribs); view->setObjectListsCapacity(attribs[Attributes::MaxObjCount].toUInt()); view->setMaterialized(attribs[Attributes::Materialized]==Attributes::True); view->setRecursive(attribs[Attributes::Recursive]==Attributes::True); view->setWithNoData(attribs[Attributes::WithNoData]==Attributes::True); view->setCollapseMode(attribs[Attributes::CollapseMode].isEmpty() ? CollapseMode::NotCollapsed : static_cast(attribs[Attributes::CollapseMode].toUInt())); view->setPaginationEnabled(attribs[Attributes::Pagination]==Attributes::True); view->setCurrentPage(BaseTable::AttribsSection, attribs[Attributes::AttribsPage].toUInt()); view->setCurrentPage(BaseTable::ExtAttribsSection, attribs[Attributes::ExtAttribsPage].toUInt()); view->setFadedOut(attribs[Attributes::FadedOut]==Attributes::True); view->setLayer(attribs[Attributes::Layer].toUInt()); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Reference) { xmlparser.getElementAttributes(attribs); //If the table name is specified tries to create a reference to a table/column if(!attribs[Attributes::Table].isEmpty()) { column=nullptr; table=dynamic_cast(getObject(attribs[Attributes::Table], {ObjectType::Table, ObjectType::ForeignTable})); //Raises an error if the table doesn't exists if(!table) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(view->getName()) .arg(BaseObject::getTypeName(ObjectType::View)) .arg(attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Table)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } if(!attribs[Attributes::Column].isEmpty()) { column=table->getColumn(attribs[Attributes::Column]); if(!column) column=table->getColumn(attribs[Attributes::Column], true); //Raises an error if the view references an inexistant column if(!column) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(view->getName()) .arg(BaseObject::getTypeName(ObjectType::View)) .arg(attribs[Attributes::Table] + QString(".") + attribs[Attributes::Column]) .arg(BaseObject::getTypeName(ObjectType::Column)); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } //Adds the configured reference to a temporarily list reference = Reference(table, column, attribs[Attributes::Alias], attribs[Attributes::ColumnAlias]); reference.setReferenceAlias(attribs[Attributes::RefAlias]); refs.push_back(reference); } else { xmlparser.savePosition(); str_aux=attribs[Attributes::Alias]; // Retrieving the reference expression xmlparser.accessElement(XmlParser::ChildElement); xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); reference = Reference(xmlparser.getElementContent(), str_aux); reference.setReferenceAlias(attribs[Attributes::RefAlias]); xmlparser.restorePosition(); // Creating the columns related to the expression if(xmlparser.accessElement(XmlParser::NextElement)) { do { elem = xmlparser.getElementName(); xmlparser.savePosition(); if(elem == Attributes::Column) { column = createColumn(); reference.addColumn(column); delete(column); } else if(elem == Attributes::RefTableTag) { xmlparser.getElementAttributes(aux_attribs); table = getTable(aux_attribs[Attributes::Name]); if(!table) table = getForeignTable(aux_attribs[Attributes::Name]); reference.addReferencedTable(table); } xmlparser.restorePosition(); } while(xmlparser.accessElement(XmlParser::NextElement)); } refs.push_back(reference); xmlparser.restorePosition(); } } else if(elem==Attributes::Expression) { xmlparser.savePosition(); xmlparser.getElementAttributes(attribs); xmlparser.accessElement(XmlParser::ChildElement); if(attribs[Attributes::Type]==Attributes::CteExpression) view->setCommomTableExpression(xmlparser.getElementContent()); else { if(attribs[Attributes::Type]==Attributes::SelectExp) type=Reference::SqlReferSelect; else if(attribs[Attributes::Type]==Attributes::FromExp) type=Reference::SqlReferFrom; else if(attribs[Attributes::Type]==Attributes::SimpleExp) type=Reference::SqlReferWhere; else type=Reference::SqlReferEndExpr; list_aux=xmlparser.getElementContent().split(','); count=list_aux.size(); //Indicates that some of the references were used in the expressions if(count > 0 && !refs_in_expr) refs_in_expr=true; for(i=0; i < count; i++) { ref_idx=list_aux[i].toInt(); view->addReference(refs[ref_idx],type); } } xmlparser.restorePosition(); } else if(elem==BaseObject::getSchemaName(ObjectType::Tag)) { xmlparser.getElementAttributes(aux_attribs); tag=getObject(aux_attribs[Attributes::Name] ,ObjectType::Tag); if(!tag) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Table)) .arg(aux_attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Tag)) , ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } view->setTag(dynamic_cast(tag)); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } /** Special case for refereces used as view definition ** If the flag 'refs_in_expr' isn't set indicates that the user defined a reference but has no used to define the view declaration, this way pgModeler will consider these references as View definition expressions and will force the insertion of them as Reference::SQL_VIEW_DEFINITION. This process can raise errors because if the user defined more than one reference the view cannot accept the two as it's SQL definition, also the defined references MUST be expressions in order to be used as view definition */ if(!refs.empty() && !refs_in_expr) { vector::iterator itr; itr=refs.begin(); while(itr!=refs.end()) { view->addReference(*itr, Reference::SqlViewDefinition); itr++; } } } catch(Exception &e) { if(view) delete(view); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(view); } Collation *DatabaseModel::createCollation(void) { Collation *collation=nullptr; BaseObject *copy_coll=nullptr; EncodingType encoding; attribs_map attribs; try { collation=new Collation; setBasicAttributes(collation); xmlparser.getElementAttributes(attribs); encoding=EncodingType(attribs[Attributes::Encoding]); collation->setEncoding(encoding); //Creating a collation from a base locale if(!attribs[Attributes::Locale].isEmpty()) collation->setLocale(attribs[Attributes::Locale]); //Creating a collation from another collation else if(!attribs[Attributes::Collation].isEmpty()) { copy_coll=this->getObject(attribs[Attributes::Collation], ObjectType::Collation); //Raises an error if the copy collation doesn't exists if(!copy_coll) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(collation->getName()) .arg(BaseObject::getTypeName(ObjectType::Collation)) .arg(attribs[Attributes::Collation]) .arg(BaseObject::getTypeName(ObjectType::Collation)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } collation->setCollation(dynamic_cast(copy_coll)); } //Creating a collation using LC_COLLATE and LC_CTYPE params else { collation->setLocalization(Collation::LcCollate, attribs[Attributes::LcCollate]); collation->setLocalization(Collation::LcCtype, attribs[Attributes::LcCtype]); } } catch(Exception &e) { if(collation) delete(collation); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(collation); } Extension *DatabaseModel::createExtension(void) { Extension *extension=nullptr; attribs_map attribs; try { extension=new Extension; xmlparser.getElementAttributes(attribs); setBasicAttributes(extension); extension->setHandlesType(attribs[Attributes::HandlesType]==Attributes::True); extension->setVersion(Extension::CurVersion, attribs[Attributes::CurVersion]); extension->setVersion(Extension::OldVersion, attribs[Attributes::OldVersion]); } catch(Exception &e) { if(extension) delete(extension); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(extension); } Tag *DatabaseModel::createTag(void) { Tag *tag=nullptr; attribs_map attribs; QString elem; try { tag=new Tag; setBasicAttributes(tag); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::Style) { xmlparser.getElementAttributes(attribs); tag->setElementColors(attribs[Attributes::Id],attribs[Attributes::Colors]); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } return(tag); } catch(Exception &e) { if(tag) delete(tag); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } } Textbox *DatabaseModel::createTextbox(void) { Textbox *txtbox=nullptr; attribs_map attribs; try { txtbox=new Textbox; setBasicAttributes(txtbox); xmlparser.getElementAttributes(attribs); txtbox->setFadedOut(attribs[Attributes::FadedOut]==Attributes::True); txtbox->setLayer(attribs[Attributes::Layer].toUInt()); txtbox->setTextAttribute(Textbox::ItalicText, attribs[Attributes::Italic]==Attributes::True); txtbox->setTextAttribute(Textbox::BoldText, attribs[Attributes::Bold]==Attributes::True); txtbox->setTextAttribute(Textbox::UnderlineText, attribs[Attributes::Underline]==Attributes::True); if(!attribs[Attributes::Color].isEmpty()) txtbox->setTextColor(QColor(attribs[Attributes::Color])); if(!attribs[Attributes::FontSize].isEmpty()) txtbox->setFontSize(attribs[Attributes::FontSize].toDouble()); } catch(Exception &e) { if(txtbox) delete(txtbox); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(txtbox); } BaseRelationship *DatabaseModel::createRelationship(void) { vector cols_special_pk; attribs_map attribs, constr_attribs; map labels_id; BaseRelationship *base_rel=nullptr; Relationship *rel=nullptr; BaseTable *tables[2]={nullptr, nullptr}; bool src_mand, dst_mand, identifier, protect, deferrable, sql_disabled, single_pk_col, faded_out; DeferralType defer_type; ActionType del_action, upd_action; unsigned rel_type=0, i = 0, layer = 0; ObjectType table_types[2]={ ObjectType::View, ObjectType::Table }, obj_rel_type; QString str_aux, elem, tab_attribs[2]={ Attributes::SrcTable, Attributes::DstTable }; QColor custom_color=Qt::transparent; Table *table = nullptr; try { labels_id[Attributes::NameLabel]=BaseRelationship::RelNameLabel; labels_id[Attributes::SrcLabel]=BaseRelationship::SrcCardLabel; labels_id[Attributes::DstLabel]=BaseRelationship::DstCardLabel; xmlparser.getElementAttributes(attribs); protect=(attribs[Attributes::Protected]==Attributes::True); faded_out=(attribs[Attributes::FadedOut]==Attributes::True); layer = attribs[Attributes::Layer].toUInt(); if(!attribs[Attributes::CustomColor].isEmpty()) custom_color=QColor(attribs[Attributes::CustomColor]); if(attribs[Attributes::Type]!=Attributes::RelationshipTabView && attribs[Attributes::Type]!=Attributes::RelationshipFk) { table_types[0]=ObjectType::Table; obj_rel_type=ObjectType::Relationship; } else { if(attribs[Attributes::Type]==Attributes::RelationshipFk) table_types[0]=ObjectType::Table; obj_rel_type=ObjectType::BaseRelationship; } //Gets the participant tables for(i=0; i < 2; i++) { tables[i]=dynamic_cast(getObject(attribs[tab_attribs[i]], table_types[i])); /* If the relationship is between a view and a table and the table is not found * we try to find a foreign table instead */ if(table_types[i] == ObjectType::Table && !tables[i]) tables[i]=dynamic_cast(getObject(attribs[tab_attribs[i]], ObjectType::ForeignTable)); //Raises an error if some table doesn't exists if(!tables[i]) { str_aux=Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(obj_rel_type)) .arg(attribs[tab_attribs[i]]) .arg(BaseObject::getTypeName(table_types[i])); throw Exception(str_aux,ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } if(obj_rel_type==ObjectType::BaseRelationship) { base_rel=getRelationship(tables[0], tables[1]); /* Creates the fk relationship if it not exists. This generally happens when a foreign key is added to the table after its creation. */ if(attribs[Attributes::Type]==Attributes::RelationshipFk) { base_rel=new BaseRelationship(BaseRelationship::RelationshipFk, tables[0], tables[1], false, false); base_rel->setName(attribs[Attributes::Name]); base_rel->setAlias(attribs[Attributes::Alias]); addRelationship(base_rel); /* If the source table doesn't have any fk that references the destination table indicates that the relationship is being created before the fk that represents it or the fk is invalid (inconsistence!). In this case an error is raised. */ if(base_rel->getRelationshipType() == BaseRelationship::RelationshipFk && !base_rel->getReferenceForeignKey()) { Table *src_tab = dynamic_cast
(base_rel->getTable(BaseRelationship::SrcTable)), *dst_tab = dynamic_cast
(base_rel->getTable(BaseRelationship::DstTable)); vector fks; src_tab->getForeignKeys(fks, false, dst_tab); for(auto fk : fks) { if(!getRelationship(src_tab, dst_tab, fk)) { base_rel->setReferenceForeignKey(fk); break; } } //Throws an error if the relationship was created without a valid foreign key attached to it if(!base_rel->getReferenceForeignKey()) { throw Exception(Exception::getErrorMessage(ErrorCode::InvAllocationFKRelationship) .arg(attribs[Attributes::Name]) .arg(src_tab->getName(true)), ErrorCode::InvAllocationFKRelationship,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } else if(base_rel) base_rel->setName(attribs[Attributes::Name]); if(!base_rel) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(this->getName()) .arg(this->getTypeName()) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::BaseRelationship)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); base_rel->blockSignals(loading_model); base_rel->disconnectRelationship(); base_rel->blockSignals(false); } else { QString pat_attrib[]= { Attributes::SrcColPattern, Attributes::DstColPattern, Attributes::SrcFkPattern, Attributes::DstFkPattern, Attributes::PkPattern, Attributes::UqPattern, Attributes::PkColPattern }; unsigned pattern_id[]= { Relationship::SrcColPattern, Relationship::DstColPattern, Relationship::SrcFkPattern, Relationship::DstFkPattern, Relationship::PkPattern, Relationship::UqPattern, Relationship::PkColPattern }, pat_count=sizeof(pattern_id)/sizeof(unsigned); sql_disabled=attribs[Attributes::SqlDisabled]==Attributes::True; src_mand=attribs[Attributes::SrcRequired]==Attributes::True; dst_mand=attribs[Attributes::DstRequired]==Attributes::True; identifier=attribs[Attributes::Identifier]==Attributes::True; deferrable=attribs[Attributes::Deferrable]==Attributes::True; defer_type=DeferralType(attribs[Attributes::DeferType]); del_action=ActionType(attribs[Attributes::DelAction]); upd_action=ActionType(attribs[Attributes::UpdAction]); single_pk_col=(attribs[Attributes::SinglePkColumn]==Attributes::True); if(attribs[Attributes::Type]==Attributes::Relationship11) rel_type=BaseRelationship::Relationship11; else if(attribs[Attributes::Type]==Attributes::Relationship1n) rel_type=BaseRelationship::Relationship1n; else if(attribs[Attributes::Type]==Attributes::RelationshipNn) rel_type=BaseRelationship::RelationshipNn; else if(attribs[Attributes::Type]==Attributes::RelationshipGen) rel_type=BaseRelationship::RelationshipGen; else if(attribs[Attributes::Type]==Attributes::RelationshipDep) rel_type=BaseRelationship::RelationshipDep; else if(attribs[Attributes::Type]==Attributes::RelationshipPart) rel_type=BaseRelationship::RelationshipPart; rel=new Relationship(rel_type, dynamic_cast(tables[0]), dynamic_cast(tables[1]), src_mand, dst_mand, identifier, deferrable, defer_type, del_action, upd_action, CopyOptions(attribs[Attributes::CopyMode].toUInt(), attribs[Attributes::CopyOptions].toUInt())); rel->setSQLDisabled(sql_disabled); rel->setSiglePKColumn(single_pk_col); if(!attribs[Attributes::TableName].isEmpty()) rel->setTableNameRelNN(attribs[Attributes::TableName]); rel->setName(attribs[Attributes::Name]); rel->setAlias(attribs[Attributes::Alias]); base_rel=rel; //Configuring the name patterns for(i=0; i < pat_count; i++) rel->setNamePattern(pattern_id[i], attribs[pat_attrib[i]]); } if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem == Attributes::Expression && rel) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); rel->setPartitionBoundingExpr(xmlparser.getElementContent()); xmlparser.restorePosition(); } else if(elem==Attributes::Column && rel) { xmlparser.savePosition(); rel->addObject(createColumn()); xmlparser.restorePosition(); } else if(elem==Attributes::Constraint && rel) { xmlparser.savePosition(); xmlparser.getElementAttributes(constr_attribs); /* If we find a primary key constraint at this point means that we're handling the original primary key stored by the relationship. * Since relationships can't have primary keys created manually by the users we assume that * the relationship contains a special primary key (created during relationship connection) * and the current constraint is the original one owned by one of the tables prior the connection * of the relationship. */ if(constr_attribs[Attributes::Type] == Attributes::PkConstr) { table = getTable(constr_attribs[Attributes::Table]); rel->setOriginalPrimaryKey(createConstraint(table)); } else rel->addObject(createConstraint(rel)); xmlparser.restorePosition(); } else if(elem==Attributes::Line) { vector points; xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); do { xmlparser.getElementAttributes(attribs); points.push_back(QPointF(attribs[Attributes::XPos].toDouble(), attribs[Attributes::YPos].toDouble())); } while(xmlparser.accessElement(XmlParser::NextElement)); base_rel->setPoints(points); xmlparser.restorePosition(); } else if(elem==Attributes::Label) { xmlparser.getElementAttributes(attribs); str_aux=attribs[Attributes::RefType]; xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); xmlparser.getElementAttributes(attribs); xmlparser.restorePosition(); base_rel->setLabelDistance(labels_id[str_aux], QPointF(attribs[Attributes::XPos].toDouble(), attribs[Attributes::YPos].toDouble())); } else if(elem==Attributes::SpecialPkCols && rel) { QList col_list; xmlparser.getElementAttributes(attribs); col_list=attribs[Attributes::Indexes].split(','); while(!col_list.isEmpty()) { cols_special_pk.push_back(col_list.front().toUInt()); col_list.pop_front(); } rel->setSpecialPrimaryKeyCols(cols_special_pk); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { if(base_rel && base_rel->getObjectType()==ObjectType::Relationship) delete(base_rel); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } if(rel) { storeSpecialObjectsXML(); addRelationship(rel); } base_rel->setFadedOut(faded_out); base_rel->setProtected(protect); base_rel->setCustomColor(custom_color); base_rel->setLayer(layer); /* If the FK relationship does not reference a foreign key (models generated in older versions) * we need to assign them to the respective relationships */ if(base_rel && base_rel->getObjectType()==ObjectType::BaseRelationship) { base_rel->blockSignals(loading_model); base_rel->connectRelationship(); base_rel->blockSignals(false); } return(base_rel); } Permission *DatabaseModel::createPermission(void) { Permission *perm=nullptr; BaseObject *object=nullptr; PhysicalTable *parent_table=nullptr; Role *role=nullptr; attribs_map priv_attribs, attribs; attribs_map::iterator itr, itr_end; ObjectType obj_type; QString parent_name, obj_name; QStringList list; unsigned priv_type=Permission::PrivSelect; bool priv_value, grant_op, revoke, cascade; try { xmlparser.getElementAttributes(priv_attribs); revoke=priv_attribs[Attributes::Revoke]==Attributes::True; cascade=priv_attribs[Attributes::Cascade]==Attributes::True; xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); xmlparser.getElementAttributes(attribs); obj_type=BaseObject::getObjectType(attribs[Attributes::Type]); obj_name=attribs[Attributes::Name]; parent_name=attribs[Attributes::Parent]; //If the object is a column its needed to get the parent table if(obj_type==ObjectType::Column) { parent_table=dynamic_cast(getObject(parent_name, {ObjectType::Table, ObjectType::ForeignTable})); if(parent_table) object=parent_table->getColumn(obj_name); } else if(obj_type==ObjectType::Database) { object=this; } else object=getObject(obj_name, obj_type); //Raises an error if the permission references an object that does not exists if(!object) throw Exception(Exception::getErrorMessage(ErrorCode::PermissionRefInexistObject) .arg(obj_name) .arg(BaseObject::getTypeName(obj_type)), ErrorCode::PermissionRefInexistObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); perm=new Permission(object); perm->setRevoke(revoke); perm->setCascade(cascade); do { if(xmlparser.getElementName()==Attributes::Roles) { xmlparser.getElementAttributes(attribs); list = attribs[Attributes::Names].split(','); for(auto &name : list) { role=dynamic_cast(getObject(name.trimmed(), ObjectType::Role)); //Raises an error if the referenced role doesn't exists if(!role) { throw Exception(Exception::getErrorMessage(ErrorCode::PermissionRefInexistObject) .arg(name) .arg(BaseObject::getTypeName(ObjectType::Role)), ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } perm->addRole(role); } } else if(xmlparser.getElementName()==Attributes::Privileges) { xmlparser.getElementAttributes(priv_attribs); itr=priv_attribs.begin(); itr_end=priv_attribs.end(); while(itr!=itr_end) { if(itr->first!=Attributes::GrantOp) { priv_value=(itr->second==Attributes::True); grant_op=(itr->second==Attributes::GrantOp); if(itr->first==Attributes::ConnectPriv) priv_type=Permission::PrivConnect; else if(itr->first==Attributes::CreatePriv) priv_type=Permission::PrivCreate; else if(itr->first==Attributes::DeletePriv) priv_type=Permission::PrivDelete; else if(itr->first==Attributes::ExecutPriv) priv_type=Permission::PrivExecute; else if(itr->first==Attributes::InsertPriv) priv_type=Permission::PrivInsert; else if(itr->first==Attributes::ReferencesPriv) priv_type=Permission::PrivReferences; else if(itr->first==Attributes::SelectPriv) priv_type=Permission::PrivSelect; else if(itr->first==Attributes::TemporaryPriv) priv_type=Permission::PrivTemporary; else if(itr->first==Attributes::TriggerPriv) priv_type=Permission::PrivTrigger; else if(itr->first==Attributes::TruncatePriv) priv_type=Permission::PrivTruncate; else if(itr->first==Attributes::UpdatePriv) priv_type=Permission::PrivUpdate; else if(itr->first==Attributes::UsagePriv) priv_type=Permission::PrivUsage; perm->setPrivilege(priv_type, (priv_value || grant_op), grant_op); } itr++; } } } while(xmlparser.accessElement(XmlParser::NextElement)); xmlparser.restorePosition(); } catch(Exception &e) { if(perm) delete(perm); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, getErrorExtraInfo()); } return(perm); } void DatabaseModel::validateColumnRemoval(Column *column) { if(column && column->getParentTable()) { vector refs; getObjectReferences(column, refs); //Raises an error if there are objects referencing the column if(!refs.empty()) throw Exception(Exception::getErrorMessage(ErrorCode::RemDirectReference) .arg(column->getParentTable()->getName(true) + QString(".") + column->getName(true)) .arg(column->getTypeName()) .arg(refs[0]->getName(true)) .arg(refs[0]->getTypeName()), ErrorCode::RemDirectReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } void DatabaseModel::validateRelationships(TableObject *object, Table *parent_tab) { try { bool revalidate_rels=false, ref_tab_inheritance=false; Relationship *rel=nullptr; vector::iterator itr, itr_end; ObjectType obj_type; if(object && parent_tab) { obj_type=object->getObjectType(); /* Relationship validation condition: > Case the object is a column and its reference by the parent table primary key > Case the parent table is a partition and a column is being removed > Case the object is a constraint and its a table primary key */ revalidate_rels=((obj_type==ObjectType::Column && (parent_tab->isConstraintRefColumn(dynamic_cast(object), ConstraintType::PrimaryKey) || parent_tab->isPartition() || parent_tab->isPartitioned())) || (obj_type==ObjectType::Constraint && dynamic_cast(object)->getConstraintType()==ConstraintType::PrimaryKey)); /* Additional validation for columns: checks if the parent table participates on a generalization/copy as destination table */ if(obj_type==ObjectType::Column) { itr=relationships.begin(); itr_end=relationships.end(); while(itr!=itr_end && !ref_tab_inheritance) { rel=dynamic_cast(*itr); itr++; ref_tab_inheritance=(rel->getRelationshipType()==Relationship::RelationshipGen && rel->getReferenceTable()==parent_tab); } } if(revalidate_rels || ref_tab_inheritance) { storeSpecialObjectsXML(); disconnectRelationships(); validateRelationships(); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString DatabaseModel::__getCodeDefinition(unsigned def_type) { QString def, bkp_appended_sql, bkp_prepended_sql; //Forcing the name/signature cleanup due to the validation temp. names feature attributes[Attributes::Name]=QString(); attributes[Attributes::Signature]=QString(); if(conn_limit >= 0) attributes[Attributes::ConnLimit]=QString("%1").arg(conn_limit); if(def_type==SchemaParser::SqlDefinition) { QString loc_attribs[]={ Attributes::LcCtype, Attributes::LcCollate }; if(encoding!=BaseType::Null) attributes[Attributes::Encoding]=QString("'%1'").arg(~encoding); for(unsigned i=0; i < 2; i++) { if(!localizations[i].isEmpty()) { attributes[loc_attribs[i]]=QString("'%1'").arg(localizations[i]); } } } else { attributes[Attributes::Encoding]=(~encoding); attributes[Attributes::LcCollate]=localizations[1]; attributes[Attributes::LcCtype]=localizations[0]; attributes[Attributes::AppendAtEod]=(append_at_eod ? Attributes::True : QString()); attributes[Attributes::PrependAtBod]=(prepend_at_bod ? Attributes::True : QString()); } attributes[Attributes::IsTemplate]=(is_template ? Attributes::True : Attributes::False); attributes[Attributes::AllowConns]=(allow_conns ? Attributes::True : Attributes::False); attributes[Attributes::TemplateDb]=template_db; if(def_type==SchemaParser::SqlDefinition && append_at_eod) { bkp_appended_sql=this->appended_sql; this->appended_sql.clear(); } if(def_type==SchemaParser::SqlDefinition && prepend_at_bod) { bkp_prepended_sql=this->prepended_sql; this->prepended_sql.clear(); } try { def=this->BaseObject::__getCodeDefinition(def_type); if(def_type==SchemaParser::SqlDefinition && append_at_eod) this->appended_sql=bkp_appended_sql; if(def_type==SchemaParser::SqlDefinition && prepend_at_bod) this->prepended_sql=bkp_prepended_sql; return(def); } catch(Exception &e) { this->appended_sql=bkp_appended_sql; this->prepended_sql=bkp_prepended_sql; throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString DatabaseModel::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, true)); } QString DatabaseModel::getCodeDefinition(unsigned def_type, bool export_file) { attribs_map attribs_aux; unsigned general_obj_cnt, gen_defs_count; bool sql_disabled=false; BaseObject *object=nullptr; QString def, search_path=QString("pg_catalog,public"), msg=trUtf8("Generating %1 code: `%2' (%3)"), attrib=Attributes::Objects, attrib_aux, def_type_str=(def_type==SchemaParser::SqlDefinition ? QString("SQL") : QString("XML")); Type *usr_type=nullptr; map objects_map; ObjectType obj_type; try { objects_map=getCreationOrder(def_type); general_obj_cnt=objects_map.size(); gen_defs_count=0; attribs_aux[Attributes::ShellTypes]=QString(); attribs_aux[Attributes::Permission]=QString(); attribs_aux[Attributes::Schema]=QString(); attribs_aux[Attributes::Tablespace]=QString(); attribs_aux[Attributes::Role]=QString(); if(def_type==SchemaParser::SqlDefinition) { attribs_aux[Attributes::Function]=(!functions.empty() ? Attributes::True : QString()); for(auto &type : types) { usr_type=dynamic_cast(type); if(usr_type->getConfiguration()==Type::BaseType) usr_type->convertFunctionParameters(); } } for(auto &obj_itr : objects_map) { object=obj_itr.second; obj_type=object->getObjectType(); if(obj_type==ObjectType::Type && def_type==SchemaParser::SqlDefinition) { usr_type=dynamic_cast(object); //Generating the shell type declaration (only for base types) if(usr_type->getConfiguration()==Type::BaseType) attribs_aux[Attributes::ShellTypes]+=usr_type->getCodeDefinition(def_type, true); else attribs_aux[attrib]+=usr_type->getCodeDefinition(def_type); } else if(obj_type==ObjectType::Database) { if(def_type==SchemaParser::SqlDefinition) { /* The Database has the SQL code definition disabled when generating the code of the entire model because this object cannot be created from a multiline sql command */ //Saving the sql disabled state sql_disabled=this->isSQLDisabled(); //Disables the sql to generate a commented code this->setSQLDisabled(true); attribs_aux[this->getSchemaName()]+=this->__getCodeDefinition(def_type); //Restore the original sql disabled state this->setSQLDisabled(sql_disabled); } else attribs_aux[attrib]+=this->__getCodeDefinition(def_type); } else if(obj_type==ObjectType::Permission) { attribs_aux[Attributes::Permission]+=dynamic_cast(object)->getCodeDefinition(def_type); } else if(obj_type==ObjectType::Constraint) { attribs_aux[attrib]+=dynamic_cast(object)->getCodeDefinition(def_type, true); } else if(obj_type==ObjectType::Role || obj_type==ObjectType::Tablespace || obj_type==ObjectType::Schema) { //The "public" schema does not have the SQL code definition generated if(def_type==SchemaParser::SqlDefinition) attrib_aux=BaseObject::getSchemaName(obj_type); else attrib_aux=attrib; /* The Tablespace has the SQL code definition disabled when generating the code of the entire model because this object cannot be created from a multiline sql command */ if(obj_type==ObjectType::Tablespace && !object->isSystemObject() && def_type==SchemaParser::SqlDefinition) { //Saving the sql disabled state sql_disabled=object->isSQLDisabled(); //Disables the sql to generate a commented code object->setSQLDisabled(true); attribs_aux[attrib_aux]+=object->getCodeDefinition(def_type); //Restore the original sql disabled state object->setSQLDisabled(sql_disabled); } //System object doesn't has the XML generated (the only exception is for public schema) else if((obj_type!=ObjectType::Schema && !object->isSystemObject()) || (obj_type==ObjectType::Schema && ((object->getName()==QString("public") && def_type==SchemaParser::XmlDefinition) || (object->getName()!=QString("public") && object->getName()!=QString("pg_catalog"))))) { if(object->getObjectType()==ObjectType::Schema) search_path+=QString(",") + object->getName(true); //Generates the code definition and concatenates to the others attribs_aux[attrib_aux]+=object->getCodeDefinition(def_type); } } else { if(object->isSystemObject()) attribs_aux[attrib]+=QString(); else attribs_aux[attrib]+=object->getCodeDefinition(def_type); } gen_defs_count++; if((def_type==SchemaParser::SqlDefinition && !object->isSQLDisabled()) || (def_type==SchemaParser::XmlDefinition && !object->isSystemObject())) { emit s_objectLoaded((gen_defs_count/static_cast(general_obj_cnt)) * 100, msg.arg(def_type_str) .arg(object->getName()) .arg(object->getTypeName()), enum_cast(object->getObjectType())); } } attribs_aux[Attributes::SearchPath]=search_path; attribs_aux[Attributes::ModelAuthor]=author; attribs_aux[Attributes::PgModelerVersion]=GlobalAttributes::PgModelerVersion; if(def_type==SchemaParser::XmlDefinition) { QStringList act_layers; for(auto &layer_id : active_layers) act_layers.push_back(QString::number(layer_id)); attribs_aux[Attributes::Layers]=layers.join(';'); attribs_aux[Attributes::ActiveLayers]=act_layers.join(';'); attribs_aux[Attributes::MaxObjCount]=QString::number(static_cast(getMaxObjectCount() * 1.20)); attribs_aux[Attributes::Protected]=(this->is_protected ? Attributes::True : QString()); attribs_aux[Attributes::LastPosition]=QString("%1,%2").arg(last_pos.x()).arg(last_pos.y()); attribs_aux[Attributes::LastZoom]=QString::number(last_zoom); attribs_aux[Attributes::DefaultSchema]=(default_objs[ObjectType::Schema] ? default_objs[ObjectType::Schema]->getName(true) : QString()); attribs_aux[Attributes::DefaultOwner]=(default_objs[ObjectType::Role] ? default_objs[ObjectType::Role]->getName(true) : QString()); attribs_aux[Attributes::DefaultTablespace]=(default_objs[ObjectType::Tablespace] ? default_objs[ObjectType::Tablespace]->getName(true) : QString()); attribs_aux[Attributes::DefaultCollation]=(default_objs[ObjectType::Collation] ? default_objs[ObjectType::Collation]->getName(true) : QString()); } else { for(auto &type : types) { usr_type=dynamic_cast(type); if(usr_type->getConfiguration()==Type::BaseType) { attribs_aux[attrib]+=usr_type->getCodeDefinition(def_type); usr_type->convertFunctionParameters(true); } } } } catch(Exception &e) { if(def_type==SchemaParser::SqlDefinition) { for(auto &type : types) { usr_type=dynamic_cast(type); if(usr_type->getConfiguration()==Type::BaseType) { attribs_aux[attrib]+=usr_type->getCodeDefinition(def_type); usr_type->convertFunctionParameters(true); } } } throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } attribs_aux[Attributes::ExportToFile]=(export_file ? Attributes::True : QString()); def=schparser.getCodeDefinition(Attributes::DbModel, attribs_aux, def_type); if(prepend_at_bod && def_type==SchemaParser::SqlDefinition) def=QString("-- Prepended SQL commands --\n") + this->prepended_sql + Attributes::DdlEndToken + def; if(append_at_eod && def_type==SchemaParser::SqlDefinition) def+=QString("-- Appended SQL commands --\n") + this->appended_sql + QChar('\n') + Attributes::DdlEndToken; return(def); } map DatabaseModel::getCreationOrder(unsigned def_type, bool incl_relnn_objs, bool incl_rel1n_constrs) { BaseObject *object=nullptr; vector fkeys, fk_rels, aux_tables; vector *obj_list=nullptr; vector::iterator itr, itr_end; map objects_map; PhysicalTable *table=nullptr; Constraint *constr=nullptr; View *view=nullptr; Relationship *rel=nullptr; ObjectType aux_obj_types[]={ ObjectType::Role, ObjectType::Tablespace, ObjectType::Schema, ObjectType::Tag }; vector obj_types_vect = getObjectTypes(false, { ObjectType::Role, ObjectType::Tablespace, ObjectType::Schema, ObjectType::Tag, ObjectType::Database, ObjectType::Permission }); unsigned i=0, aux_obj_cnt=sizeof(aux_obj_types)/sizeof(ObjectType); //The first objects on the map will be roles, tablespaces, schemas and tags for(i=0; i < aux_obj_cnt; i++) { if(aux_obj_types[i]!=ObjectType::Tag || def_type==SchemaParser::XmlDefinition) { obj_list=getObjectList(aux_obj_types[i]); for(auto &object : (*obj_list)) objects_map[object->getObjectId()]=object; } } //Includes the database model on the objects map permitting to create the code in a correct order objects_map[this->getObjectId()]=this; for(auto &obj_type : obj_types_vect) { //For SQL definition, only the textbox and base relationship does not enters to the code generation list if(def_type==SchemaParser::SqlDefinition && (obj_type==ObjectType::Textbox || obj_type==ObjectType::BaseRelationship)) obj_list=nullptr; else obj_list=getObjectList(obj_type); if(obj_list) { for(auto &object : (*obj_list)) { /* If the object is a FK relationship it's stored in a separeted list in order to have the code generated at end of whole definition (after foreign keys definition) */ if(object->getObjectType()==ObjectType::BaseRelationship && dynamic_cast(object)->getRelationshipType()==BaseRelationship::RelationshipFk) { fk_rels.push_back(object); } else { if(def_type==SchemaParser::XmlDefinition || !incl_relnn_objs) objects_map[object->getObjectId()]=object; else { rel=dynamic_cast(object); /* Avoiding many-to-many relationships to be included in the map. They are treated in a separated way below, because on the diff process (ModelsDiffHelper) the generated table need to be compared to other tables not the relationship itself */ if(!incl_relnn_objs || !rel || (rel && rel->getRelationshipType()!=BaseRelationship::RelationshipNn)) objects_map[object->getObjectId()]=object; } } } } } /* Getting and storing the special objects (which reference columns of tables added for relationships) on the map of objects. */ aux_tables = tables; aux_tables.insert(aux_tables.end(), foreign_tables.begin(), foreign_tables.end()); for(auto &obj : aux_tables) { table = dynamic_cast(obj); for(auto &obj : *table->getObjectList(ObjectType::Constraint)) { //table->getConstraint(i); constr = dynamic_cast(obj); /* Case the constraint is a special object stores it on the objects map. Independently to the configuration, foreign keys are discarded in this iteration because on the end of the method they have the definition generated */ if(constr->getConstraintType()!=ConstraintType::ForeignKey && !constr->isAddedByLinking() && ((constr->getConstraintType()!=ConstraintType::PrimaryKey && constr->isReferRelationshipAddedColumn()))) objects_map[constr->getObjectId()]=constr; else if(constr->getConstraintType()==ConstraintType::ForeignKey && !constr->isAddedByLinking()) fkeys.push_back(constr); } for(auto obj : table->getObjects({ ObjectType::Column, ObjectType::Constraint })) objects_map[obj->getObjectId()]=obj; } /* Getting and storing the special objects (which reference columns of tables added for relationships) on the map of objects. */ for(auto &obj : views) { view=dynamic_cast(obj); for(auto obj : view->getObjects()) objects_map[obj->getObjectId()]=obj; } /* SPECIAL CASE: Generating the correct order for tables, views, relationships and sequences This generation is made in the following way: 1) Based on the relationship list, participant tables comes before the relationship itself. 2) Other tables came after the objects on the step 1. 3) The sequences must have their code generated after the tables 4) View are the last objects in the list avoiding table/column reference breaking */ if(def_type==SchemaParser::SqlDefinition) { BaseObject *objs[3]={nullptr, nullptr, nullptr}; vector vet_aux, rel_constrs; vet_aux=relationships; vet_aux.insert(vet_aux.end(), tables.begin(),tables.end()); vet_aux.insert(vet_aux.end(), foreign_tables.begin(),foreign_tables.end()); vet_aux.insert(vet_aux.end(), sequences.begin(),sequences.end()); vet_aux.insert(vet_aux.end(), views.begin(),views.end());; itr=vet_aux.begin(); itr_end=vet_aux.end(); while(itr!=itr_end) { object=(*itr); itr++; if(object->getObjectType()==ObjectType::Relationship) { rel=dynamic_cast(object); objs[0]=rel->getTable(Relationship::SrcTable); objs[1]=rel->getTable(Relationship::DstTable); /* For many-to-many relationship, the generated table and the foreign keys that represents the link are included on the creation order map instead of the relationship itself. This is done to permit the table to be accessed and compared on the diff process */ if(incl_relnn_objs && rel->getRelationshipType()==BaseRelationship::RelationshipNn && rel->getGeneratedTable()) { table=rel->getGeneratedTable(); objs[2]=table; for(BaseObject *tab_obj : *table->getObjectList(ObjectType::Constraint)) { constr=dynamic_cast(tab_obj); if(constr->getConstraintType()==ConstraintType::ForeignKey) fkeys.push_back(constr); } } else if(incl_rel1n_constrs) { vector constrs=rel->getGeneratedConstraints(); for(auto &constr : constrs) { if(constr->getConstraintType()!=ConstraintType::PrimaryKey) rel_constrs.push_back(constr); } } else objs[2]=rel; for(i=0; i < 3; i++) { if(objs[i] && objects_map.count(objs[i]->getObjectId())==0) objects_map[objs[i]->getObjectId()]=objs[i]; } } else { if(objects_map.count(object->getObjectId())==0) objects_map[object->getObjectId()]=object; } } fkeys.insert(fkeys.end(), rel_constrs.begin(), rel_constrs.end()); } //Adding fk relationships and foreign keys at end of objects map i=BaseObject::getGlobalId() + 1; fkeys.insert(fkeys.end(), fk_rels.begin(), fk_rels.end()); for(auto &obj : fkeys) { objects_map[i]=obj; i++; } //Adding permissions at the very end of object map i=BaseObject::getGlobalId() + fkeys.size() + 1; for(auto &obj : permissions) { objects_map[i]=obj; i++; } return(objects_map); } void DatabaseModel::__getObjectDependencies(BaseObject *object, vector &objs) { vector dep_objs, chld_objs; PhysicalTable *table=dynamic_cast(object); ObjectType obj_type=ObjectType::BaseObject; if(!object) return; getObjectDependecies(object, objs, true); obj_type=object->getObjectType(); //If the object is a table include as dependency the copy table as well any ancestor table if(table) { //Including copy table and its dependencies if(table->getCopyTable()) { __getObjectDependencies(table->getCopyTable(), dep_objs); objs.insert(objs.end(), dep_objs.begin(), dep_objs.end()); } //Including ancestor tables and their dependencies dep_objs.clear(); for(unsigned i=0; i < table->getAncestorTableCount(); i++) { __getObjectDependencies(table->getAncestorTable(i), dep_objs); objs.insert(objs.end(), dep_objs.begin(), dep_objs.end()); } } //If there is the need to include the children objects if(BaseTable::isBaseTable(obj_type) || obj_type==ObjectType::Schema) { vector::iterator end; if(obj_type==ObjectType::Schema) { //Retrieve all objects that belongs to the schema chld_objs=getObjects(object); objs.insert(objs.end(), chld_objs.begin(), chld_objs.end()); for(BaseObject *aux_obj : chld_objs) { __getObjectDependencies(aux_obj, dep_objs); objs.insert(objs.end(), dep_objs.begin(), dep_objs.end()); } } else { BaseTable *tab=dynamic_cast(object); Constraint *constr=nullptr; chld_objs=tab->getObjects(); for(BaseObject *child : chld_objs) { constr=dynamic_cast(child); /* Columns are discarded but constraint included only if they are included by relationship or foreign keys in which referenced table resides in the same schema as their parent tables */ if((!constr && child->getObjectType()!=ObjectType::Column) || (constr && ((constr->getConstraintType()==ConstraintType::ForeignKey) || (constr->getConstraintType()!=ConstraintType::ForeignKey && constr->getConstraintType()!=ConstraintType::PrimaryKey && constr->isReferRelationshipAddedColumn())))) { __getObjectDependencies(child, objs); if(constr && constr->getReferencedTable() && std::find(objs.begin(), objs.end(), constr->getReferencedTable())==objs.end()) __getObjectDependencies(constr->getReferencedTable(), objs); } } } //Cleaning up the resulting list removing duplicate elements std::sort(objs.begin(), objs.end()); end=std::unique(objs.begin(), objs.end()); objs.erase(end, objs.end()); } } vector DatabaseModel::getCreationOrder(BaseObject *object, bool only_children) { if(!object) return(vector()); map objs_map; vector objs, children; vector perms_aux, perms; vector roles; PhysicalTable *table=nullptr; Relationship *rel=nullptr; ObjectType obj_type=object->getObjectType(); if(only_children) objs.push_back(object); else __getObjectDependencies(object, objs); /* Include tables generated by many-to-many relationships if their schemas are the same as the 'object' when this one is a schema too */ if(obj_type==ObjectType::Schema) { if(only_children) { children=getObjects(object); objs.insert(objs.end(), children.begin(), children.end()); } for(BaseObject *obj : relationships) { rel=dynamic_cast(obj); if(rel->getRelationshipType()==Relationship::RelationshipNn && rel->getGeneratedTable() && rel->getGeneratedTable()->getSchema()==object) { if(only_children) objs.push_back(rel->getGeneratedTable()); else __getObjectDependencies(rel->getGeneratedTable(), objs); } } } if(only_children) { BaseTable *table=nullptr; Constraint *constr=nullptr; vector objs_aux; for(BaseObject *obj : objs) { table=dynamic_cast(obj); if(table) { children=table->getObjects(); for(BaseObject *child : children) { constr=dynamic_cast(child); if((!constr && child->getObjectType()!=ObjectType::Column) || (constr && ((constr->getConstraintType()==ConstraintType::ForeignKey) || (constr->getConstraintType()!=ConstraintType::ForeignKey && constr->getConstraintType()!=ConstraintType::PrimaryKey && constr->isReferRelationshipAddedColumn())))) { objs_aux.push_back(child); } } } } objs.insert(objs.end(), objs_aux.begin(), objs_aux.end()); } else { //Retrieving all permission related to the gathered objects for(BaseObject *obj : objs) { getPermissions(obj, perms_aux); perms.insert(perms.end(), perms_aux.begin(), perms_aux.end()); perms_aux.clear(); table=dynamic_cast(obj); if(table) { for(BaseObject *col : *table->getObjectList(ObjectType::Column)) { getPermissions(col, perms_aux); perms.insert(perms.end(), perms_aux.begin(), perms_aux.end()); } } } /* Retrieving all additional roles (reference by permissions) that are not in the main object list (used as creation order) */ for(Permission *perm : perms) { roles=perm->getRoles(); for(Role *role : roles) { if(std::find(objs.begin(), objs.end(), role)==objs.end()) getObjectDependecies(role, objs, true); } } } if(objs.size() > 1 || !perms.empty()) { //Putting all objects in a map ordering them by ID for(BaseObject *obj : objs) objs_map[obj->getObjectId()]=obj; //Recreationg the object list now with objects ordered properly objs.clear(); for(auto &itr : objs_map) objs.push_back(itr.second); //Appending permissions at the end of the creation order list objs.insert(objs.end(), perms.begin(), perms.end()); } return(objs); } void DatabaseModel::saveModel(const QString &filename, unsigned def_type) { QFile output(filename); QByteArray buf; output.open(QFile::WriteOnly); if(!output.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(filename), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { buf.append(this->getCodeDefinition(def_type)); output.write(buf.data(),buf.size()); output.close(); } catch(Exception &e) { if(output.isOpen()) output.close(); throw Exception(Exception::getErrorMessage(ErrorCode::FileNotWrittenInvalidDefinition).arg(filename), ErrorCode::FileNotWrittenInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::getObjectDependecies(BaseObject *object, vector &deps, bool inc_indirect_deps) { //Case the object is allocated and is not included in the dependecies list if(object && std::find(deps.begin(), deps.end(), object)==deps.end()) { deps.push_back(object); if((deps.size()==1 && !inc_indirect_deps) || inc_indirect_deps) { ObjectType obj_type=object->getObjectType(); /* if the object has a schema, tablespace and owner applies the dependecy search in these objects */ if(object->getSchema()) getObjectDependecies(object->getSchema(), deps, inc_indirect_deps); if(object->getTablespace()) getObjectDependecies(object->getTablespace(), deps, inc_indirect_deps); if(object->getOwner()) getObjectDependecies(object->getOwner(), deps, inc_indirect_deps); if(object->getCollation()) getObjectDependecies(object->getCollation(), deps, inc_indirect_deps); //** Getting the dependecies for operator class ** if(obj_type==ObjectType::OpClass) { OperatorClass *opclass=dynamic_cast(object); BaseObject *usr_type=getObjectPgSQLType(opclass->getDataType()); unsigned i, cnt; OperatorClassElement elem; if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); if(opclass->getFamily()) getObjectDependecies(opclass->getFamily(), deps, inc_indirect_deps); cnt=opclass->getElementCount(); for(i=0; i < cnt; i++) { elem=opclass->getElement(i); if(elem.getFunction()) getObjectDependecies(elem.getFunction(), deps, inc_indirect_deps); if(elem.getOperator()) getObjectDependecies(elem.getOperator(), deps, inc_indirect_deps); if(elem.getOperatorFamily()) getObjectDependecies(elem.getOperatorFamily(), deps, inc_indirect_deps); if(elem.getStorage().isUserType()) { usr_type=getObjectPgSQLType(elem.getStorage()); getObjectDependecies(usr_type, deps, inc_indirect_deps); } } } //** Getting the dependecies for domain ** else if(obj_type==ObjectType::Domain) { BaseObject *usr_type=getObjectPgSQLType(dynamic_cast(object)->getType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } //** Getting the dependecies for conversion ** else if(obj_type==ObjectType::Conversion) { Function *func=dynamic_cast(object)->getConversionFunction(); getObjectDependecies(func, deps, inc_indirect_deps); } //** Getting the dependecies for cast ** else if(obj_type==ObjectType::Cast) { Cast *cast=dynamic_cast(object); BaseObject *usr_type=nullptr; for(unsigned i=Cast::SrcType; i <= Cast::DstType; i++) { usr_type=getObjectPgSQLType(cast->getDataType(i)); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } getObjectDependecies(cast->getCastFunction(), deps, inc_indirect_deps); } //** Getting the dependecies for event trigger ** else if(obj_type==ObjectType::EventTrigger) { getObjectDependecies(dynamic_cast(object)->getFunction(), deps, inc_indirect_deps); } //** Getting the dependecies for function ** else if(obj_type==ObjectType::Function) { Function *func=dynamic_cast(object); BaseObject *usr_type=getObjectPgSQLType(func->getReturnType()); unsigned count, i; if(!func->isSystemObject()) getObjectDependecies(func->getLanguage(), deps, inc_indirect_deps); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); count=func->getParameterCount(); for(i=0; i < count; i++) { usr_type=getObjectPgSQLType(func->getParameter(i).getType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } count=func->getReturnedTableColumnCount(); for(i=0; i < count; i++) { usr_type=getObjectPgSQLType(func->getReturnedTableColumn(i).getType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } } //** Getting the dependecies for aggregate ** else if(obj_type==ObjectType::Aggregate) { Aggregate *aggreg=dynamic_cast(object); BaseObject *usr_type=nullptr; unsigned count, i; for(i=Aggregate::FinalFunc; i <= Aggregate::TransitionFunc; i++) getObjectDependecies(aggreg->getFunction(i), deps, inc_indirect_deps); usr_type=getObjectPgSQLType(aggreg->getStateType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); if(aggreg->getSortOperator()) getObjectDependecies(aggreg->getSortOperator(), deps, inc_indirect_deps); count=aggreg->getDataTypeCount(); for(i=0; i < count; i++) { usr_type=getObjectPgSQLType(aggreg->getDataType(i)); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } } //** Getting the dependecies for language ** else if(obj_type==ObjectType::Language) { Language *lang=dynamic_cast(object); for(unsigned i=Language::ValidatorFunc; i <= Language::InlineFunc; i++) { if(lang->getFunction(i)) getObjectDependecies(lang->getFunction(i), deps, inc_indirect_deps); } } //** Getting the dependecies for operator ** else if(obj_type==ObjectType::Operator) { Operator *oper=dynamic_cast(object); BaseObject *usr_type=nullptr; unsigned i; for(i=Operator::FuncOperator; i <= Operator::FuncRestrict; i++) { if(oper->getFunction(i)) getObjectDependecies(oper->getFunction(i), deps, inc_indirect_deps); } for(i=Operator::LeftArg; i <= Operator::RightArg; i++) { usr_type=getObjectPgSQLType(oper->getArgumentType(i)); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } for(i=Operator::OperCommutator; i <= Operator::OperNegator; i++) { if(oper->getOperator(i)) getObjectDependecies(oper->getOperator(i), deps, inc_indirect_deps); } } //** Getting the dependecies for role ** else if(obj_type==ObjectType::Role) { Role *role=dynamic_cast(object); unsigned i, i1, count, role_types[3]={ Role::RefRole, Role::MemberRole, Role::AdminRole }; for(i=0; i < 3; i++) { count=role->getRoleCount(role_types[i]); for(i1=0; i1 < count; i1++) getObjectDependecies(role->getRole(role_types[i], i1), deps, inc_indirect_deps); } } //** Getting the dependecies for relationships ** else if(obj_type==ObjectType::Relationship) { Relationship *rel=dynamic_cast(object); BaseObject *usr_type=nullptr; Constraint *constr=nullptr; unsigned i, count; getObjectDependecies(rel->getTable(Relationship::SrcTable), deps, inc_indirect_deps); getObjectDependecies(rel->getTable(Relationship::DstTable), deps, inc_indirect_deps); count=rel->getAttributeCount(); for(i=0; i < count; i++) { usr_type=getObjectPgSQLType(rel->getAttribute(i)->getType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } count=rel->getConstraintCount(); for(i=0; i < count; i++) { constr=dynamic_cast(rel->getConstraint(i)); if(constr->getTablespace()) getObjectDependecies(constr->getTablespace(), deps, inc_indirect_deps); } } //** Getting the dependecies for sequence ** else if(obj_type==ObjectType::Sequence) { Sequence *seq=dynamic_cast(object); if(seq->getOwnerColumn()) getObjectDependecies(seq->getOwnerColumn()->getParentTable(), deps, inc_indirect_deps); } //** Getting the dependecies for column ** else if(obj_type==ObjectType::Column) { Column *col=dynamic_cast(object); BaseObject *usr_type=getObjectPgSQLType(col->getType()), *sequence=col->getSequence(); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); if(sequence) getObjectDependecies(sequence, deps, inc_indirect_deps); } //** Getting the dependecies for trigger ** else if(obj_type==ObjectType::Trigger) { Trigger *trig=dynamic_cast(object); if(trig->getReferencedTable()) getObjectDependecies(trig->getReferencedTable(), deps, inc_indirect_deps); if(trig->getFunction()) getObjectDependecies(trig->getFunction(), deps, inc_indirect_deps); } //** Getting the dependecies for index ** else if(obj_type==ObjectType::Index) { Index *index=dynamic_cast(object); BaseObject *usr_type=nullptr; unsigned i, count=index->getIndexElementCount(); for(i=0; i < count; i++) { if(index->getIndexElement(i).getOperatorClass()) getObjectDependecies(index->getIndexElement(i).getOperatorClass(), deps, inc_indirect_deps); if(index->getIndexElement(i).getColumn()) { usr_type=getObjectPgSQLType(index->getIndexElement(i).getColumn()->getType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } if(index->getIndexElement(i).getCollation()) getObjectDependecies(index->getIndexElement(i).getCollation(), deps, inc_indirect_deps); } } else if(obj_type==ObjectType::Policy) { Policy *pol=dynamic_cast(object); for(auto role : pol->getRoles()) getObjectDependecies(role, deps, inc_indirect_deps); } //** Getting the dependecies for table / foreign table ** else if(PhysicalTable::isPhysicalTable(obj_type)) { PhysicalTable *tab=dynamic_cast(object); Table *aux_tab = dynamic_cast
(object); ForeignTable *ftable = dynamic_cast(tab); BaseObject *usr_type=nullptr, *seq=nullptr; Constraint *constr=nullptr; Trigger *trig=nullptr; Index *index=nullptr; Column *col=nullptr; Policy *pol=nullptr; unsigned count, i, count1, i1; count=tab->getColumnCount(); for(i=0; i < count; i++) { col=tab->getColumn(i); usr_type=getObjectPgSQLType(col->getType()); seq=col->getSequence(); if(!col->isAddedByLinking()) { if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); if(seq) getObjectDependecies(seq, deps, inc_indirect_deps); } } count=tab->getConstraintCount(); for(i=0; i < count; i++) { constr=dynamic_cast(tab->getConstraint(i)); count1=constr->getExcludeElementCount(); for(i1=0; i1 < count1; i1++) { if(constr->getExcludeElement(i1).getOperator()) getObjectDependecies(constr->getExcludeElement(i1).getOperator(), deps, inc_indirect_deps); if(constr->getExcludeElement(i1).getOperatorClass()) getObjectDependecies(constr->getExcludeElement(i1).getOperatorClass(), deps, inc_indirect_deps); } if(inc_indirect_deps && !constr->isAddedByLinking() && constr->getConstraintType()==ConstraintType::ForeignKey) getObjectDependecies(constr->getReferencedTable(), deps, inc_indirect_deps); if(!constr->isAddedByLinking() && constr->getTablespace()) getObjectDependecies(constr->getTablespace(), deps, inc_indirect_deps); } count=tab->getTriggerCount(); for(i=0; i < count; i++) { trig=dynamic_cast(tab->getTrigger(i)); if(trig->getReferencedTable()) getObjectDependecies(trig->getReferencedTable(), deps, inc_indirect_deps); if(trig->getFunction()) getObjectDependecies(trig->getFunction(), deps, inc_indirect_deps); } if(ftable) { getObjectDependecies(ftable->getForeignServer(), deps, inc_indirect_deps); } if(aux_tab) { count=aux_tab->getIndexCount(); for(i=0; i < count; i++) { index=dynamic_cast(aux_tab->getIndex(i)); count1=index->getIndexElementCount(); for(i1=0; i1 < count1; i1++) { if(index->getIndexElement(i1).getOperatorClass()) getObjectDependecies(index->getIndexElement(i1).getOperatorClass(), deps, inc_indirect_deps); if(index->getIndexElement(i1).getColumn()) { usr_type=getObjectPgSQLType(index->getIndexElement(i1).getColumn()->getType()); if(usr_type) getObjectDependecies(usr_type, deps, inc_indirect_deps); } if(index->getIndexElement(i1).getCollation()) getObjectDependecies(index->getIndexElement(i1).getCollation(), deps, inc_indirect_deps); } } count=aux_tab->getPolicyCount(); for(i=0; i < count; i++) { pol=dynamic_cast(aux_tab->getPolicy(i)); for(auto role : pol->getRoles()) getObjectDependecies(role, deps, inc_indirect_deps); } } } //** Getting the dependecies for user defined type ** else if(obj_type==ObjectType::Type) { Type *usr_type=dynamic_cast(object); BaseObject *aux_type=nullptr; unsigned count, i; if(usr_type->getConfiguration()==Type::BaseType) { aux_type=getObjectPgSQLType(usr_type->getLikeType()); if(aux_type) getObjectDependecies(aux_type, deps, inc_indirect_deps); for(i=Type::InputFunc; i <= Type::AnalyzeFunc; i++) getObjectDependecies(usr_type->getFunction(i), deps, inc_indirect_deps); } else if(usr_type->getConfiguration()==Type::CompositeType) { count=usr_type->getAttributeCount(); for(i=0; i < count; i++) { aux_type=getObjectPgSQLType(usr_type->getAttribute(i).getType()); if(aux_type) getObjectDependecies(aux_type, deps, inc_indirect_deps); } } } //** Getting the dependecies for view ** else if(obj_type==ObjectType::View) { View *view=dynamic_cast(object); unsigned i, count; count=view->getReferenceCount(); for(i=0; i < count; i++) { if(view->getReference(i).getTable()) getObjectDependecies(view->getReference(i).getTable(), deps, inc_indirect_deps); } for(i=0; i < view->getTriggerCount(); i++) getObjectDependecies(view->getTrigger(i), deps, inc_indirect_deps); for(i=0; i < view->getTriggerCount(); i++) { if(view->getTrigger(i)->getReferencedTable()) getObjectDependecies(view->getTrigger(i)->getReferencedTable(), deps, inc_indirect_deps); } } //** Getting the dependecies for foreign data wrapper ** else if(obj_type == ObjectType::ForeignDataWrapper) { ForeignDataWrapper *fdw = dynamic_cast(object); getObjectDependecies(fdw->getHandlerFunction(), deps, inc_indirect_deps); getObjectDependecies(fdw->getValidatorFunction(), deps, inc_indirect_deps); } //** Getting the dependecies for server ** else if(obj_type == ObjectType::ForeignServer) { ForeignServer *server = dynamic_cast(object); getObjectDependecies(server->getForeignDataWrapper(), deps, inc_indirect_deps); } //** Getting the dependecies for generic sql ** else if(obj_type==ObjectType::GenericSql) { GenericSQL *generic_sql = dynamic_cast(object); vector ref_objs = generic_sql->getReferencedObjects(); for(auto &obj : ref_objs) getObjectDependecies(obj, deps, inc_indirect_deps); } //** Getting the dependecies for user mapping ** else if(obj_type==ObjectType::UserMapping) { UserMapping *usr_map = dynamic_cast(object); getObjectDependecies(usr_map->getForeignServer(), deps, inc_indirect_deps); } if(BaseTable::isBaseTable(obj_type)) { BaseTable *tab = dynamic_cast(object); if(tab->getTag()) deps.push_back(tab->getTag()); } } } } void DatabaseModel::getObjectReferences(BaseObject *object, vector &refs, bool exclusion_mode, bool exclude_perms) { refs.clear(); if(object) { vector::iterator itr_perm, itr_perm_end; ObjectType obj_type=object->getObjectType(); bool refer=false; Permission *perm=nullptr; if(!exclude_perms) { //Get the permissions thata references the object itr_perm=permissions.begin(); itr_perm_end=permissions.end(); while(itr_perm!=itr_perm_end && (!exclusion_mode || (exclusion_mode && !refer))) { perm=dynamic_cast(*itr_perm); if(perm->getObject()==object) { refer=true; refs.push_back(perm); } itr_perm++; } } if(exclusion_mode && !refer && default_objs.count(obj_type) && default_objs[obj_type]==object) { refer=true; refs.push_back(this); } if(obj_type==ObjectType::View && (!exclusion_mode || (exclusion_mode && !refer))) { View *view=dynamic_cast(object); vector tab_objs=view->getObjects(); refs.insert(refs.end(), tab_objs.begin(), tab_objs.end()); if(!exclusion_mode) { vector base_rels=getRelationships(view); while(!base_rels.empty()) { refs.push_back(base_rels.back()); base_rels.pop_back(); } } } if(PhysicalTable::isPhysicalTable(obj_type) && (!exclusion_mode || (exclusion_mode && !refer))) { PhysicalTable *table=dynamic_cast(object); Sequence *seq=nullptr; Constraint *constr=nullptr; PhysicalTable *tab=nullptr; Trigger *gat=nullptr; BaseRelationship *base_rel=nullptr; View *view=nullptr; vector::iterator itr, itr_end; vector *tab_objs; unsigned i, count; vector tab_obj_types={ ObjectType::Trigger, ObjectType::Rule, ObjectType::Index, ObjectType::Policy }; vector tabs; for(auto &type : tab_obj_types) { if(obj_type == ObjectType::ForeignTable && type != ObjectType::Trigger) continue; tab_objs=table->getObjectList(type); refs.insert(refs.end(), tab_objs->begin(), tab_objs->end()); } itr=relationships.begin(); itr_end=relationships.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { base_rel=dynamic_cast(*itr); if(base_rel->getTable(BaseRelationship::SrcTable)==table || base_rel->getTable(BaseRelationship::DstTable)==table) { refer=true; refs.push_back(base_rel); } itr++; } itr=base_relationships.begin(); itr_end=base_relationships.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { base_rel=dynamic_cast(*itr); if(base_rel->getRelationshipType()==BaseRelationship::RelationshipFk && (base_rel->getTable(BaseRelationship::SrcTable)==table || base_rel->getTable(BaseRelationship::DstTable)==table)) { refer=true; refs.push_back(base_rel); } itr++; } itr=sequences.begin(); itr_end=sequences.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { seq=dynamic_cast(*itr); if(seq->getOwnerColumn() && seq->getOwnerColumn()->getParentTable()==table) { refer=true; refs.push_back(seq); } itr++; } tabs = tables; tabs.insert(tabs.end(), foreign_tables.begin(), foreign_tables.end()); itr= tabs.begin(); itr_end = tabs.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { tab = dynamic_cast(*itr); count=tab->getConstraintCount(); for(i=0; i < count&& (!exclusion_mode || (exclusion_mode && !refer)); i++) { constr=tab->getConstraint(i); //If a constraint references its own parent table it'll not be included on the references list if(constr->getConstraintType()==ConstraintType::ForeignKey && constr->getParentTable()!=constr->getReferencedTable() && constr->getReferencedTable()==table) { refer=true; refs.push_back(constr); } } count=tab->getTriggerCount(); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { gat=tab->getTrigger(i); if(gat->getReferencedTable()==table) { refer=true; refs.push_back(gat); } } itr++; } itr=views.begin(); itr_end=views.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { view=dynamic_cast(*itr); if(view->isReferencingTable(table)) { refer=true; refs.push_back(view); } itr++; } /* As base relationship are created automatically by the model they aren't considered as a reference to the table in exclusion mode */ itr=base_relationships.begin(); itr_end=base_relationships.end(); while(itr!=itr_end && !exclusion_mode)// || (exclusion_mode && !refer))) { base_rel=dynamic_cast(*itr); if(base_rel->getTable(BaseRelationship::SrcTable)==table || base_rel->getTable(BaseRelationship::DstTable)==table) { refer=true; refs.push_back(base_rel); } itr++; } } if(obj_type==ObjectType::Function && (!exclusion_mode || (exclusion_mode && !refer))) { Function *func=dynamic_cast(object); vector *obj_list=nullptr; vector::iterator itr, itr_end; ObjectType obj_types[]={ObjectType::Cast, ObjectType::EventTrigger, ObjectType::Conversion, ObjectType::Aggregate, ObjectType::Operator, ObjectType::OpClass, ObjectType::Table, ObjectType::Type, ObjectType::Language, ObjectType::ForeignDataWrapper, ObjectType::ForeignTable }; unsigned i, i1, count, cnt=sizeof(obj_types)/sizeof(ObjectType); PhysicalTable *tab=nullptr; Aggregate *aggreg=nullptr; Operator *oper=nullptr; Trigger *trig=nullptr; Type *type=nullptr; Language *lang=nullptr; OperatorClass *opclass=nullptr; ForeignDataWrapper *fdw=nullptr; for(i=0; i < cnt && (!exclusion_mode || (exclusion_mode && !refer)); i++) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); if(obj_types[i]==ObjectType::Cast) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getCastFunction()==func) { refer=true; refs.push_back(*itr); } itr++; } } else if(obj_types[i]==ObjectType::EventTrigger) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getFunction()==func) { refer=true; refs.push_back(*itr); } itr++; } } else if(obj_types[i]==ObjectType::Conversion) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getConversionFunction()==func) { refer=true; refs.push_back(*itr); } itr++; } } else if(obj_types[i]==ObjectType::Aggregate) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { aggreg=dynamic_cast(*itr); if(aggreg->getFunction(Aggregate::FinalFunc)==func || aggreg->getFunction(Aggregate::TransitionFunc)==func) { refer=true; refs.push_back(aggreg); } itr++; } } else if(obj_types[i]==ObjectType::Operator) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { oper=dynamic_cast(*itr); if(oper->getFunction(Operator::FuncOperator)==func || oper->getFunction(Operator::FuncJoin)==func || oper->getFunction(Operator::FuncRestrict)==func) { refer=true; refs.push_back(oper); } itr++; } } else if(obj_types[i]==ObjectType::OpClass) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { opclass=dynamic_cast(*itr); count=opclass->getElementCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(opclass->getElement(i1).getFunction()==func) { refer=true; refs.push_back(opclass); } } itr++; } } else if(obj_types[i]==ObjectType::Table || obj_types[i]==ObjectType::ForeignTable) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { tab=dynamic_cast(*itr); itr++; count=tab->getTriggerCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { trig=tab->getTrigger(i1); if(trig->getFunction()==func) { refer=true; refs.push_back(trig); } } } } else if(obj_types[i]==ObjectType::Type) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { type=dynamic_cast(*itr); itr++; for(i1=Type::InputFunc; i1 <= Type::AnalyzeFunc && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(type->getFunction(i1)==func) { refer=true; refs.push_back(type); } } } } else if(obj_types[i]==ObjectType::Language) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { lang=dynamic_cast(*itr); itr++; if(lang->getFunction(Language::HandlerFunc)==func || lang->getFunction(Language::ValidatorFunc)==func || lang->getFunction(Language::InlineFunc)==func) { refer=true; refs.push_back(lang); } } } else if(obj_types[i]==ObjectType::ForeignDataWrapper) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { fdw=dynamic_cast(*itr); itr++; if(fdw->getHandlerFunction() == func || fdw->getValidatorFunction() == func) { refer=true; refs.push_back(fdw); } } } } } if(obj_type==ObjectType::Schema && (!exclusion_mode || (exclusion_mode && !refer))) { vector *obj_list=nullptr; vector::iterator itr, itr_end; ObjectType obj_types[12]={ObjectType::Function, ObjectType::Table, ObjectType::ForeignTable, ObjectType::View, ObjectType::Domain, ObjectType::Aggregate, ObjectType::Operator, ObjectType::Sequence, ObjectType::Conversion, ObjectType::Type, ObjectType::OpFamily, ObjectType::OpClass}; unsigned i; for(i=0; i < 12 && (!exclusion_mode || (exclusion_mode && !refer)); i++) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if((*itr)->getSchema()==object) { refer=true; refs.push_back(*itr); } itr++; } } } if((obj_type==ObjectType::Type || obj_type==ObjectType::Domain || obj_type==ObjectType::Sequence || obj_type==ObjectType::Extension || BaseTable::isBaseTable(obj_type)) && (!exclusion_mode || (exclusion_mode && !refer))) { vector *obj_list=nullptr; vector::iterator itr, itr_end; ObjectType obj_types[]={ObjectType::Table, ObjectType::ForeignTable, ObjectType::OpClass, ObjectType::Cast, ObjectType::Domain, ObjectType::Function, ObjectType::Aggregate, ObjectType::Operator, ObjectType::Type, ObjectType::Relationship }; unsigned i, i1, count, tp_count = sizeof(obj_types)/sizeof(ObjectType); OperatorClass *op_class=nullptr; OperatorClassElement elem; PhysicalTable *tab=nullptr; Column *col=nullptr; Cast *cast=nullptr; Domain *dom=nullptr; Function *func=nullptr; Aggregate *aggreg=nullptr; Operator *oper=nullptr; Type *type=nullptr; Relationship *rel=nullptr; void *ptr_pgsqltype=nullptr; switch(obj_type) { case ObjectType::Type: ptr_pgsqltype=dynamic_cast(object); break; case ObjectType::Domain: ptr_pgsqltype=dynamic_cast(object); break; case ObjectType::Sequence: ptr_pgsqltype=dynamic_cast(object); break; case ObjectType::Extension: ptr_pgsqltype=dynamic_cast(object); break; case ObjectType::View: ptr_pgsqltype=dynamic_cast(object); break; case ObjectType::ForeignTable: ptr_pgsqltype=dynamic_cast(object); break; default: ptr_pgsqltype=dynamic_cast(object); break; } for(i=0; i < tp_count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); if(obj_types[i]==ObjectType::Relationship) { bool added; while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { added=false; rel=dynamic_cast(*itr); itr++; count=rel->getAttributeCount(); for(i1=0; i1 < count && !added; i1++) { col=rel->getAttribute(i1); if(col->getType()==ptr_pgsqltype) { added=refer=true; refs.push_back(rel); } } } } else if(PhysicalTable::isPhysicalTable(obj_types[i])) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { tab=dynamic_cast(*itr); itr++; count=tab->getColumnCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { col=tab->getColumn(i1); if(!col->isAddedByRelationship() && (col->getType()==ptr_pgsqltype || //Special case for postgis extension (obj_type == ObjectType::Extension && object->getName() == QString("postgis") && col->getType().isGiSType()))) { refer=true; refs.push_back(col); } } } } else if(obj_types[i]==ObjectType::OpClass) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { op_class=dynamic_cast(*itr); itr++; if(op_class->getDataType()==ptr_pgsqltype) { refer=true; refs.push_back(op_class); } for(i1=0; i1 < op_class->getElementCount() && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { elem=op_class->getElement(i1); if(elem.getStorage()==ptr_pgsqltype) { refer=true; refs.push_back(op_class); } } } } else if(obj_types[i]==ObjectType::Domain) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { dom=dynamic_cast(*itr); itr++; if(dom->getType()==ptr_pgsqltype) { refer=true; refs.push_back(dom); } } } else if(obj_types[i]==ObjectType::Type) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { type=dynamic_cast(*itr); itr++; if(type->getAlignment()==ptr_pgsqltype || type->getElement()==ptr_pgsqltype || type->getLikeType()==ptr_pgsqltype || type->getSubtype()==ptr_pgsqltype) { refer=true; refs.push_back(type); } } } else if(obj_types[i]==ObjectType::Aggregate) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { aggreg=dynamic_cast(*itr); itr++; count=aggreg->getDataTypeCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(aggreg->getDataType(i1)==ptr_pgsqltype) { refer=true; refs.push_back(aggreg); } } } } else if(obj_types[i]==ObjectType::Function) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { func=dynamic_cast(*itr); itr++; if(func->getReturnType()==ptr_pgsqltype) { refer=true; refs.push_back(func); } else { count=func->getParameterCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(func->getParameter(i1).getType()==ptr_pgsqltype) { refer=true; refs.push_back(func); } } } } } else if(obj_types[i]==ObjectType::Operator) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { oper=dynamic_cast(*itr); itr++; if(oper->getArgumentType(Operator::LeftArg)==ptr_pgsqltype || oper->getArgumentType(Operator::RightArg)==ptr_pgsqltype) { refer=true; refs.push_back(oper); } } } else if(obj_types[i]==ObjectType::Cast) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { cast=dynamic_cast(*itr); itr++; if(cast->getDataType(Cast::SrcType)==ptr_pgsqltype || cast->getDataType(Cast::DstType)==ptr_pgsqltype) { refer=true; refs.push_back(cast); } } } } } if(obj_type==ObjectType::Role && (!exclusion_mode || (exclusion_mode && !refer))) { vector *obj_list=nullptr; vector::iterator itr, itr_end; vector obj_types = { ObjectType::Function, ObjectType::Table, ObjectType::ForeignTable, ObjectType::Domain, ObjectType::Aggregate, ObjectType::Schema, ObjectType::Operator, ObjectType::Sequence, ObjectType::Conversion, ObjectType::Language, ObjectType::Tablespace, ObjectType::Type, ObjectType::OpFamily, ObjectType::OpClass, ObjectType::UserMapping }; vector::iterator itr_tp, itr_tp_end; unsigned i,i1, count; Role *role_aux=nullptr; Role *role=dynamic_cast(object); unsigned role_types[3]={Role::RefRole, Role::MemberRole, Role::AdminRole}; Permission *perm=nullptr; //Check if the role is being referencend by permissions itr=permissions.begin(); itr_end=permissions.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { perm=dynamic_cast(*itr); itr++; if(perm->isRoleExists(role)) { refer=true; refs.push_back(perm); } } //Check if the role is being referenced in other roles itr=roles.begin(); itr_end=roles.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { role_aux=dynamic_cast(*itr); itr++; for(i1=0; i1 < 3 && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { count=role_aux->getRoleCount(role_types[i1]); for(i=0; i < count && !refer; i++) { if(role_aux->getRole(role_types[i1], i)==role) { refer=true; refs.push_back(role_aux); } } } } itr_tp = obj_types.begin(); itr_tp_end = obj_types.end(); while(itr_tp != itr_tp_end && (!exclusion_mode || (exclusion_mode && !refer))) { obj_list=getObjectList(*itr_tp); itr_tp++; itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if((*itr)->getOwner()==role) { refer=true; refs.push_back(*itr); } if((*itr)->getObjectType() == ObjectType::Table) { for(auto obj : *(dynamic_cast
(*itr))->getObjectList(ObjectType::Policy)) { if(dynamic_cast(obj)->isRoleExists(role)) { refer=true; refs.push_back(obj); } } } itr++; } } //Special case: check if the role to be removed is the owner of the database if((!exclusion_mode || (exclusion_mode && !refer)) && this->getOwner()==role) { refer=true; refs.push_back(this); } } if(obj_type==ObjectType::Tablespace && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; unsigned i, count; Table *tab=nullptr; Index *ind=nullptr; Constraint *rest=nullptr; itr=tables.begin(); itr_end=tables.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { tab=dynamic_cast
(*itr); if(tab->getTablespace()==object) { refer=true; refs.push_back(tab); } count=tab->getIndexCount(); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { ind=tab->getIndex(i); if(ind->getTablespace()==object) { refer=true; refs.push_back(ind); } } count=tab->getConstraintCount(); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { rest=tab->getConstraint(i); if(rest->getTablespace()==object) { refer=true; refs.push_back(rest); } } itr++; } if((!exclusion_mode || (exclusion_mode && !refer)) && this->BaseObject::getTablespace()==object) { refer=true; refs.push_back(this); } } if(obj_type==ObjectType::Language && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; Function *func=nullptr; itr=functions.begin(); itr_end=functions.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { func=dynamic_cast(*itr); if(func->getLanguage()==object) { refer=true; refs.push_back(func); } itr++; } } if(obj_type==ObjectType::OpClass && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; Type *usertype=nullptr; Index *ind=nullptr; Constraint *constr=nullptr; Table *table=nullptr; ForeignTable *ftable=nullptr; itr=types.begin(); itr_end=types.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { usertype=dynamic_cast(*itr); if(usertype->getSubtypeOpClass()==object) { refer=true; refs.push_back(usertype); } itr++; } itr=tables.begin(); itr_end=tables.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { table=dynamic_cast
(*itr); //Checking if the indexes are referencing the operator class for(unsigned idx=0; idx < table->getIndexCount() && (!exclusion_mode || (exclusion_mode && !refer)); idx++) { ind=table->getIndex(idx); for(unsigned id_elem=0; id_elem < ind->getIndexElementCount() && (!exclusion_mode || (exclusion_mode && !refer)); id_elem++) { if(ind->getIndexElement(id_elem).getOperatorClass()==object) { refer=true; refs.push_back(ind); } } } //Checking if the constraints are referencing the operator class for(unsigned idx=0; idx < table->getConstraintCount() && (!exclusion_mode || (exclusion_mode && !refer)); idx++) { constr=table->getConstraint(idx); for(unsigned id_elem=0; id_elem < constr->getExcludeElementCount() && (!exclusion_mode || (exclusion_mode && !refer)); id_elem++) { if(constr->getExcludeElement(id_elem).getOperatorClass()==object) { refer=true; refs.push_back(constr); } } } //Checking if the partition keys are referencing the operator class for(auto &part_key : table->getPartitionKeys()) { if(part_key.getOperatorClass() == object) { refer = true; refs.push_back(table); break; } } itr++; } itr=foreign_tables.begin(); itr_end=foreign_tables.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { ftable=dynamic_cast(*itr); //Checking if the partition keys are referencing the operator class for(auto &part_key : ftable->getPartitionKeys()) { if(part_key.getOperatorClass() == object) { refer = true; refs.push_back(ftable); break; } } itr++; } } if(obj_type==ObjectType::Operator && (!exclusion_mode || (exclusion_mode && !refer))) { vector *obj_list=nullptr; vector::iterator itr, itr_end; ObjectType obj_types[]={ObjectType::OpClass, ObjectType::Aggregate, ObjectType::Operator, ObjectType::Table }; unsigned i, i1, count; OperatorClass *op_class=nullptr; Operator *oper_aux=nullptr, *oper=dynamic_cast(object); Table *table=nullptr; Constraint *constr=nullptr; for(i=0; i < 4 && (!exclusion_mode || (exclusion_mode && !refer)); i++) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); if(obj_types[i]==ObjectType::OpClass) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { op_class=dynamic_cast(*itr); itr++; count=op_class->getElementCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(op_class->getElement(i1).getOperator()==oper) { refer=true; refs.push_back(op_class); } } } } else if(obj_types[i]==ObjectType::Aggregate) { while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getSortOperator()==oper) { refer=true; refs.push_back(*itr); } itr++; } } else if(obj_types[i]==ObjectType::Operator) { while(itr!=itr_end && !refer) { oper_aux=dynamic_cast(*itr); itr++; for(i1=Operator::OperCommutator; i1 <= Operator::OperNegator && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(oper_aux->getOperator(i1)==oper) { refer=true; refs.push_back(oper_aux); } } } } else { while(itr!=itr_end && !refer) { table=dynamic_cast
(*itr); itr++; count=table->getConstraintCount(); for(i1=0; i1 < count && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { constr=table->getConstraint(i1); if(constr->getConstraintType()==ConstraintType::Exclude) { for(auto &elem : constr->getExcludeElements()) { if(elem.getOperator()==oper) { refer=true; refs.push_back(constr); if(exclusion_mode) break; } } } } } } } } if(obj_type==ObjectType::OpFamily && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; OperatorFamily *op_family=dynamic_cast(object); itr=op_classes.begin(); itr_end=op_classes.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getFamily()==op_family) { refer=true; refs.push_back(*itr); } itr++; } } if(obj_type==ObjectType::Collation && (!exclusion_mode || (exclusion_mode && !refer))) { ObjectType obj_types[]={ ObjectType::Domain, ObjectType::Collation, ObjectType::Type }, tab_obj_types[]={ ObjectType::Column, ObjectType::Index }; unsigned i, count; vector *obj_list=nullptr; vector::iterator itr, itr_end; vector *tab_obj_list=nullptr; vector::iterator tab_itr, tab_itr_end; TableObject *tab_obj=nullptr; PhysicalTable *table = nullptr; count=sizeof(obj_types)/sizeof(ObjectType); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if((*itr)->getCollation()==object) { refer=true; refs.push_back(*itr); } itr++; } } count=sizeof(tab_obj_types)/sizeof(ObjectType); vector tabs; tabs.insert(tabs.end(), tables.begin(), tabs.end()); tabs.insert(tabs.end(), foreign_tables.begin(), foreign_tables.end()); itr=tabs.begin(); itr_end=tabs.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { table = dynamic_cast(*itr); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { tab_obj_list = table->getObjectList(tab_obj_types[i]); if(!tab_obj_list) continue; tab_itr=tab_obj_list->begin(); tab_itr_end=tab_obj_list->end(); while(tab_itr!=tab_itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { tab_obj=(*tab_itr); if((tab_obj->getObjectType()==ObjectType::Column && tab_obj->getCollation()==object) || (tab_obj->getObjectType()==ObjectType::Index && dynamic_cast(tab_obj)->isReferCollation(dynamic_cast(object)))) { refer=true; refs.push_back(*tab_itr); } tab_itr++; } } //Checking if the partition keys are referencing the operator class for(auto &part_key : table->getPartitionKeys()) { if(part_key.getCollation() == object) { refer = true; refs.push_back(table); break; } } itr++; } } if(obj_type==ObjectType::Column && (!exclusion_mode || (exclusion_mode && !refer))) { Column *column=dynamic_cast(object); vector *obj_list=nullptr; vector::iterator itr, itr_end; ObjectType obj_types[]={ ObjectType::Sequence, ObjectType::View, ObjectType::Table, ObjectType::ForeignTable, ObjectType::Relationship }; unsigned i, count=sizeof(obj_types)/sizeof(ObjectType); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !refer)); i++) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if((obj_types[i]==ObjectType::Sequence && dynamic_cast(*itr)->getOwnerColumn()==column) || (obj_types[i]==ObjectType::View && dynamic_cast(*itr)->isReferencingColumn(column))) { refer=true; refs.push_back(*itr); } else if(obj_types[i]==ObjectType::Table || obj_types[i]==ObjectType::ForeignTable) { PhysicalTable *tab=dynamic_cast(*itr); Table *aux_tab = dynamic_cast
(tab); unsigned count, idx, count1, i1; Trigger *trig=nullptr; Index *index=nullptr; Constraint *constr=nullptr; vector part_keys; count=tab->getConstraintCount(); for(idx=0; idx < count && (!exclusion_mode || (exclusion_mode && !refer)); idx++) { constr=tab->getConstraint(idx); if(constr->isColumnReferenced(column)) { refer=true; refs.push_back(constr); } } if(aux_tab) { count=aux_tab->getIndexCount(); for(idx=0; idx < count && (!exclusion_mode || (exclusion_mode && !refer)); idx++) { index=aux_tab->getIndex(idx); if(index->isReferColumn(column)) { refer=true; refs.push_back(index); } } } count=tab->getTriggerCount(); for(idx=0; idx < count && (!exclusion_mode || (exclusion_mode && !refer)); idx++) { trig=tab->getTrigger(idx); count1=trig->getColumnCount(); for(i1=0; i1 < count1 && (!exclusion_mode || (exclusion_mode && !refer)); i1++) { if(trig->getColumn(i1)==column) { refer=true; refs.push_back(trig); } } } part_keys = tab->getPartitionKeys(); for(auto &part_key : part_keys) { if(part_key.getColumn() == column) { refer = true; refs.push_back(tab); break; } } } else if(obj_types[i]==ObjectType::Relationship) { Relationship *rel=dynamic_cast(*itr); unsigned constr_cnt, idx; constr_cnt=rel->getConstraintCount(); for(idx=0; idx < constr_cnt && (!exclusion_mode || (exclusion_mode && !refer)); idx++) { if(rel->getConstraint(idx)->isColumnReferenced(column)) { refer=true; refs.push_back(rel); } } } itr++; } } } if(obj_type==ObjectType::Tag && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; vector list; Tag *tag=dynamic_cast(object); list.assign(tables.begin(), tables.end()); list.insert(list.end(), foreign_tables.begin(), foreign_tables.end()); list.insert(list.end(), views.begin(), views.end()); itr=list.begin(); itr_end=list.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getTag()==tag) { refer=true; refs.push_back(*itr); } itr++; } } if(obj_type==ObjectType::Sequence && (!exclusion_mode || (exclusion_mode && !refer))) { PhysicalTable *table=nullptr; vector *cols=nullptr; vector::iterator itr, itr_end; vector tabs; unsigned i = 0, cnt = 0; tabs = tables; tabs.insert(tabs.end(), foreign_tables.begin(), foreign_tables.end()); cnt = tabs.size(); for(i=0; i < cnt && (!exclusion_mode || (exclusion_mode && !refer)); i++) { table=dynamic_cast(tabs[i]); cols=table->getObjectList(ObjectType::Column); itr=cols->begin(); itr_end=cols->end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getSequence()==object) { refer=true; refs.push_back(*itr); } itr++; } } } if(obj_type==ObjectType::ForeignDataWrapper && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; vector list; ForeignDataWrapper *fdw=dynamic_cast(object); itr=foreign_servers.begin(); itr_end=foreign_servers.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getForeignDataWrapper() == fdw) { refer=true; refs.push_back(*itr); } itr++; } } if(obj_type==ObjectType::ForeignServer && (!exclusion_mode || (exclusion_mode && !refer))) { vector::iterator itr, itr_end; vector list; ForeignServer *srv=dynamic_cast(object); itr=usermappings.begin(); itr_end=usermappings.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getForeignServer() == srv) { refer=true; refs.push_back(*itr); } itr++; } itr=foreign_tables.begin(); itr_end=foreign_tables.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->getForeignServer() == srv) { refer=true; refs.push_back(*itr); } itr++; } } // Checking if any generic SQL object is referencing the object passed vector::iterator itr = genericsqls.begin(), itr_end = genericsqls.end(); while(itr != itr_end && (!exclusion_mode || (exclusion_mode && !refer))) { if(dynamic_cast(*itr)->isObjectReferenced(object)) { refer = true; refs.push_back(*itr); } itr++; } } } void DatabaseModel::__getObjectReferences(BaseObject *object, vector &refs, bool exclude_perms) { vector refs_aux; vector::iterator end; getObjectReferences(object, refs_aux, exclude_perms); if(!refs_aux.empty()) { refs.insert(refs.end(), refs_aux.begin(), refs_aux.end()); std::sort(refs.begin(), refs.end()); end=std::unique(refs.begin(), refs.end()); refs.erase(end, refs.end()); for(BaseObject *obj : refs_aux) __getObjectReferences(obj, refs, exclude_perms); } } void DatabaseModel::setObjectsModified(vector &objects) { for(auto &obj : objects) { if(BaseGraphicObject::isGraphicObject(obj->getObjectType())) dynamic_cast(obj)->setModified(true); } } void DatabaseModel::setObjectsModified(vector types) { ObjectType obj_types[]={ObjectType::Table, ObjectType::View, ObjectType::ForeignTable, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Textbox, ObjectType::Schema }; vector::iterator itr, itr_end; vector *obj_list=nullptr; Textbox *label=nullptr; BaseRelationship *rel=nullptr; unsigned i, i1, count=sizeof(obj_types)/sizeof(ObjectType); for(i=0; i < count; i++) { if(types.empty() || find(types.begin(), types.end(), obj_types[i])!=types.end()) { obj_list=getObjectList(obj_types[i]); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end) { dynamic_cast(*itr)->setModified(true); //For relationships is needed to set the labels as modified too if(obj_types[i]==ObjectType::Relationship || obj_types[i]==ObjectType::BaseRelationship) { rel=dynamic_cast(*itr); for(i1=0; i1 < 3; i1++) { label=rel->getLabel(i1); if(label) label->setModified(true); } } itr++; } } } } void DatabaseModel::setCodesInvalidated(vector types) { vector sel_types; vector *list=nullptr; if(types.empty()) sel_types=BaseObject::getObjectTypes(false); else { ObjectType tab_obj_types[]={ObjectType::Column, ObjectType::Constraint, ObjectType::Trigger, ObjectType::Rule, ObjectType::Index, ObjectType::Policy}; for(unsigned i=0; i < 6; i++) sel_types.erase(std::find(sel_types.begin(), sel_types.end(), tab_obj_types[i])); sel_types=types; } while(!sel_types.empty()) { list=getObjectList(sel_types.back()); sel_types.pop_back(); if(list) { for(auto &obj : *list) obj->setCodeInvalidated(true); } } } BaseObject *DatabaseModel::getObjectPgSQLType(PgSqlType type) { switch(type.getUserTypeConfig()) { case UserTypeConfig::BaseType: return(this->getObject(*type, ObjectType::Type)); case UserTypeConfig::DomainType: return(this->getObject(*type, ObjectType::Domain)); case UserTypeConfig::TableType: return(this->getObject(*type, ObjectType::Table)); case UserTypeConfig::ViewType: return(this->getObject(*type, ObjectType::View)); case UserTypeConfig::SequenceType: return(this->getObject(*type, ObjectType::Sequence)); case UserTypeConfig::ExtensionType: return(this->getObject(*type, ObjectType::Extension)); default: return(nullptr); } } void DatabaseModel::validateSchemaRenaming(Schema *schema, const QString &prev_sch_name) { vector types = { ObjectType::Table, ObjectType::ForeignTable, ObjectType::View, ObjectType::Domain, ObjectType::Type, ObjectType::Sequence }; vector list, sch_objs, refs; QString prev_name; //Raise an error if the schema is not allocated if(!schema) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Get all the objects on the informed schema for(auto &type : types) { list = getObjects(type, schema); sch_objs.insert(sch_objs.end(), list.begin(), list.end()); } for(auto &obj : sch_objs) { //Configures the previous type name prev_name=BaseObject::formatName(prev_sch_name) + QString(".") + BaseObject::formatName(obj->getName(), false); /* Special case for tables. Need to make a dynamic_cast before the reinterpret_cast to get the correct reference to table */ if(obj->getObjectType() == ObjectType::Table) PgSqlType::renameUserType(prev_name, reinterpret_cast(dynamic_cast
(obj)), obj->getName(true)); else if(obj->getObjectType() == ObjectType::View) PgSqlType::renameUserType(prev_name, reinterpret_cast(dynamic_cast(obj)), obj->getName(true)); else if(obj->getObjectType() == ObjectType::ForeignTable) PgSqlType::renameUserType(prev_name, reinterpret_cast(dynamic_cast(obj)), obj->getName(true)); else PgSqlType::renameUserType(prev_name, reinterpret_cast(obj), obj->getName(true)); getObjectReferences(obj, refs); //For graphical objects set them as modified to redraw them if(BaseTable::isBaseTable(obj->getObjectType())) dynamic_cast(obj)->setModified(true); for(auto &ref_obj : refs) { if(BaseTable::isBaseTable(ref_obj->getObjectType())) dynamic_cast(ref_obj)->setModified(true); else if(TableObject::isTableObject(ref_obj->getObjectType())) { BaseTable *tab = dynamic_cast(ref_obj)->getParentTable(); tab->setModified(true); tab->setCodeInvalidated(true); } ref_obj->setCodeInvalidated(true); } refs.clear(); } } void DatabaseModel::createSystemObjects(bool create_public) { Schema *public_sch=nullptr, *pg_catalog=nullptr; Language *lang=nullptr; Tablespace *tbspace=nullptr; LanguageType lang_types[]={ LanguageType::C, LanguageType::Sql, LanguageType::PlPgsql, LanguageType::Internal }; Role *postgres=nullptr; Collation *collation=nullptr; QString collnames[]={ "default", "C", "POSIX" }; /* The particular case is for public schema that is created only when the flag is set. This because the public schema is written on model file even being a system object. This strategy permits the user controls the schema rectangle behavior */ if(create_public && getObjectIndex(QString("public"), ObjectType::Schema) < 0) { public_sch=new Schema; public_sch->setName(QString("public")); public_sch->setSystemObject(true); addSchema(public_sch); } //Create the pg_catalog schema in order to insert default collations in pg_catalog=new Schema; pg_catalog->BaseObject::setName(QString("pg_catalog")); pg_catalog->setSystemObject(true); addSchema(pg_catalog); //Creating default collations for(unsigned i=0; i < 3; i++) { collation=new Collation; collation->setName(collnames[i]); collation->setSchema(pg_catalog); collation->setEncoding(EncodingType(QString("UTF8"))); collation->setLocale(QString("C")); collation->setSystemObject(true); addCollation(collation); } for(unsigned i=0; i < sizeof(lang_types)/sizeof(LanguageType); i++) { if(getObjectIndex(~LanguageType(lang_types[i]), ObjectType::Language) < 0) { lang=new Language; lang->BaseObject::setName(~LanguageType(lang_types[i])); lang->setSystemObject(true); addLanguage(lang); } } tbspace=new Tablespace; tbspace->BaseObject::setName(QString("pg_global")); tbspace->setDirectory(QString("_pg_global_dir_")); tbspace->setSystemObject(true); addTablespace(tbspace); tbspace=new Tablespace; tbspace->BaseObject::setName(QString("pg_default")); tbspace->setDirectory(QString("_pg_default_dir_")); tbspace->setSystemObject(true); addTablespace(tbspace); postgres=new Role; postgres->setName(QString("postgres")); postgres->setOption(Role::OpSuperuser, true); postgres->setSystemObject(true); addRole(postgres); setDefaultObject(postgres); setDefaultObject(getObject(QString("public"), ObjectType::Schema), ObjectType::Schema); } vector DatabaseModel::findObjects(const QString &pattern, vector types, bool case_sensitive, bool is_regexp, bool exact_match, const QString &search_attr) { vector list, objs; vector::iterator end; vector::iterator itr_tp=types.begin(); vector tables; bool inc_tabs=false, inc_views=false; ObjectType obj_type; QRegExp regexp; BaseObject *object = nullptr; attribs_map srch_attribs; //Configuring the regex style regexp.setPattern(pattern); regexp.setCaseSensitivity(case_sensitive ? Qt::CaseSensitive : Qt::CaseInsensitive); if(is_regexp) regexp.setPatternSyntax(QRegExp::RegExp2); else if(exact_match) regexp.setPatternSyntax(QRegExp::FixedString); else regexp.setPatternSyntax(QRegExp::Wildcard); //If there is some table object types on the type list, gather tables and views while(itr_tp!=types.end() && (!inc_views || !inc_tabs)) { if(!inc_tabs && TableObject::isTableObject(*itr_tp)) { tables.insert(tables.end(), getObjectList(ObjectType::Table)->begin(), getObjectList(ObjectType::Table)->end()); tables.insert(tables.end(), getObjectList(ObjectType::ForeignTable)->begin(), getObjectList(ObjectType::ForeignTable)->end()); inc_tabs=true; } if(!inc_views && ((*itr_tp)==ObjectType::Rule || (*itr_tp)==ObjectType::Trigger)) { tables.insert(tables.end(), getObjectList(ObjectType::View)->begin(), getObjectList(ObjectType::View)->end()); inc_views=true; } itr_tp++; } //Gathering all other objects itr_tp=types.begin(); while(itr_tp!=types.end()) { obj_type=(*itr_tp); itr_tp++; if(obj_type==ObjectType::Database) objs.push_back(this); else if(!TableObject::isTableObject(obj_type)) objs.insert(objs.end(), getObjectList(obj_type)->begin(), getObjectList(obj_type)->end()); else { //Including table object on the object list vector *tab_objs=nullptr; vector::iterator itr=tables.begin(); BaseObject *tab=nullptr; while(itr!=tables.end()) { tab=(*itr); itr++; if(PhysicalTable::isPhysicalTable(tab->getObjectType())) tab_objs=dynamic_cast(tab)->getObjectList(obj_type); else if(tab->getObjectType()==ObjectType::View && (obj_type==ObjectType::Trigger || obj_type==ObjectType::Rule)) tab_objs=dynamic_cast(tab)->getObjectList(obj_type); if(tab_objs) objs.insert(objs.end(), tab_objs->begin(), tab_objs->end()); } } } //Try to find the objects on the configured list while(!objs.empty()) { object = objs.back(); object->configureSearchAttributes(); srch_attribs = object->getSearchAttributes(); if((exact_match && pattern == srch_attribs[search_attr]) || (exact_match && regexp.exactMatch(srch_attribs[search_attr])) || (!exact_match && regexp.indexIn(srch_attribs[search_attr]) >= 0)) list.push_back(object); objs.pop_back(); } //Removing the duplicate items on the list std::sort(list.begin(), list.end()); end=std::unique(list.begin(), list.end()); list.erase(end, list.end()); return(list); } void DatabaseModel::setInvalidated(bool value) { this->invalidated=value; } bool DatabaseModel::isInvalidated(void) { return(invalidated); } void DatabaseModel::setAppendAtEOD(bool value) { append_at_eod=value; } void DatabaseModel::setPrependAtBOD(bool value) { prepend_at_bod=value; } void DatabaseModel::setDefaultObject(BaseObject *object, ObjectType obj_type) { if((!object && default_objs.count(obj_type)==0) || (object && default_objs.count(object->getObjectType())==0)) throw Exception(ErrorCode::RefObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); if(!object) default_objs[obj_type]=nullptr; else default_objs[object->getObjectType()]=object; } void DatabaseModel::setIsTemplate(bool value) { is_template = value; } void DatabaseModel::setAllowConnections(bool value) { allow_conns = value; } bool DatabaseModel::isAppendAtEOD(void) { return(append_at_eod); } bool DatabaseModel::isPrependedAtBOD(void) { return(prepend_at_bod); } bool DatabaseModel::isTemplate(void) { return(is_template); } bool DatabaseModel::isAllowConnections(void) { return(allow_conns); } void DatabaseModel::saveObjectsMetadata(const QString &filename, unsigned options) { QFile output(filename); QByteArray buf; QString objs_def; vector objects, tab_objs; attribs_map attribs; BaseGraphicObject *graph_obj=nullptr; Relationship *rel=nullptr; PhysicalTable *tab_nn=nullptr; BaseTable *src_tab=nullptr, *dst_tab=nullptr, *base_tab=nullptr; Schema *schema=nullptr; QPointF pnt; ObjectType obj_type; int idx=0; bool save_db_attribs=false, save_objs_pos=false, save_objs_prot=false, save_objs_sqldis=false, save_textboxes=false, save_tags=false, save_custom_sql=false, save_custom_colors=false, save_fadeout=false, save_collapsemode=false, save_genericsqls=false, save_objs_aliases=false; QStringList labels_attrs={ Attributes::SrcLabel, Attributes::DstLabel, Attributes::NameLabel }; save_db_attribs=(MetaDbAttributes & options) == MetaDbAttributes; save_objs_pos=(MetaObjsPositioning & options) == MetaObjsPositioning; save_objs_prot=(MetaObjsProtection & options) == MetaObjsProtection; save_objs_sqldis=(MetaObjsSqlDisabled & options) == MetaObjsSqlDisabled; save_textboxes=(MetaTextboxObjs & options) == MetaTextboxObjs; save_tags=(MetaTagObjs & options) == MetaTagObjs; save_custom_sql=(MetaObjsCustomSql & options) == MetaObjsCustomSql; save_custom_colors=(MetaObjsCustomColors & options) == MetaObjsCustomColors; save_fadeout=(MetaObjsFadeOut & options) == MetaObjsFadeOut; save_collapsemode=(MetaObjsCollapseMode & options) == MetaObjsCollapseMode; save_genericsqls=(MetaGenericSqlObjs & options) == MetaGenericSqlObjs; save_objs_aliases=(MetaObjsAliases & options) == MetaObjsAliases; output.open(QFile::WriteOnly); if(!output.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(filename), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { if(save_textboxes || save_tags || save_genericsqls) { if(save_textboxes) objects.insert(objects.end(), textboxes.begin(), textboxes.end()); if(save_tags) objects.insert(objects.end(), tags.begin(), tags.end()); if(save_genericsqls) objects.insert(objects.end(), genericsqls.begin(), genericsqls.end()); } if(save_db_attribs) objects.push_back(this); if(save_objs_pos || save_objs_aliases) { objects.insert(objects.end(), schemas.begin(), schemas.end()); objects.insert(objects.end(), tables.begin(), tables.end()); objects.insert(objects.end(), views.begin(), views.end()); objects.insert(objects.end(), relationships.begin(), relationships.end()); objects.insert(objects.end(), base_relationships.begin(), base_relationships.end()); //Adding rel. n-n generated tables to the list of tables too for(BaseObject *object : relationships) { rel=dynamic_cast(object); if(save_objs_pos && rel->getRelationshipType()==BaseRelationship::RelationshipNn && rel->getReceiverTable()) { tab_nn=rel->getReceiverTable(); src_tab=rel->getTable(BaseRelationship::SrcTable); dst_tab=rel->getTable(BaseRelationship::DstTable); //Since the generated table does not have a position we create one based upon the source tables positions pnt.setX((src_tab->getPosition().x() + dst_tab->getPosition().x())/2.0); pnt.setY((src_tab->getPosition().y() + dst_tab->getPosition().y())/2.0); tab_nn->setPosition(pnt); objects.push_back(tab_nn); } } //Saving aliases the children of tables and views if(save_objs_aliases) { for(auto &tab : tables) { tab_objs = dynamic_cast
(tab)->getObjects(); objects.insert(objects.end(), tab_objs.begin(), tab_objs.end()); } for(auto &tab : foreign_tables) { tab_objs = dynamic_cast(tab)->getObjects(); objects.insert(objects.end(), tab_objs.begin(), tab_objs.end()); } for(auto &vw : views) { tab_objs = dynamic_cast(vw)->getObjects(); objects.insert(objects.end(), tab_objs.begin(), tab_objs.end()); } } } if(save_objs_prot || save_objs_sqldis) { vector types=getChildObjectTypes(ObjectType::Database), sch_types=getChildObjectTypes(ObjectType::Schema); types.insert(types.end(), sch_types.begin(), sch_types.end()); //Removing the types for schema, table and view to avoid retrieving the objects twice if(save_objs_pos) { types.erase(std::find(types.begin(), types.end(), ObjectType::Schema)); types.erase(std::find(types.begin(), types.end(), ObjectType::Table)); types.erase(std::find(types.begin(), types.end(), ObjectType::View)); } //Append the other objects to the list of selected entities for(ObjectType type : types) objects.insert(objects.end(), getObjectList(type)->begin(), getObjectList(type)->end()); } for(BaseObject *object : objects) { obj_type=object->getObjectType(); //When handling a tag , textbox or generic sql we just extract their XML code if(obj_type==ObjectType::Textbox || obj_type==ObjectType::Tag || obj_type == ObjectType::GenericSql) { emit s_objectLoaded(((idx++)/static_cast(objects.size()))*100, trUtf8("Saving object `%1' (%2)") .arg(object->getName()).arg(object->getTypeName()), enum_cast(obj_type)); objs_def+=object->getCodeDefinition(SchemaParser::XmlDefinition); continue; } //Discarding the relationship added table objects (when extracting aliases) else if(TableObject::isTableObject(obj_type) && dynamic_cast(object)->isAddedByRelationship()) continue; graph_obj=dynamic_cast(object); base_tab=dynamic_cast(object); attribs[Attributes::Table]=QString(); attribs[Attributes::Name]=(TableObject::isTableObject(obj_type) ? object->getName() : object->getSignature()); attribs[Attributes::Alias]=(save_objs_aliases ? object->getAlias() : QString()); attribs[Attributes::Type]=object->getSchemaName(); attribs[Attributes::Protected]=(save_objs_prot && object->isProtected() && !object->isSystemObject() ? Attributes::True : QString()); attribs[Attributes::SqlDisabled]=(save_objs_sqldis && object->isSQLDisabled() && !object->isSystemObject() ? Attributes::True : QString()); attribs[Attributes::Tag]=(save_tags && base_tab && base_tab->getTag() ? base_tab->getTag()->getName() : QString()); attribs[Attributes::AppendedSql]=object->getAppendedSQL(); attribs[Attributes::PrependedSql]=object->getPrependedSQL(); attribs[Attributes::FadedOut]=(save_fadeout && graph_obj && graph_obj->isFadedOut() ? Attributes::True : QString()); attribs[Attributes::CollapseMode]=(save_collapsemode && base_tab ? QString::number(enum_cast(base_tab->getCollapseMode())) : QString()); if(TableObject::isTableObject(obj_type)) { base_tab = dynamic_cast(object)->getParentTable(); attribs[Attributes::Table]=base_tab->getSignature(); } if(save_custom_sql && obj_type==ObjectType::Database) { attribs[Attributes::AppendAtEod]=(this->isAppendAtEOD() ? Attributes::True : Attributes::False); attribs[Attributes::PrependAtBod]=(this->isPrependedAtBOD() ? Attributes::True : Attributes::False); } //Configuring database model attributes if(save_db_attribs && object==this) { attribs[Attributes::ModelAuthor]=this->getAuthor(); attribs[Attributes::LastPosition]=QString("%1,%2").arg(last_pos.x()).arg(last_pos.y()); attribs[Attributes::LastZoom]=QString::number(last_zoom); attribs[Attributes::DefaultCollation]=(default_objs[ObjectType::Collation] ? default_objs[ObjectType::Collation]->getSignature() : QString()); attribs[Attributes::DefaultSchema]=(default_objs[ObjectType::Schema] ? default_objs[ObjectType::Schema]->getSignature() : QString()); attribs[Attributes::DefaultTablespace]=(default_objs[ObjectType::Tablespace] ? default_objs[ObjectType::Tablespace]->getSignature() : QString()); attribs[Attributes::DefaultOwner]=(default_objs[ObjectType::Role] ? default_objs[ObjectType::Role]->getSignature() : QString()); } //If the object is a graphic one and we need to save positions and colors if((save_objs_pos || save_custom_colors) && graph_obj) { if(obj_type!=ObjectType::BaseRelationship && obj_type!=ObjectType::Relationship) { pnt=graph_obj->getPosition(); if(obj_type==ObjectType::Schema) { schema=dynamic_cast(object); attribs[Attributes::CustomColor]=(save_custom_colors ? schema->getFillColor().name() : QString()); attribs[Attributes::RectVisible]=(schema->isRectVisible() ? Attributes::True : Attributes::False); if(schema->isRectVisible()) { attribs[Attributes::XPos]=QString::number(pnt.x()); attribs[Attributes::YPos]=QString::number(pnt.y()); } } else { attribs[Attributes::XPos]=QString::number(pnt.x()); attribs[Attributes::YPos]=QString::number(pnt.y()); } if(obj_type!=ObjectType::Schema || !attribs[Attributes::XPos].isEmpty()) { schparser.ignoreUnkownAttributes(true); attribs[Attributes::Position]= schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + Attributes::Position + GlobalAttributes::SchemaExt, attribs); } } else { BaseRelationship *rel=dynamic_cast(object); vector points=rel->getPoints(); attribs_map aux_attribs; attribs[Attributes::CustomColor]=(save_custom_colors && rel->getCustomColor()!=Qt::transparent ? rel->getCustomColor().name() : Attributes::None); attribs[Attributes::SrcTable]=rel->getTable(BaseRelationship::SrcTable)->getSignature(); attribs[Attributes::SrcType]=rel->getTable(BaseRelationship::SrcTable)->getSchemaName(); attribs[Attributes::DstTable]=rel->getTable(BaseRelationship::DstTable)->getSignature(); attribs[Attributes::DstType]=rel->getTable(BaseRelationship::DstTable)->getSchemaName(); for(QPointF pnt : points) { attribs[Attributes::XPos]=QString::number(pnt.x()); attribs[Attributes::YPos]=QString::number(pnt.y()); schparser.ignoreUnkownAttributes(true); attribs[Attributes::Position]+= schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + Attributes::Position + GlobalAttributes::SchemaExt, attribs); } //Saving the labels' custom positions for(unsigned id=BaseRelationship::SrcCardLabel; id <= BaseRelationship::RelNameLabel; id++) { pnt=rel->getLabelDistance(id); if(!std::isnan(pnt.x()) && !std::isnan(pnt.y())) { aux_attribs[Attributes::XPos]=QString::number(pnt.x()); aux_attribs[Attributes::YPos]=QString::number(pnt.y()); aux_attribs[Attributes::RefType]=labels_attrs[id]; aux_attribs[Attributes::Position]=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + Attributes::Position + GlobalAttributes::SchemaExt, aux_attribs); attribs[Attributes::Position]+=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + Attributes::Label + GlobalAttributes::SchemaExt, aux_attribs); } } } } //Storing the custom SQLs if the object has them configured if(save_custom_sql) { if(!object->getAppendedSQL().isEmpty()) attribs[Attributes::AppendedSql]=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + QString(Attributes::AppendedSql).remove(QChar('-')) + GlobalAttributes::SchemaExt, attribs); if(!object->getPrependedSQL().isEmpty()) attribs[Attributes::PrependedSql]=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + QString(Attributes::PrependedSql).remove(QChar('-')) + GlobalAttributes::SchemaExt, attribs); } /* The object's metadata code will be generated only if one of the key attributes for each option were filled previously. */ if((save_db_attribs && obj_type==ObjectType::Database) || (save_custom_colors && ((obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship) || (!attribs[Attributes::CustomColor].isEmpty()))) || (save_objs_pos && (!attribs[Attributes::Position].isEmpty() || !attribs[Attributes::RectVisible].isEmpty())) || (save_tags && !attribs[Attributes::Tag].isEmpty()) || (save_objs_prot && !attribs[Attributes::Protected].isEmpty()) || (save_objs_sqldis && !attribs[Attributes::SqlDisabled].isEmpty()) || (save_custom_sql && (!attribs[Attributes::AppendedSql].isEmpty() || !attribs[Attributes::PrependedSql].isEmpty())) || (save_fadeout && !attribs[Attributes::FadedOut].isEmpty()) || (save_collapsemode && !attribs[Attributes::CollapseMode].isEmpty()) || (save_objs_aliases && !attribs[Attributes::Alias].isEmpty())) { emit s_objectLoaded(((idx++)/static_cast(objects.size()))*100, trUtf8("Saving metadata of the object `%1' (%2)") .arg(object->getSignature()).arg(object->getTypeName()), enum_cast(obj_type)); schparser.ignoreUnkownAttributes(true); objs_def+=schparser.convertCharsToXMLEntities( schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + Attributes::Info + GlobalAttributes::SchemaExt, attribs)); } else idx++; attribs.clear(); } if(!objs_def.isEmpty()) { //Generates the metadata XML buffer attribs[Attributes::Info]=objs_def; buf.append(schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + Attributes::Metadata + GlobalAttributes::SchemaExt, attribs)); output.write(buf.data(),buf.size()); emit s_objectLoaded(100, trUtf8("Metadata file successfully saved!"), enum_cast(ObjectType::BaseObject)); } else emit s_objectLoaded(100, trUtf8("Process successfully ended but no metadata was saved!"), enum_cast(ObjectType::BaseObject)); output.close(); } catch(Exception &e) { if(output.isOpen()) output.close(); throw Exception(Exception::getErrorMessage(ErrorCode::FileNotWrittenInvalidDefinition).arg(filename), ErrorCode::FileNotWrittenInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseModel::loadObjectsMetadata(const QString &filename, unsigned options) { QString elem_name, aux_elem, obj_name, ref_type, dtd_file=GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::XMLSchemaDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectDTDDir + GlobalAttributes::DirSeparator; attribs_map attribs, aux_attrib; ObjectType obj_type; BaseObject *object=nullptr, *new_object=nullptr; BaseTable *src_tab=nullptr, *dst_tab=nullptr, *base_tab=nullptr; vector points; map labels_attrs; vector labels_pos={ QPointF(DNaN,DNaN), QPointF(DNaN,DNaN), QPointF(DNaN,DNaN) }; BaseRelationship *rel=nullptr; Schema *schema=nullptr; Tag *tag=nullptr; int progress=0; bool load_db_attribs=false, load_objs_pos=false, load_objs_prot=false, load_objs_sqldis=false, load_textboxes=false, load_tags=false, load_custom_sql=false, load_custom_colors=false, load_fadeout=false, load_collapse_mode=false, load_genericsqls=false, load_objs_aliases=false; load_db_attribs=(MetaDbAttributes & options) == MetaDbAttributes; load_objs_pos=(MetaObjsPositioning & options) == MetaObjsPositioning; load_objs_prot=(MetaObjsProtection & options) == MetaObjsProtection; load_objs_sqldis=(MetaObjsSqlDisabled & options) == MetaObjsSqlDisabled; load_textboxes=(MetaTextboxObjs & options) == MetaTextboxObjs; load_tags=(MetaTagObjs & options) == MetaTagObjs; load_custom_sql=(MetaObjsCustomSql & options) == MetaObjsCustomSql; load_custom_colors=(MetaObjsCustomColors & options) == MetaObjsCustomColors; load_fadeout=(MetaObjsFadeOut & options) == MetaObjsFadeOut; load_collapse_mode=(MetaObjsCollapseMode & options) == MetaObjsCollapseMode; load_genericsqls=(MetaGenericSqlObjs & options) == MetaGenericSqlObjs; load_objs_aliases=(MetaObjsAliases & options) == MetaObjsAliases; try { labels_attrs[Attributes::SrcLabel]=BaseRelationship::SrcCardLabel; labels_attrs[Attributes::DstLabel]=BaseRelationship::DstCardLabel; labels_attrs[Attributes::NameLabel]=BaseRelationship::RelNameLabel; xmlparser.restartParser(); xmlparser.setDTDFile(dtd_file + GlobalAttributes::MetadataDTD + GlobalAttributes::ObjectDTDExt, GlobalAttributes::MetadataDTD); xmlparser.loadXMLFile(filename); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem_name=xmlparser.getElementName(); if((elem_name==BaseObject::getSchemaName(ObjectType::Tag) && load_tags) || (elem_name==BaseObject::getSchemaName(ObjectType::Textbox) && load_textboxes) || (elem_name==BaseObject::getSchemaName(ObjectType::GenericSql) && load_genericsqls)) { xmlparser.savePosition(); obj_type=BaseObject::getObjectType(elem_name); new_object=createObject(obj_type); if(getObjectIndex(new_object->getName(), obj_type) < 0) { emit s_objectLoaded(progress, trUtf8("Creating object `%1' (%2)") .arg(new_object->getName()).arg(new_object->getTypeName()), enum_cast(obj_type)); addObject(new_object); } else { emit s_objectLoaded(progress, trUtf8("Object `%1' (%2) already exists. Ignoring.") .arg(new_object->getName()).arg(new_object->getTypeName()), enum_cast(ObjectType::BaseObject)); delete(new_object); } new_object=nullptr; xmlparser.restorePosition(); } else if(elem_name==Attributes::Info) { xmlparser.getElementAttributes(attribs); obj_name=attribs[Attributes::Object]; xmlparser.savePosition(); obj_type=BaseObject::getObjectType(attribs[Attributes::Type]); progress=xmlparser.getCurrentBufferLine()/static_cast(xmlparser.getBufferLineCount()) * 100; if(obj_type==ObjectType::Database) { if(load_db_attribs) { QStringList pos=attribs[Attributes::LastPosition].split(','); default_objs[ObjectType::Schema]=getSchema(attribs[Attributes::DefaultSchema]); default_objs[ObjectType::Role]=getRole(attribs[Attributes::DefaultOwner]); default_objs[ObjectType::Collation]=getCollation(attribs[Attributes::DefaultCollation]); default_objs[ObjectType::Tablespace]=getTablespace(attribs[Attributes::DefaultTablespace]); author=attribs[Attributes::ModelAuthor]; last_zoom=attribs[Attributes::LastZoom].toDouble(); if(pos.size()>=2) last_pos=QPoint(pos[0].toInt(), pos[1].toInt()); } object=this; } else if(TableObject::isTableObject(obj_type)) { base_tab = getTable(attribs[Attributes::Table]); if(!base_tab && (obj_type == ObjectType::Rule || obj_type == ObjectType::Index || obj_type == ObjectType::Trigger)) base_tab = getView(attribs[Attributes::Table]); if(base_tab) object = base_tab->getObject(attribs[Attributes::Object], obj_type); //Discarding the object if it was added by relationship if(object && dynamic_cast(object)->isAddedByRelationship()) object = nullptr; } else object=getObject(obj_name, obj_type); /* If the object does not exists but it is a relationship, we try to get the relationship involving the tables in paramenters src-table and dst-table */ if(!object && obj_type==ObjectType::Relationship) { src_tab=dynamic_cast(getObject(attribs[Attributes::SrcTable], BaseObject::getObjectType(attribs[Attributes::SrcType]))); dst_tab=dynamic_cast(getObject(attribs[Attributes::DstTable], BaseObject::getObjectType(attribs[Attributes::DstType]))); object=getRelationship(src_tab, dst_tab); } if(object) { emit s_objectLoaded(progress, trUtf8("Loading metadata for object `%1' (%2)") .arg(object->getName()).arg(object->getTypeName()), enum_cast(obj_type)); if(!object->isSystemObject() && ((!attribs[Attributes::Protected].isEmpty() && load_objs_prot) || (!attribs[Attributes::SqlDisabled].isEmpty() && load_objs_sqldis))) { if(!attribs[Attributes::Protected].isEmpty()) object->setProtected(attribs[Attributes::Protected]==Attributes::True); if(!attribs[Attributes::SqlDisabled].isEmpty()) object->setSQLDisabled(attribs[Attributes::SqlDisabled]==Attributes::True); } else if((obj_type==ObjectType::Table || obj_type==ObjectType::View) && load_tags && !attribs[Attributes::Tag].isEmpty()) { tag=getTag(attribs[Attributes::Tag]); if(tag) dynamic_cast(object)->setTag(tag); } else if(obj_type==ObjectType::Database && load_custom_sql) { if(!attribs[Attributes::AppendAtEod].isEmpty()) this->setAppendAtEOD(attribs[Attributes::AppendAtEod]==Attributes::True); if(!attribs[Attributes::PrependAtBod].isEmpty()) this->setPrependAtBOD(attribs[Attributes::PrependAtBod]==Attributes::True); } if(load_objs_aliases && !attribs[Attributes::Alias].isEmpty()) object->setAlias(attribs[Attributes::Alias]); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { aux_elem=xmlparser.getElementName(); xmlparser.getElementAttributes(aux_attrib); //Retrieving and storing the points if(aux_elem==Attributes::Position) { points.push_back(QPointF(aux_attrib[Attributes::XPos].toDouble(), aux_attrib[Attributes::YPos].toDouble())); } //Retrieving and storing the labels' custom positions else if(aux_elem==Attributes::Label) { ref_type=aux_attrib[Attributes::RefType]; xmlparser.savePosition(); if(xmlparser.accessElement(XmlParser::ChildElement)) { xmlparser.getElementAttributes(aux_attrib); labels_pos[labels_attrs[ref_type]]=QPointF(aux_attrib[Attributes::XPos].toDouble(), aux_attrib[Attributes::YPos].toDouble()); } xmlparser.restorePosition(); } else if(load_custom_sql && aux_elem==Attributes::AppendedSql && attribs[Attributes::AppendedSql].isEmpty()) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); object->setAppendedSQL(xmlparser.getElementContent()); xmlparser.restorePosition(); } else if(load_custom_sql && aux_elem==Attributes::PrependedSql && attribs[Attributes::PrependedSql].isEmpty()) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); object->setPrependedSQL(xmlparser.getElementContent()); xmlparser.restorePosition(); } } while(xmlparser.accessElement(XmlParser::NextElement)); } if(BaseGraphicObject::isGraphicObject(obj_type)) { base_tab=dynamic_cast(object); rel=dynamic_cast(object); schema=dynamic_cast(object); if(!rel && !schema && !points.empty() && load_objs_pos) dynamic_cast(object)->setPosition(points[0]); else if(rel) { if(load_custom_colors) { if(attribs[Attributes::CustomColor]==Attributes::None) rel->setCustomColor(Qt::transparent); else rel->setCustomColor(QColor(attribs[Attributes::CustomColor])); } if(load_objs_pos) { rel->setPoints(points); for(unsigned id=BaseRelationship::SrcCardLabel; id <= BaseRelationship::RelNameLabel; id++) { rel->setLabelDistance(id, labels_pos[id]); labels_pos[id]=QPointF(DNaN, DNaN); } } } else if(schema) { if(load_custom_colors) schema->setFillColor(QColor(attribs[Attributes::CustomColor])); schema->setRectVisible(attribs[Attributes::RectVisible]==Attributes::True); } if(load_fadeout) dynamic_cast(object)->setFadedOut(attribs[Attributes::FadedOut]==Attributes::True); if(load_collapse_mode && base_tab) base_tab->setCollapseMode(static_cast(attribs[Attributes::CollapseMode].toUInt())); } points.clear(); } else if(!object) { emit s_objectLoaded(progress, trUtf8("Object `%1' (%2) not found. Ignoring metadata.") .arg(obj_name).arg(BaseObject::getTypeName(obj_type)), enum_cast(ObjectType::BaseObject)); } xmlparser.restorePosition(); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } emit s_objectLoaded(100, trUtf8("Metadata file successfully loaded!"), enum_cast(ObjectType::BaseObject)); setObjectsModified(); } catch(Exception &e) { QString extra_info; if(xmlparser.getCurrentElement()) extra_info=QString(QObject::trUtf8("%1 (line: %2)")).arg(xmlparser.getLoadedFilename()).arg(xmlparser.getCurrentElement()->line); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, extra_info); } } void DatabaseModel::setLayers(const QStringList &layers) { this->layers = layers; } QStringList DatabaseModel::getLayers(void) { return(layers); } void DatabaseModel::setActiveLayers(const QList &layers) { active_layers = layers; } QList DatabaseModel::getActiveLayers(void) { return(active_layers); } template TableClass *DatabaseModel::createPhysicalTable(void) { attribs_map attribs, aux_attribs; QString elem; TableClass *table=nullptr; TableObject *object=nullptr; BaseObject *tag=nullptr; ObjectType obj_type; vector idxs; vector names; PartitionKey part_key; vector partition_keys; try { table = new TableClass; setBasicAttributes(table); xmlparser.getElementAttributes(attribs); table->setObjectListsCapacity(attribs[Attributes::MaxObjCount].toUInt()); table->setGenerateAlterCmds(attribs[Attributes::GenAlterCmds]==Attributes::True); table->setCollapseMode(attribs[Attributes::CollapseMode].isEmpty() ? CollapseMode::NotCollapsed : static_cast(attribs[Attributes::CollapseMode].toUInt())); table->setPaginationEnabled(attribs[Attributes::Pagination]==Attributes::True); table->setCurrentPage(BaseTable::AttribsSection, attribs[Attributes::AttribsPage].toUInt()); table->setCurrentPage(BaseTable::ExtAttribsSection, attribs[Attributes::ExtAttribsPage].toUInt()); table->setFadedOut(attribs[Attributes::FadedOut]==Attributes::True); table->setLayer(attribs[Attributes::Layer].toUInt()); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); xmlparser.savePosition(); object=nullptr; if(elem==BaseObject::objs_schemas[enum_cast(ObjectType::Column)]) object=createColumn(); else if(elem==BaseObject::objs_schemas[enum_cast(ObjectType::Constraint)]) object=createConstraint(table); else if(elem==BaseObject::objs_schemas[enum_cast(ObjectType::Tag)]) { xmlparser.getElementAttributes(aux_attribs); tag=getObject(aux_attribs[Attributes::Name], ObjectType::Tag); if(!tag) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Table)) .arg(aux_attribs[Attributes::Table]) .arg(BaseObject::getTypeName(ObjectType::Tag)) , ErrorCode::RefObjectInexistsModel,__PRETTY_FUNCTION__,__FILE__,__LINE__); } table->setTag(dynamic_cast(tag)); } //Retrieving custom columns / constraint indexes else if(elem==Attributes::CustomIdxs) { xmlparser.getElementAttributes(aux_attribs); obj_type=BaseObject::getObjectType(aux_attribs[Attributes::ObjectType]); xmlparser.savePosition(); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); //The element stores the index for each object in the current group if(elem==Attributes::Object) { xmlparser.getElementAttributes(aux_attribs); names.push_back(aux_attribs[Attributes::Name]); idxs.push_back(aux_attribs[Attributes::Index].toUInt()); } } } while(xmlparser.accessElement(XmlParser::NextElement)); table->setRelObjectsIndexes(names, idxs, obj_type); names.clear(); idxs.clear(); } xmlparser.restorePosition(); } else if(elem==Attributes::Partitioning) { xmlparser.getElementAttributes(aux_attribs); table->setPartitioningType(aux_attribs[Attributes::Type]); xmlparser.savePosition(); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE && xmlparser.getElementName()==Attributes::PartitionKey) { createElement(part_key, nullptr, table); partition_keys.push_back(part_key); } } while(xmlparser.accessElement(XmlParser::NextElement)); table->addPartitionKeys(partition_keys); } xmlparser.restorePosition(); } //Retrieving initial data else if(elem==Attributes::InitialData) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); table->setInitialData(xmlparser.getElementContent()); xmlparser.restorePosition(); } if(object) table->addObject(object); xmlparser.restorePosition(); } } while(xmlparser.accessElement(XmlParser::NextElement)); } table->setProtected(table->isProtected()); } catch(Exception &e) { QString extra_info=getErrorExtraInfo(); xmlparser.restorePosition(); if(table) delete(table); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, extra_info); } return(table); } void DatabaseModel::getDataDictionary(attribs_map &datadict, bool browsable, bool splitted) { int idx = 0; BaseObject *object = nullptr; vector objects; map objs_map; QString styles, id, index, items, buffer; attribs_map attribs, aux_attribs; QStringList index_list; QString dict_files_root = GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::DataDictSchemaDir + GlobalAttributes::DirSeparator, dict_sch_file = dict_files_root + GlobalAttributes::DataDictSchemaDir + GlobalAttributes::SchemaExt, style_sch_file = dict_files_root + Attributes::Styles + GlobalAttributes::SchemaExt, item_sch_file = dict_files_root + Attributes::Item + GlobalAttributes::SchemaExt, index_sch_file = dict_files_root + Attributes::Index + GlobalAttributes::SchemaExt; objects.assign(tables.begin(), tables.end()); objects.insert(objects.end(), foreign_tables.begin(), foreign_tables.end()); objects.insert(objects.end(), views.begin(), views.end()); objects.insert(objects.end(), relationships.begin(), relationships.end()); // Placing the objects in alphabectical order for(auto &obj : objects) { // Retrieving the generated table if the current object is a relationship (n-n) if(obj->getObjectType() == ObjectType::Relationship) { Relationship *rel = dynamic_cast(obj); if(!rel->getGeneratedTable()) continue; obj = rel->getGeneratedTable(); } id = obj->getSignature().remove(QChar('"')); objs_map[id] = obj; index_list.push_back(id); } index_list.sort(); datadict.clear(); // Generates the the stylesheet styles = schparser.getCodeDefinition(style_sch_file, attribs); attribs[Attributes::Styles] = QString(); attribs[Attributes::Index] = QString(); attribs[Attributes::Splitted] = splitted ? Attributes::True : QString(); // If the generation is a standalone HTML the css is embedded if(!splitted) attribs[Attributes::Styles] = styles; else // Otherwise we create a separated stylesheet file datadict[Attributes::Styles + QString(".css")] = styles; // Generating individual data dictionaries for(auto &itr : objs_map) { object = itr.second; // Generate the individual data dictionaries aux_attribs[Attributes::Index] = browsable ? Attributes::True : QString(); aux_attribs[Attributes::Previous] = idx - 1 >= 0 ? index_list.at(idx - 1) : QString(); aux_attribs[Attributes::Next] = (++idx <= index_list.size() - 1) ? index_list.at(idx) : QString(); attribs[Attributes::Objects] += dynamic_cast(object)->getDataDictionary(splitted, aux_attribs); // If the generation is configured to be splitted we generate a complete HTML file for the current table if(splitted && !attribs[Attributes::Objects].isEmpty()) { id = itr.first + QString(".html"); schparser.ignoreEmptyAttributes(true); datadict[id] = schparser.getCodeDefinition(dict_sch_file, attribs); attribs[Attributes::Objects].clear(); } } // If the data dictionary is browsable we proceed with the index generation if(browsable) { attribs_map idx_attribs; idx_attribs[BaseObject::getSchemaName(ObjectType::Table)] = QString(); idx_attribs[BaseObject::getSchemaName(ObjectType::View)] = QString(); idx_attribs[BaseObject::getSchemaName(ObjectType::ForeignTable)] = QString(); // Generating the index items for(auto &item : index_list) { aux_attribs[Attributes::Splitted] = attribs[Attributes::Splitted]; aux_attribs[Attributes::Item] = item; idx_attribs[objs_map[item]->getSchemaName()] += schparser.getCodeDefinition(item_sch_file, aux_attribs); } idx_attribs[Attributes::Name] = this->obj_name; idx_attribs[Attributes::Splitted] = attribs[Attributes::Splitted]; schparser.ignoreEmptyAttributes(true); index = schparser.getCodeDefinition(index_sch_file, idx_attribs); } // If the data dictionary is browsable and splitted the index goes into a separated file if(splitted && browsable) datadict[Attributes::Index + QString(".html")] = index; else if(!splitted) { attribs[Attributes::Index] = index; schparser.ignoreEmptyAttributes(true); datadict[Attributes::Database] = schparser.getCodeDefinition(dict_sch_file, attribs); } } void DatabaseModel::saveDataDictionary(const QString &path, bool browsable, bool splitted) { try { attribs_map datadict; QFile output; QByteArray buffer; QFileInfo finfo(path); QDir dir; if(splitted) { if(finfo.exists() && !finfo.isDir()) throw Exception(Exception::getErrorMessage(ErrorCode::InvDataDictDirectory).arg(path), ErrorCode::InvDataDictDirectory,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!finfo.exists()) dir.mkpath(path); } getDataDictionary(datadict, browsable, splitted); output.setFileName(path); for(auto &itr : datadict) { if(splitted) output.setFileName(path + GlobalAttributes::DirSeparator + itr.first); output.open(QFile::WriteOnly); if(!output.isOpen()) { throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(output.fileName()), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); } buffer.append(itr.second); output.write(buffer); output.close(); buffer.clear(); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/databasemodel.h000066400000000000000000000726061360462764600217230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class DatabaseModel \brief This class reunites and manages all the other object types. Additionally, this class, saves, loads and generates the XML/SQL definition of a complete database. \note Creation date: 20/10/2006 */ #ifndef DATABASE_MODEL_H #define DATABASE_MODEL_H #include #include #include #include "baseobject.h" #include "table.h" #include "function.h" #include "schema.h" #include "view.h" #include "sequence.h" #include "relationship.h" #include "textbox.h" #include "role.h" #include "type.h" #include "tablespace.h" #include "language.h" #include "aggregate.h" #include "cast.h" #include "conversion.h" #include "operatorclass.h" #include "xmlparser.h" #include "permission.h" #include "domain.h" #include "collation.h" #include "extension.h" #include "tag.h" #include "eventtrigger.h" #include "genericsql.h" #include "foreigndatawrapper.h" #include "foreignserver.h" #include "usermapping.h" #include "foreigntable.h" #include #include class ModelWidget; class DatabaseModel: public QObject, public BaseObject { private: Q_OBJECT /*! \brief Stores the references of all object lists of each type. This map is used by getObjectList() in order * to return the list according to the provided type */ map *> obj_lists; static unsigned dbmodel_id; XmlParser xmlparser; //! \brief Stores the layers names and active layer to write them on XML code QStringList layers; QList active_layers; //! \brief Stores the model widget that is managing this database model instance ModelWidget *model_wgt; //! \brief Database encoding EncodingType encoding; //! \brief Template database QString template_db, //! \brief Model's author author, //! \brief Database localizations (LC_CTYPE, LC_COLLATE) localizations[2]; //! \brief Stores the objects of each type that are considered the default ones associated to new objects map default_objs; //! \brief Maximum number of connections int conn_limit; //! \brief Indicates if the database can be used as template bool is_template, //! \brief Indicates if the database accepts connection allow_conns; //! \brief Vectors that stores all the objects types vector textboxes, relationships, base_relationships, functions, schemas, views, tables, types, roles, tablespaces, languages, aggregates, casts, conversions, operators, op_classes, op_families, domains, sequences, permissions, collations, extensions, tags, eventtriggers, genericsqls, fdata_wrappers, foreign_servers, usermappings, foreign_tables; /*! \brief Stores the xml definition for special objects. This map is used when revalidating the relationships */ map xml_special_objs; //! \brief Indicates if the model is being loaded bool loading_model, /*! \brief Indicates if the model was invalidated due to operations like insert / remove objects. When this flag is set it's recommend to revalidate the model using the Model validation tool */ invalidated, //! \brief Indicates that appended SQL commands must be put at the very end of model definition append_at_eod, //! \brief Indicates that prepended SQL commands must be put at the very beginning of model definition prepend_at_bod; //! \brief Stores the last position on the model where the user was editing objects QPoint last_pos; double last_zoom; //! \brief Returns an object seaching it by its name and type. The third parameter stores the object index BaseObject *getObject(const QString &name, ObjectType obj_type, int &obj_idx); //! \brief Generic method that adds an object to the model void __addObject(BaseObject *object, int obj_idx=-1); /*! \brief Generic method that removes an object to the model. The boolean param is used to enable/disable reference checking before remove the object from model. */ void __removeObject(BaseObject *object, int obj_idx=-1, bool check_refs=true); //! \brief Recreates the special object from the passed xml code buffer void createSpecialObject(const QString &xml_def, unsigned obj_id=0); //! \brief Removes an user defined type (domain or type) void removeUserType(BaseObject *object, int obj_idx); /*! \brief Returns the object on the model that represents the base pgsql type. The possible returned object can be: table, sequence, domain or type */ BaseObject *getObjectPgSQLType(PgSqlType type); //! \brief Creates a IndexElement or ExcludeElement from XML depending on type of the 'elem' param. void createElement(Element &elem, TableObject *tab_obj, BaseObject *parent_obj); //! \brief Returns extra error info when loading database models QString getErrorExtraInfo(void); /*! \brief This method forces the indication that the model is being loaded or not by setting the attribute loading_model. * The attribute loading_model causes the model perform certain operations only when model starts/ends the loading process, * for instance, if loading_model = true graphical objects will be rendered only when the loading process finishes (loading_model =false) * otherwise the objects are rendered as they are added to the model. The drawback of this approach is, depending on the operation being used after * calling this method, the user is obligated to call the methdo setObjectsModified() to force the graphical objects rendering. */ void setLoadingModel(bool value); //! \brief Set the initial capacity of the objects list for a optimized memory usage void setObjectListsCapacity(unsigned capacity); protected: void setLayers(const QStringList &layers); void setActiveLayers(const QList &layers); QStringList getLayers(void); QList getActiveLayers(void); public: static constexpr unsigned MetaDbAttributes=1, //! \brief Handle database model attribute when save/load metadata file MetaObjsPositioning=2, //! \brief Handle objects' positioning when save/load metadata file MetaObjsProtection=4, //! \brief Handle objects' protection status when save/load metadata file MetaObjsSqlDisabled=8, //! \brief Handle objects' sql disabled status when save/load metadata file MetaObjsCustomSql=16, //! \brief Handle object's custom sql when save/load metadata file MetaObjsCustomColors=32, //! \brief Handle object's custom colors when save/load metadata file MetaObjsFadeOut=64, //! \brief Handle graphical object's fade out status when save/load metadata file MetaObjsCollapseMode=128, //! \brief Handle tables and views collapse mode when save/load metadata file MetaTextboxObjs=256, //! \brief Handle textboxes object when save/load metadata file MetaTagObjs=512, //! \brief Handle tags object when save/load metadata file MetaGenericSqlObjs=1024, //! \brief Handle generic sql object when save/load metadata file MetaObjsAliases=2048, //! \brief Handle the object's aliases (graphical objects and table children objects) when save/load metadata file MetaAllInfo=4095; //! \brief Handle all metadata information about objects when save/load metadata file DatabaseModel(void); //! \brief Creates a database model and assign the model widget which will manage this instance explicit DatabaseModel(ModelWidget *model_wgt); ~DatabaseModel(void); //! \brief Returns the model widget that is managing the current database instance ModelWidget *getModelWidget(void); //! \brief Returns the complete object list according to the type vector *getObjectList(ObjectType obj_type); //! \brief Disconnects all the relationships in a ordered way void disconnectRelationships(void); /*! \brief Detects and stores the XML for special objects (that is referencing columns created by relationship) in order to be reconstructed in a posterior moment */ void storeSpecialObjectsXML(void); //! \brief Validates all the relationship, propagating all column modifications over the tables void validateRelationships(void); /*! \brief Returns an object seaching it by its name and on the group objects specified by "types". * If the types list is empty the method will return nullptr. */ BaseObject *getObject(const QString &name, const vector &types); //! \brief Returns the list of specified object type that belongs to the passed schema vector getObjects(ObjectType obj_type, BaseObject *schema=nullptr); //! \brief Returns the list of objects (all types) that belongs to the passed schema vector getObjects(BaseObject *schema); //! \brief Returns the object index searching by its name int getObjectIndex(const QString &name, ObjectType obj_type); //! \brief Retuns the passed object index int getObjectIndex(BaseObject *object); //! \brief Adds an object to the model void addObject(BaseObject *object, int obj_idx=-1); //! \brief Removes an object from the model void removeObject(BaseObject *object, int obj_idx=-1); //! \brief Removes an object using its index and type void removeObject(unsigned obj_idx, ObjectType obj_type); //! \brief Returns an object from the model using its index and type BaseObject *getObject(unsigned obj_idx, ObjectType obj_type); /*! \brief Loads a database model from a file. In case of loading errors the objects in the model will not be destroyed automatically. The user need to call destroyObjects() or delete the entire model */ void loadModel(const QString &filename); //! \brief Sets the database encoding void setEncoding(EncodingType encod); //! \brief Sets the database localizations void setLocalization(unsigned localiz_id, const QString &value); //! \brief Sets the connections limit void setConnectionLimit(int conn_lim); //! \brief Sets the template database void setTemplateDB(const QString &temp_db); //! \brief Sets the model's author void setAuthor(const QString &author); //! \brief Sets the protection for all objects on the model void setProtected(bool value); //! \brief Sets the sql appending at end of entire model definition void setAppendAtEOD(bool value); //! \brief Sets the sql prepeding at beginning of entire model definition void setPrependAtBOD(bool value); void setDefaultObject(BaseObject *object, ObjectType obj_type=ObjectType::BaseObject); void setIsTemplate(bool value); void setAllowConnections(bool value); //! \brief Returns the current state of the sql appeding at end of entire model definition bool isAppendAtEOD(void); //! \brief Returns the current state of the sql prepeding at beginning of entire model definition bool isPrependedAtBOD(void); bool isTemplate(void); bool isAllowConnections(void); //! \brief Destroys all the objects void destroyObjects(void); //! \brief Returns the object count for the specified type unsigned getObjectCount(ObjectType obj_type); //! \brief Returns the object count for all object types. unsigned getObjectCount(void); unsigned getMaxObjectCount(void); //! \brief Retuns the specified localization value QString getLocalization(unsigned localiz_id); //! \brief Returns the connection limit int getConnectionLimit(void); //! \brief Returns the template database QString getTemplateDB(void); //! \brief Returns the model's author QString getAuthor(void); //! \brief Returns the database enconding EncodingType getEncoding(void); BaseObject *getDefaultObject(ObjectType obj_type); //! \brief Returns if the model is invalidated. When true its recommended to validate model using Model validation tool bool isInvalidated(void); //! \brief Indicate if the model invalidated void setInvalidated(bool value); //! \brief Saves the specified code definition for the model on the specified filename void saveModel(const QString &filename, unsigned def_type); /*! \brief Returns the complete SQL/XML defintion for the entire model (including all the other objects). The parameter 'export_file' is used to format the generated code in a way that can be saved in na SQL file and executed later on the DBMS server. This parameter is only used for SQL definition. */ virtual QString getCodeDefinition(unsigned def_type, bool export_file) final; //! \brief Returns the complete SQL/XML definition for the entire model (including all the other objects). virtual QString getCodeDefinition(unsigned def_type) final; //! \brief Returns the code definition only for the database (excluding the definition of the other objects) QString __getCodeDefinition(unsigned def_type); /*! \brief Returns the creation order of objects in each definition type (SQL or XML). The parameter incl_relnn_objs when 'true' includes the generated objects (table and constraint) of the many-to-many relationships instead of the relationships themselves. The incl_relnn_objs is is accepted only when the creation order for SQL code is being generated, for XML, it'll simply ignored. The parameter incl_rel1n_constr when 'true' includes the generated foreign and unique keys of one-to-one|many relationships instead of the relationships themselves. This parameter is is accepted only when the creation order for SQL code is being generated, for XML, it'll simply ignored. */ map getCreationOrder(unsigned def_type, bool incl_relnn_objs=false, bool incl_rel1n_constrs=false); /*! \brief Returns a list containig all the object need to create the 'object' in the proper order. If 'only_children' is set only children objects will be included in the list (for tables, views or schemas). If 'only_children' is not set, the method will automatically include dependencies, children and permissions of the object. */ vector getCreationOrder(BaseObject *object, bool only_children); void addRelationship(BaseRelationship *rel, int obj_idx=-1); void removeRelationship(BaseRelationship *rel, int obj_idx=-1); BaseRelationship *getRelationship(unsigned obj_idx, ObjectType rel_type); BaseRelationship *getRelationship(const QString &name); /*! \brief Searchs and returns the relationship between the specified tables. If the second parameter is ommited (nullptr), the method returns the first relationship where the source table is participating. The optional parameter ref_fk will search for foreign key relationships which the reference foreign key is the one provided */ BaseRelationship *getRelationship(BaseTable *src_tab, BaseTable *dst_tab, Constraint *ref_fk = nullptr); //! \brief Searchs and returns all the relationships that the specified table participates vector getRelationships(BaseTable *tab); void addTextbox(Textbox *txtbox, int obj_idx=-1); void removeTextbox(Textbox *txtbox, int obj_idx=-1); Textbox *getTextbox(unsigned obj_idx); Textbox *getTextbox(const QString &name); void addFunction(Function *func, int obj_idx=-1); void removeFunction(Function *func, int obj_idx=-1); Function *getFunction(unsigned obj_idx); Function *getFunction(const QString &signature); void addSchema(Schema *schema, int obj_idx=-1); void removeSchema(Schema *schema, int obj_idx=-1); Schema *getSchema(unsigned obj_idx); Schema *getSchema(const QString &name); void addView(View *view, int obj_idx=-1); void removeView(View *view, int obj_idx=-1); View *getView(unsigned obj_idx); View *getView(const QString &name); void addTable(Table *table, int obj_idx=-1); void removeTable(Table *table, int obj_idx=-1); Table *getTable(unsigned obj_idx); Table *getTable(const QString &name); void addType(Type *type, int obj_idx=-1); void removeType(Type *type, int obj_idx=-1); Type *getType(unsigned obj_idx); Type *getType(const QString &name); void addRole(Role *role, int obj_idx=-1); void removeRole(Role *role, int obj_idx=-1); Role *getRole(unsigned obj_idx); Role *getRole(const QString &name); void addTablespace(Tablespace *tabspc, int obj_idx=-1); void removeTablespace(Tablespace *tabspc, int obj_idx=-1); Tablespace *getTablespace(unsigned obj_idx); Tablespace *getTablespace(const QString &name); void addLanguage(Language *lang, int obj_idx=-1); void removeLanguage(Language *lang, int obj_idx=-1); Language *getLanguage(unsigned obj_idx); Language *getLanguage(const QString &name); void addAggregate(Aggregate *aggreg, int obj_idx=-1); void removeAggregate(Aggregate *aggreg, int obj_idx=-1); Aggregate *getAggregate(unsigned obj_idx); Aggregate *getAggregate(const QString &name); void addCast(Cast *cast, int obj_idx=-1); void removeCast(Cast *cast, int obj_idx=-1); Cast *getCast(unsigned obj_idx); Cast *getCast(const QString &name); void addConversion(Conversion *conv, int obj_idx=-1); void removeConversion(Conversion *conv, int obj_idx=-1); Conversion *getConversion(unsigned obj_idx); Conversion *getConversion(const QString &name); void addOperator(Operator *oper, int obj_idx=-1); void removeOperator(Operator *oper, int obj_idx=-1); Operator *getOperator(unsigned obj_idx); Operator *getOperator(const QString &signature); void addOperatorClass(OperatorClass *op_class, int obj_idx=-1); void removeOperatorClass(OperatorClass *op_class, int obj_idx=-1); OperatorClass *getOperatorClass(unsigned obj_idx); OperatorClass *getOperatorClass(const QString &name); void addOperatorFamily(OperatorFamily *familia_op, int obj_idx=-1); void removeOperatorFamily(OperatorFamily *op_family, int obj_idx=-1); OperatorFamily *getOperatorFamily(unsigned obj_idx); OperatorFamily *getOperatorFamily(const QString &name); void addDomain(Domain *domain, int obj_idx=-1); void removeDomain(Domain *dominio, int obj_idx=-1); Domain *getDomain(unsigned obj_idx); Domain *getDomain(const QString &name); void addSequence(Sequence *sequence, int obj_idx=-1); void removeSequence(Sequence *sequence, int obj_idx=-1); Sequence *getSequence(unsigned obj_idx); Sequence *getSequence(const QString &name); void addCollation(Collation *collation, int obj_idx=-1); void removeCollation(Collation *collation, int obj_idx=-1); Collation *getCollation(unsigned obj_idx); Collation *getCollation(const QString &name); void addExtension(Extension *extension, int obj_idx=-1); void removeExtension(Extension *extension, int obj_idx=-1); Extension *getExtension(unsigned obj_idx); Extension *getExtension(const QString &name); void addTag(Tag *tag, int obj_idx=-1); void removeTag(Tag *tag, int obj_idx=-1); Tag *getTag(unsigned obj_idx); Tag *getTag(const QString &name); void addEventTrigger(EventTrigger *evnttrig, int obj_idx=-1); void removeEventTrigger(EventTrigger *evnttrig, int obj_idx=-1); EventTrigger *getEventTrigger(unsigned obj_idx); EventTrigger *getEventTrigger(const QString &name); void addGenericSQL(GenericSQL *genericsql, int obj_idx=-1); void removeGenericSQL(GenericSQL *genericsql, int obj_idx=-1); GenericSQL *getGenericSQL(unsigned obj_idx); GenericSQL *getGenericSQL(const QString &name); void addForeignDataWrapper(ForeignDataWrapper *fdata_wrapper, int obj_idx=-1); void removeForeignDataWrapper(ForeignDataWrapper *fdata_wrapper, int obj_idx=-1); ForeignDataWrapper *getForeignDataWrapper(unsigned obj_idx); ForeignDataWrapper *getForeignDataWrapper(const QString &name); void addForeignServer(ForeignServer *server, int obj_idx=-1); void removeForeignServer(ForeignServer *server, int obj_idx=-1); ForeignServer *getForeignServer(unsigned obj_idx); ForeignServer *getForeignServer(const QString &name); void addUserMapping(UserMapping *usrmap, int obj_idx=-1); void removeUserMapping(UserMapping *usrmap, int obj_idx=-1); UserMapping *getUserMapping(unsigned obj_idx); UserMapping *getUserMapping(const QString &name); void addForeignTable(ForeignTable *table, int obj_idx=-1); void removeForeignTable(ForeignTable *table, int obj_idx=-1); ForeignTable *getForeignTable(unsigned obj_idx); ForeignTable *getForeignTable(const QString &name); void addPermission(Permission *perm); void removePermission(Permission *perm); /*! \brief Returns the specified permission's index. If exact_match is true then all the contents of the permission are compared against other permission, otherwise checks only if the roles and the objects are the same between the specified permission and the ones existent in the model */ int getPermissionIndex(Permission *perm, bool exact_match); //! \brief Inserts a list of permissions into the model void addPermissions(const vector &perms); //! \brief Removes all the permission related to the passed object void removePermissions(BaseObject *object); //! \brief Returns all the permissions related to the passed object void getPermissions(BaseObject *object, vector &perms); //! \brief Returns the object searching by its name and type BaseObject *getObject(const QString &name, ObjectType obj_type); void setBasicAttributes(BaseObject *object); void configureDatabase(attribs_map &attribs); PgSqlType createPgSQLType(void); BaseObject *createObject(ObjectType obj_type); Role *createRole(void); Tablespace *createTablespace(void); Schema *createSchema(void); Language *createLanguage(void); Function *createFunction(void); Parameter createParameter(void); TypeAttribute createTypeAttribute(void); Type *createType(void); Domain *createDomain(void); Cast *createCast(void); Conversion *createConversion(void); Operator *createOperator(void); OperatorFamily *createOperatorFamily(void); OperatorClass *createOperatorClass(void); Aggregate *createAggregate(void); Table *createTable(void); Column *createColumn(void); Sequence *createSequence(bool ignore_onwer=false); View *createView(void); Collation *createCollation(void); Extension *createExtension(void); Tag *createTag(void); Permission *createPermission(void); Textbox *createTextbox(void); BaseRelationship *createRelationship(void); Constraint *createConstraint(BaseObject *parent_obj); Rule *createRule(void); Index *createIndex(void); Trigger *createTrigger(void); Policy *createPolicy(void); EventTrigger *createEventTrigger(void); GenericSQL *createGenericSQL(void); ForeignDataWrapper *createForeignDataWrapper(void); ForeignServer *createForeignServer(void); UserMapping *createUserMapping(void); ForeignTable *createForeignTable(void); template TableClass *createPhysicalTable(void); //! \brief Update views that reference the provided table forcing the column name deduction and redraw of the former objects void updateViewsReferencingTable(PhysicalTable *table); //! \brief Creates/removes the relationship between the passed view and the referecend tables void updateViewRelationships(View *view, bool force_rel_removal=false); //! \brief Creates/removes the relationship between the passed table and the referecend tables on its foreign keys void updateTableFKRelationships(Table *table); //! \brief Updates the fk relationships for all table on the model void updateTablesFKRelationships(void); /*! \brief Validates the removal of the specified column raising errors when the passed object is still being referecend */ void validateColumnRemoval(Column *column); //! \brief Validates the relationship to reflect the modifications on the column/constraint of the passed table void validateRelationships(TableObject *object, Table *parent_tab); /*! \brief Checks if from the passed relationship some redundacy is found. Redundancy generates infinite column propagation over the tables. This method raises an error when found some. */ void checkRelationshipRedundancy(Relationship *rel); /*! \brief Returns all the objects that the object depends on. The boolean paramenter is used to include the indirect dependencies on the search. Indirect dependencies are objects that is not linked directly to the informed object, e.g., a schema linked to a table that is referenced in a view */ void getObjectDependecies(BaseObject *objeto, vector &vet_deps, bool inc_indirect_deps=false); /*! \brief Recursive version of getObjectDependencies. Returns all the dependencies of the specified object but additionally its children objects (for schemas, tables or views) as well permissions. This method is less efficient than the non recursive version and is used only as an auxiliary operation for getCreationOrder(BaseObject *object) */ void __getObjectDependencies(BaseObject *object, vector &objs); /*! \brief Returns all the objects that references the passed object. The boolean exclusion_mode is used to performance purpose, generally applied when excluding objects, this means that the method will stop the search when the first reference is found. The exclude_perms parameter when true will not include permissions in the references list. */ void getObjectReferences(BaseObject *object, vector &refs, bool exclusion_mode=false, bool exclude_perms=false); /*! \brief Recursive version of getObjectReferences. The only difference here is that the method does not runs in exclusion mode, meaning that ALL objects directly or inderectly linked to the 'object' are retrieved. */ void __getObjectReferences(BaseObject *object, vector &refs, bool exclude_perms=false); /*! \brief Marks the graphical objects of the provided types as modified forcing their redraw. User can specify only a set of graphical objects to be marked */ void setObjectsModified(vector types={}); //! \brief Marks the graphical objects in the list as modified forcing their redraw. void setObjectsModified(vector &objects); /*! \brief Marks the objects with code invalidated forcing their code regeneration. User can specify only a set of graphical objects to be marked */ void setCodesInvalidated(vector types={}); /*! \brief Updates the user type names which belongs to the passed schema. This method must be executed whenever the schema is renamed to propagate the new name to the user types on the PgSQLTypes list. Additionally the previous schema name must be informed in order to rename the types correctly */ void validateSchemaRenaming(Schema *schema, const QString &prev_sch_name); /*! \brief Creates the system objects: public schema and languages C, SQL and plpgsql. This method ignores one of these objects if some of them already exists */ void createSystemObjects(bool create_public); /*! \brief Returns a list of object searching them using the specified pattern. The search can be delimited by filtering the object's types. The additional bool params are: case sensitive name search, name pattern is a regexp, exact match for names. */ vector findObjects(const QString &pattern, vector types, bool case_sensitive, bool is_regexp, bool exact_match, const QString &search_attr = Attributes::Name); void setLastPosition(const QPoint &pnt); QPoint getLastPosition(void); void setLastZoomFactor(double zoom); double getLastZoomFactor(void); /*! \brief This method exposes the XML parser for the outside world. In order to create objects from xml code inside the current database model you need first get the parser (through this method), populate the parser with the desired XML and then call the create* method. \note: This is not the better approach and certainly will be changed in future releases */ XmlParser *getXMLParser(void); //! \brief Returns the ALTER definition between the current model and the provided one virtual QString getAlterDefinition(BaseObject *object) final; //! \brief Returns the data dictionary of all tables in a single HTML code void getDataDictionary(attribs_map &datadict, bool browsable, bool splitted); //! \brief Saves the data dictionary of all tables in a single HTML file or splitted in several files for each table void saveDataDictionary(const QString &path, bool browsable, bool splitted); /*! \brief Save the graphical objects positions, custom colors and custom points (for relationship lines) to an special file that can be loaded by another model in order to change their objects position */ void saveObjectsMetadata(const QString &filename, unsigned options=MetaAllInfo); //! \brief Load the file containing the objects positioning to be applied to the model void loadObjectsMetadata(const QString &filename, unsigned options=MetaAllInfo); signals: //! \brief Signal emitted when a new object is added to the model void s_objectAdded(BaseObject *object); //! \brief Signal emitted when an object is removed from the model void s_objectRemoved(BaseObject *object); //! \brief Signal emitted when an object is created from a xml code void s_objectLoaded(int progress, QString object_id, unsigned obj_type); friend class DatabaseImportHelper; friend class ModelWidget; friend class PgModelerCli; }; #endif pgmodeler-0.9.2/libpgmodeler/src/domain.cpp000066400000000000000000000156001360462764600207270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "domain.h" Domain::Domain(void) { obj_type=ObjectType::Domain; not_null=false; attributes[Attributes::DefaultValue]=QString(); attributes[Attributes::NotNull]=QString(); attributes[Attributes::Type]=QString(); attributes[Attributes::Constraints]=QString(); } void Domain::addCheckConstraint(const QString &name, const QString &expr) { //Raises an error if the constraint name is invalid if(!name.isEmpty() && !BaseObject::isValidName(name)) throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(expr.isEmpty()) throw Exception(ErrorCode::AsgInvalidExpressionObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(chk_constrs.count(name)) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(name) .arg(BaseObject::getTypeName(ObjectType::Constraint)) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } chk_constrs[name] = expr; setCodeInvalidated(true); } void Domain::removeCheckConstraints(void) { chk_constrs.clear(); } attribs_map Domain::getCheckConstraints(void) { return(chk_constrs); } void Domain::setName(const QString &name) { QString prev_name, new_name; prev_name=this->getName(true); BaseObject::setName(name); new_name=this->getName(true); //Renames the PostgreSQL type represented by the domain PgSqlType::renameUserType(prev_name, this, new_name); } void Domain::setSchema(BaseObject *schema) { QString prev_name; prev_name=this->getName(true); BaseObject::setSchema(schema); //Renames the PostgreSQL type represented by the domain PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void Domain::setDefaultValue(const QString &default_val) { QString def=default_val.trimmed(); setCodeInvalidated(default_value != def); this->default_value=def; } void Domain::setNotNull(bool value) { setCodeInvalidated(not_null != value); not_null=value; } void Domain::setType(PgSqlType type) { setCodeInvalidated(this->type != type); this->type=type; } QString Domain::getDefaultValue(void) { return(default_value); } bool Domain::isNotNull(void) { return(not_null); } PgSqlType Domain::getType(void) { return(type); } QString Domain::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attribs_map aux_attribs; attributes[Attributes::NotNull]=(not_null ? Attributes::True : QString()); attributes[Attributes::DefaultValue]=default_value; for(auto itr : chk_constrs) { aux_attribs[Attributes::Name] = itr.first; aux_attribs[Attributes::Expression] = itr.second; attributes[Attributes::Constraints]+=schparser.getCodeDefinition(Attributes::DomConstraint, aux_attribs, def_type); } if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Type]=(*type); else attributes[Attributes::Type]=type.getCodeDefinition(def_type); return(BaseObject::__getCodeDefinition(def_type)); } void Domain::operator = (Domain &domain) { QString prev_name=this->getName(true); *(dynamic_cast(this))=dynamic_cast(domain); this->not_null=domain.not_null; this->default_value=domain.default_value; this->type=domain.type; this->chk_constrs=domain.chk_constrs; PgSqlType::renameUserType(prev_name, this, this->getName(true)); } QString Domain::getAlterDefinition(BaseObject *object) { Domain *domain=dynamic_cast(object); if(!domain) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { QString alter_def=BaseObject::getAlterDefinition(object); attribs_map orig_constrs, aux_constrs, aux_attribs; QString orig_expr, aux_expr; attributes[Attributes::DefaultValue]=QString(); attributes[Attributes::NotNull]=QString(); attributes[Attributes::Constraints]=QString(); attributes[Attributes::Expression]=QString(); attributes[Attributes::OldName]=QString(); attributes[Attributes::NewName]=QString(); if(this->default_value!=domain->default_value) attributes[Attributes::DefaultValue]=(!domain->default_value.isEmpty() ? domain->default_value : Attributes::Unset); if(this->not_null!=domain->not_null) attributes[Attributes::NotNull]=(domain->not_null ? Attributes::True : Attributes::Unset); orig_constrs = this->chk_constrs; aux_constrs = domain->chk_constrs; aux_attribs[Attributes::SqlObject] = this->getSQLName(); aux_attribs[Attributes::Signature] = this->getSignature(); //Generating the DROP for check constraints that does not exists anymore for(auto constr : orig_constrs) { orig_expr = QString(constr.second).remove(QChar(' ')).toLower(); aux_expr = QString(aux_constrs[constr.first]).remove(QChar(' ')).toLower(); //If the check constraint expression exists and the expressions differ from source to destination we drop it if(aux_constrs.count(constr.first) == 0 || (aux_constrs.count(constr.first) && orig_expr != aux_expr)) { aux_attribs[Attributes::Name]=constr.first; aux_attribs[Attributes::Expression]=Attributes::Unset; attributes[Attributes::Constraints]+=BaseObject::getAlterDefinition(Attributes::DomConstraint, aux_attribs, false, true); } //We should include a command to recreate the check constraint with the new expression if(aux_constrs.count(constr.first) && orig_expr != aux_expr) { aux_attribs[Attributes::Name]=constr.first; aux_attribs[Attributes::Expression]=aux_constrs[constr.first]; attributes[Attributes::Constraints]+=BaseObject::getAlterDefinition(Attributes::DomConstraint, aux_attribs, false, true); } } //Generating the ADD for new check constraints for(auto constr : aux_constrs) { if(orig_constrs.count(constr.first) == 0) { aux_attribs[Attributes::Name]=constr.first; aux_attribs[Attributes::Expression]=constr.second; attributes[Attributes::Constraints]+=BaseObject::getAlterDefinition(Attributes::DomConstraint, aux_attribs, false, true); } } alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true); return(alter_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/domain.h000066400000000000000000000047741360462764600204060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Domain \brief Implements the operations to manipulate domains on the database. \note Creation date: 07/04/2008 */ #ifndef DOMAIN_H #define DOMAIN_H #include "baseobject.h" #include "schema.h" class Domain: public BaseObject{ private: //! \brief Domain default data type value QString default_value; //! \brief Indicates that the domains accepts null values or not bool not_null; //! \brief Domain data type PgSqlType type; //! \brief Store the check constraint expressions (key:name value:expression) attribs_map chk_constrs; public: Domain(void); void addCheckConstraint(const QString &name, const QString &expr); void removeCheckConstraints(void); attribs_map getCheckConstraints(void); //! \brief Sets the default value of the domain void setDefaultValue(const QString &default_val); //! \brief Defines whether the domain accepts null values or not void setNotNull(bool value); //! \brief Defines the domain data type void setType(PgSqlType type); /*! \brief Overloaded BaseObject name definition method. Updates the reference of the domain as a PostgreSQL data type */ void setName(const QString &name); /*! \brief Overloaded BaseObject schema definition method. Updates the reference of the domain as a PostgreSQL data type */ void setSchema(BaseObject *schema); //! \brief Methods to access domain's attributes QString getConstraintName(void); QString getExpression(void); QString getDefaultValue(void); bool isNotNull(void); PgSqlType getType(void); //! \brief Returns the SQL / XML code definition for the domain virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getAlterDefinition(BaseObject *object) final; void operator = (Domain &domain); }; #endif pgmodeler-0.9.2/libpgmodeler/src/element.cpp000066400000000000000000000066551360462764600211230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "element.h" Element::Element(void) { column=nullptr; operator_class=nullptr; sorting_attibs[NullsFirst]=false; sorting_attibs[AscOrder]=true; sorting_enabled=false; } void Element::setColumn(Column *column) { if(column) { this->column=column; this->expression=QString(); } } void Element::setExpression(const QString &expression) { if(!expression.isEmpty()) { this->expression=expression; this->column=nullptr; } } void Element::setOperatorClass(OperatorClass *oper_class) { this->operator_class=oper_class; } void Element::setSortingAttribute(unsigned attrib, bool value) { if(attrib > NullsFirst) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); sorting_attibs[attrib]=value; } void Element::setSortingEnabled(bool value) { sorting_enabled=value; } bool Element::isSortingEnabled(void) { return(sorting_enabled); } bool Element::getSortingAttribute(unsigned attrib) { if(attrib > NullsFirst) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(sorting_attibs[attrib]); } Column *Element::getColumn(void) { return(column); } QString Element::getExpression(void) { return(expression); } OperatorClass *Element::getOperatorClass(void) { return(operator_class); } void Element::configureAttributes(attribs_map &attributes, unsigned def_type) { attributes[Attributes::Column]=QString(); attributes[Attributes::Expression]=QString(); attributes[Attributes::OpClass]=QString(); attributes[Attributes::UseSorting]=(this->sorting_enabled ? Attributes::True : QString()); attributes[Attributes::NullsFirst]=(this->sorting_enabled && this->sorting_attibs[NullsFirst] ? Attributes::True : QString()); attributes[Attributes::AscOrder]=(this->sorting_enabled && this->sorting_attibs[AscOrder] ? Attributes::True : QString()); if(column) attributes[Attributes::Column]=column->getName(true); else attributes[Attributes::Expression]=expression; if(operator_class) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::OpClass]=operator_class->getName(true); else attributes[Attributes::OpClass]=operator_class->getCodeDefinition(def_type, true); } } bool Element::isEqualsTo(Element &elem) { return(this->column == elem.column && this->expression == elem.expression && this->operator_class == elem.operator_class && this->sorting_enabled == elem.sorting_enabled && this->sorting_attibs[AscOrder] == elem.sorting_attibs[AscOrder] && this->sorting_attibs[NullsFirst] == elem.sorting_attibs[NullsFirst]); } bool Element::operator == (Element &elem) { return(isEqualsTo(elem)); } bool Element::operator == (const Element &elem) { return(isEqualsTo(const_cast(elem))); } pgmodeler-0.9.2/libpgmodeler/src/element.h000066400000000000000000000061071360462764600205600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements base operations to handle index/constraint(exclude) elements */ #ifndef ELEMENT_H #define ELEMENT_H #include "column.h" #include "operatorclass.h" #include "collation.h" class Element { private: /*! \brief Column referenced by the element. This attribute is mutually exclusive with the expression attribute, this means, when one is set the other has empty (null) value */ Column *column; /*! \brief Expression referenced by the element. This attribute is mutually exclusive with the column attribute, this means when one is set the other has empty (null) value */ QString expression; //! \brief Operator class used by the element OperatorClass *operator_class; /*! \brief Sorting attributes of the element (ASC|DESC, NULLS [FIRST|LAST]) This attibutes can be configured used the constants ASC_ORDER and nullptrS_FIRST */ bool sorting_attibs[2], //! \brief Enable the use of the sort attributes sorting_enabled; //! \brief Compares the attributes of provided element against this returning true/false if the match or not bool isEqualsTo(Element &elem); protected: SchemaParser schparser; void configureAttributes(attribs_map &attributes, unsigned def_type); public: //! \brief Constants used to reference the sorting method of the element static constexpr unsigned AscOrder=0, NullsFirst=1; Element(void); virtual ~Element(void) {} //! \brief Element configuration methods virtual void setColumn(Column *column); virtual void setExpression(const QString &expression); virtual void setOperatorClass(OperatorClass *oper_class); virtual void setCollation(Collation *){} virtual void setOperator(Operator *){} void setSortingEnabled(bool value); //! \brief Sets the state of one of the element sorting method void setSortingAttribute(unsigned attrib, bool value); //! \brief Gets the curret state of the element sorting attribute bool getSortingAttribute(unsigned attrib); Column *getColumn(void); QString getExpression(void); OperatorClass *getOperatorClass(void); virtual Collation *getCollation(void){ return(nullptr); } virtual Operator *getOperator(void){ return(nullptr); } bool isSortingEnabled(void); virtual QString getCodeDefinition(unsigned) { return(QString()); } bool operator == (Element &elem); bool operator ==(const Element &elem); }; #endif pgmodeler-0.9.2/libpgmodeler/src/eventtrigger.cpp000066400000000000000000000111771360462764600221720ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "eventtrigger.h" EventTrigger::EventTrigger(void) { obj_type=ObjectType::EventTrigger; function=nullptr; attributes[Attributes::Event]=QString(); attributes[Attributes::Filter]=QString(); attributes[Attributes::Function]=QString(); } void EventTrigger::setEvent(EventTriggerType evnt_type) { setCodeInvalidated(event != evnt_type); this->event=evnt_type; } void EventTrigger::setFunction(Function *func) { if(!func) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::EventTrigger)), ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Functions with return type other that event_trigger are not accepted else if(func->getReturnType()!=QString("event_trigger")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidTriggerFunction).arg(QString("event_trigger")),__PRETTY_FUNCTION__,__FILE__,__LINE__); //Functions with one or more parameters are not accepted else if(func->getParameterCount()!=0) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::EventTrigger)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Functions coded in SQL lang. is not accepted by event triggers else if(func->getLanguage()->getName()==~LanguageType(LanguageType::Sql)) throw Exception(ErrorCode::AsgEventTriggerFuncInvalidLang,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(function != func); function=func; } void EventTrigger::setFilter(const QString &variable, const QStringList &values) { if(variable.toLower()!=Attributes::Tag) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidEventTriggerVariable).arg(variable),__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!values.isEmpty()) { filter[variable].append(values); setCodeInvalidated(true); } } void EventTrigger::setFilter(const QString &variable, const QString &value) { setFilter(variable, QStringList{ value }); } void EventTrigger::removeFilter(const QString &variable) { filter.erase(variable); setCodeInvalidated(true); } void EventTrigger::clearFilter(void) { filter.clear(); setCodeInvalidated(true); } EventTriggerType EventTrigger::getEvent(void) { return(event); } Function *EventTrigger::getFunction(void) { return(function); } QStringList EventTrigger::getFilter(const QString &variable) { if(filter.count(variable)) return(filter.at(variable)); else return(QStringList()); } QString EventTrigger::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Event]=~event; if(def_type==SchemaParser::SqlDefinition) { QStringList str_list; if(function) attributes[Attributes::Function]=function->getSignature(); for(auto &flt : filter) str_list.push_back(QString("%1 IN ('%2')").arg(flt.first).arg(flt.second.join(QString("','")))); attributes[Attributes::Filter]=str_list.join(QString("\n\t AND ")); } else { if(function) attributes[Attributes::Function]=function->getCodeDefinition(def_type, true); for(auto &flt : filter) //Creating an element attributes[Attributes::Filter]+=QString("\t<%1 %2=\"%3\" %4=\"%5\"/>\n") .arg(Attributes::Filter) .arg(Attributes::Variable).arg(flt.first) .arg(Attributes::Values).arg(flt.second.join(',')); } return(BaseObject::__getCodeDefinition(def_type)); } QString EventTrigger::getAlterDefinition(BaseObject *object) { try { attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, false)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/eventtrigger.h000066400000000000000000000037221360462764600216340ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class EventTrigger \brief Implements the operations to manipulate event triggers on the database. */ #ifndef EVENT_TRIGGER_H #define EVENT_TRIGGER_H #include "baseobject.h" #include "function.h" class EventTrigger: public BaseObject { private: //! \brief Function that is excuted when the event trigger is activated Function *function; //! \brief The event that fires the trigger EventTriggerType event; /*! \brief This map contains the values used as condition on WHEN clause. Currently the only supported variable is TAG, and the object will raise error is other variable name is used on setFilter() call */ map filter; public: EventTrigger(void); void setEvent(EventTriggerType evnt_type); void setFunction(Function *func); void setFilter(const QString &variable, const QStringList &values); void setFilter(const QString &variable, const QString &value); void removeFilter(const QString &variable); void clearFilter(void); EventTriggerType getEvent(void); Function *getFunction(void); QStringList getFilter(const QString &variable); virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getAlterDefinition(BaseObject *object) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/excludeelement.cpp000066400000000000000000000017031360462764600224620ustar00rootroot00000000000000#include "excludeelement.h" ExcludeElement::ExcludeElement(void) : Element() { _operator=nullptr; } void ExcludeElement::setOperator(Operator *oper) { _operator=oper; } Operator *ExcludeElement::getOperator(void) { return(_operator); } QString ExcludeElement::getCodeDefinition(unsigned def_type) { attribs_map attributes; schparser.setPgSQLVersion(BaseObject::getPgSQLVersion()); attributes[Attributes::Operator]=QString(); configureAttributes(attributes, def_type); if(_operator) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Operator]=_operator->getName(true); else attributes[Attributes::Operator]=_operator->getCodeDefinition(def_type, true); } return(schparser.getCodeDefinition(Attributes::ExcludeElement, attributes, def_type)); } bool ExcludeElement::operator == (ExcludeElement &elem) { return(this->_operator==elem._operator && *(dynamic_cast(this))==dynamic_cast(elem)); } pgmodeler-0.9.2/libpgmodeler/src/excludeelement.h000066400000000000000000000025201360462764600221250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate exclude constraint elements. */ #ifndef EXCLUDE_ELEMENT_H #define EXCLUDE_ELEMENT_H #include "element.h" class ExcludeElement: public Element { private: Operator *_operator; public: ExcludeElement(void); virtual ~ExcludeElement(void) {} //! \brief Defines the operator used by the exclude element void setOperator(Operator *oper); //! \brief Returns the operator used by the exclude element Operator *getOperator(void); virtual QString getCodeDefinition(unsigned def_type) final; bool operator == (ExcludeElement &elem); }; #endif pgmodeler-0.9.2/libpgmodeler/src/extension.cpp000066400000000000000000000100331360462764600214670ustar00rootroot00000000000000#include "extension.h" Extension::Extension(void) { obj_type=ObjectType::Extension; handles_type=false; attributes[Attributes::HandlesType]=QString(); attributes[Attributes::CurVersion]=QString(); attributes[Attributes::OldVersion]=QString(); } void Extension::setName(const QString &name) { if(!handles_type) BaseObject::setName(name); else { QString prev_name, new_name; prev_name=this->getName(true); BaseObject::setName(name); new_name=this->getName(true); //Renames the PostgreSQL type represented by the extension PgSqlType::renameUserType(prev_name, this, new_name); } } void Extension::setSchema(BaseObject *schema) { if(!schema) this->schema = schema; else { BaseObject::setSchema(schema); if(handles_type) { QString prev_name; prev_name=this->getName(true); //Renames the PostgreSQL type represented by the extension PgSqlType::renameUserType(prev_name, this, this->getName(true)); } } } void Extension::setHandlesType(bool value) { /* Raises an error if the extension is already registered as a data type and the try to change the attribute value. This cannot be done to avoid cascade reference breaking on table columns/functions or any other objects that references PgSQLType */ if(!value && PgSqlType::getUserTypeIndex(this->getName(true), this) != BaseType::Null) throw Exception(Exception::getErrorMessage(ErrorCode::ExtensionHandlingTypeImmutable) .arg(this->getName(true)), ErrorCode::ExtensionHandlingTypeImmutable,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->handles_type=value; } void Extension::setVersion(unsigned ver, const QString &value) { if(ver > OldVersion) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(versions[ver] != value); versions[ver]=value; } bool Extension::handlesType(void) { return(handles_type); } QString Extension::getVersion(unsigned ver) { if(ver > OldVersion) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(versions[ver]); } QString Extension::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Name]=this->getName(def_type==SchemaParser::SqlDefinition, false); attributes[Attributes::HandlesType]=(handles_type ? Attributes::True : QString()); attributes[Attributes::CurVersion]=versions[CurVersion]; attributes[Attributes::OldVersion]=versions[OldVersion]; return(BaseObject::__getCodeDefinition(def_type)); } QString Extension::getAlterDefinition(BaseObject *object) { Extension *ext=dynamic_cast(object); if(!ext) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); attributes[Attributes::NewVersion]=QString(); if(!this->versions[CurVersion].isEmpty() && !ext->versions[CurVersion].isEmpty() && this->versions[CurVersion].isEmpty() < ext->versions[CurVersion].isEmpty()) attributes[Attributes::NewVersion]=ext->versions[CurVersion]; return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString Extension::getDropDefinition(bool cascade) { attributes[Attributes::Name] = this->getName(true); return(BaseObject::getDropDefinition(cascade)); } QString Extension::getSignature(bool format) { return(this->getName(format, false)); } QString Extension::getName(bool format, bool) { return(BaseObject::getName(format, false)); } void Extension::operator = (Extension &ext) { QString prev_name=this->getName(true); *(dynamic_cast(this))=dynamic_cast(ext); this->versions[CurVersion]=ext.versions[CurVersion]; this->versions[OldVersion]=ext.versions[OldVersion]; this->handles_type=ext.handles_type; if(this->handles_type) PgSqlType::renameUserType(prev_name, this, this->getName(true)); } pgmodeler-0.9.2/libpgmodeler/src/extension.h000066400000000000000000000047201360462764600211420ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Extension \brief Implements the operations to manipulate extensions on the database. **/ #ifndef EXTENSION_H #define EXTENSION_H #include "baseobject.h" class Extension: public BaseObject { private: /*! \brief Indicates if the extension handles a datatype. When this attribute is set pgModeler will consider the extension as a data type and will register it on PgSqlType class. */ bool handles_type; /*! \brief Versions of the installed extension. The first one is the current version and the last is the old version from which the extension is being updated */ QString versions[2]; public: static constexpr unsigned CurVersion=0, OldVersion=1; Extension(void); void setName(const QString &name); void setSchema(BaseObject *schema); /*! \brief Defines if the extension handles a datatype. When setting to true the extension will be registered as a datatype on DatabaseModel class. This method has no effect when the extension was already inserted on the model. */ void setHandlesType(bool value); //! \brief Set the versions of the extension void setVersion(unsigned ver, const QString &value); //! \brief Returns if the extension handles a datatype bool handlesType(void); //! \brief Returns on of the versions of the extension QString getVersion(unsigned ver); //! \brief Returns the SQL / XML code definition for the extension virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getAlterDefinition(BaseObject *object) final; virtual QString getDropDefinition(bool cascade) final; virtual QString getSignature(bool format = true) final; virtual QString getName(bool format = false, bool = false) final; void operator = (Extension &ext); }; #endif pgmodeler-0.9.2/libpgmodeler/src/foreigndatawrapper.cpp000066400000000000000000000115431360462764600233460ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "foreigndatawrapper.h" ForeignDataWrapper::ForeignDataWrapper(void) : BaseObject() { obj_type=ObjectType::ForeignDataWrapper; validator_func = handler_func = nullptr; attributes[Attributes::HandlerFunc] = QString(); attributes[Attributes::ValidatorFunc] = QString(); attributes[Attributes::Options] = QString(); } void ForeignDataWrapper::setHandlerFunction(Function *func) { if(func) { if(func->getReturnType() != PgSqlType("fdw_handler")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidReturnType) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgFunctionInvalidReturnType, __PRETTY_FUNCTION__, __FILE__, __LINE__); if(func->getParameterCount() != 0) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgFunctionInvalidParamCount, __PRETTY_FUNCTION__, __FILE__, __LINE__); } handler_func = func; } void ForeignDataWrapper::setValidatorFunction(Function *func) { if(func) { if(func->getParameterCount() != 2) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgFunctionInvalidParamCount, __PRETTY_FUNCTION__, __FILE__, __LINE__); if(!func->getParameter(0).getType().isExactTo(PgSqlType("text", 1)) || !func->getParameter(1).getType().isExactTo(PgSqlType("oid"))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParameters) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgFunctionInvalidParameters, __PRETTY_FUNCTION__, __FILE__, __LINE__); } validator_func = func; } Function *ForeignDataWrapper::getHandlerFunction(void) { return(handler_func); } Function *ForeignDataWrapper::getValidatorFunction(void) { return(validator_func); } QString ForeignDataWrapper::getCodeDefinition(unsigned def_type) { return(getCodeDefinition(def_type, false)); } QString ForeignDataWrapper::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); QStringList fmt_options; bool is_sql_def = (def_type == SchemaParser::SqlDefinition); if(handler_func) { handler_func->setAttribute(Attributes::RefType, Attributes::HandlerFunc); attributes[Attributes::HandlerFunc] = is_sql_def ? handler_func->getName(true) : handler_func->getCodeDefinition(def_type, true); } if(validator_func) { validator_func->setAttribute(Attributes::RefType, Attributes::ValidatorFunc); attributes[Attributes::ValidatorFunc] = is_sql_def ? validator_func->getName(true) : validator_func->getCodeDefinition(def_type, true); } attributes[Attributes::Options] = getOptionsAttribute(def_type); return(this->BaseObject::getCodeDefinition(def_type, reduced_form)); } QString ForeignDataWrapper::getAlterDefinition(BaseObject *object) { try { ForeignDataWrapper *fdw=dynamic_cast(object); attribs_map attribs; QStringList func_attribs = { Attributes::ValidatorFunc, Attributes::HandlerFunc }; Function *this_funcs[2] = { this->getValidatorFunction(), this->getHandlerFunction() }, *fdw_funcs[2] = { fdw->getValidatorFunction(), fdw->getHandlerFunction() }, *this_func = nullptr, *fdw_func = nullptr; attributes[Attributes::AlterCmds] = BaseObject::getAlterDefinition(fdw); getAlteredAttributes(fdw, attribs); // Comparing FDW functions for(int i = 0; i < 2; i++) { this_func = this_funcs[i]; fdw_func = fdw_funcs[i]; if(!fdw_func && this_func) attribs[func_attribs[i]] = Attributes::Unset; else if(fdw_func && (!this_func || (this_func && this_func->getSignature() != fdw_func->getSignature()))) attribs[func_attribs[i]] = fdw_func->getName(true); } copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/foreigndatawrapper.h000066400000000000000000000032531360462764600230120ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class ForeignDataWrapper \brief Implements the operations to manipulate foreign data wrappers on the database. */ #ifndef FOREIGN_DATA_WRAPPER_H #define FOREIGN_DATA_WRAPPER_H #include "baseobject.h" #include "function.h" #include "foreignobject.h" class ForeignDataWrapper: public BaseObject, public ForeignObject { private: //! \brief Function that executes the functions related to the foreign data wrapper Function *handler_func, //! \brief Function that validates the options passed to the foreign data wrapper *validator_func; public: ForeignDataWrapper(void); void setHandlerFunction(Function *func); void setValidatorFunction(Function *func); Function *getHandlerFunction(void); Function *getValidatorFunction(void); virtual QString getCodeDefinition(unsigned def_type); virtual QString getCodeDefinition(unsigned def_type, bool reduced_form); virtual QString getAlterDefinition(BaseObject *object); }; #endif pgmodeler-0.9.2/libpgmodeler/src/foreignobject.cpp000066400000000000000000000055261360462764600223060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "foreignobject.h" #include "exception.h" #include "attributes.h" const QString ForeignObject::OptionsSeparator = QString(","); const QString ForeignObject::OptionValueSeparator = QString("="); ForeignObject::ForeignObject(void) { } void ForeignObject::setOption(const QString &opt, const QString &value) { if(opt.isEmpty()) throw Exception(ErrorCode::AsgOptionInvalidName,__PRETTY_FUNCTION__,__FILE__,__LINE__); options[opt] = value; } void ForeignObject::setOptions(const attribs_map &options) { for(auto &itr : options) { if(itr.first.isEmpty()) throw Exception(ErrorCode::AsgOptionInvalidName,__PRETTY_FUNCTION__,__FILE__,__LINE__); } this->options = options; } void ForeignObject::removeOption(const QString &opt) { options.erase(opt); } void ForeignObject::removeOptions(void) { options.clear(); } attribs_map ForeignObject::getOptions(void) { return(options); } void ForeignObject::getAlteredAttributes(ForeignObject *object, attribs_map &fo_attribs) { attribs_map attribs; ForeignObject *fobj = dynamic_cast(object); QStringList opts; if(!fobj) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); // Comparing options (to be modified or added) for(auto &opt : fobj->options) { if(this->options.count(opt.first) == 0) opts.push_back(QString("ADD %1 '%2'").arg(opt.first).arg(opt.second)); else if(this->options[opt.first] != opt.second) opts.push_back(QString("SET %1 '%3'").arg(opt.first).arg(opt.second)); } // Comparing options (to be removed) for(auto &opt : this->options) { if(fobj->options.count(opt.first) == 0) opts.push_back(QString("DROP %1").arg(opt.first)); } if(!opts.isEmpty()) fo_attribs[Attributes::Options] = opts.join(OptionsSeparator); } QString ForeignObject::getOptionsAttribute(unsigned def_type) { QStringList fmt_options; for(auto &itr : options) fmt_options += def_type == SchemaParser::SqlDefinition ? QString("%1 '%2'").arg(itr.first).arg(itr.second) : QString("%1%2%3").arg(itr.first).arg(OptionValueSeparator).arg(itr.second); return(fmt_options.join(OptionsSeparator)); } pgmodeler-0.9.2/libpgmodeler/src/foreignobject.h000066400000000000000000000032301360462764600217410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class ForeignObject \brief Implements the basic operations to handle common attributes of foreign data wrapper, foreign servers and foreign tables. */ #ifndef FOREIGN_OBJECT_H #define FOREIGN_OBJECT_H #include "attribsmap.h" #include "schemaparser.h" class ForeignObject { protected: //! \brief A set of key/value options associated to the foreign object attribs_map options; QString getOptionsAttribute(unsigned def_type); public: //! \brief Store the character used to separate options/values in the XML code static const QString OptionsSeparator; static const QString OptionValueSeparator; ForeignObject(void); void setOption(const QString &opt, const QString &value); void setOptions(const attribs_map &options); void removeOption(const QString &opt); void removeOptions(void); attribs_map getOptions(void); void getAlteredAttributes(ForeignObject *object, attribs_map &fo_attribs); }; #endif pgmodeler-0.9.2/libpgmodeler/src/foreignserver.cpp000066400000000000000000000055511360462764600223440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "foreignserver.h" ForeignServer::ForeignServer(void) : BaseObject() { obj_type = ObjectType::ForeignServer; fdata_wrapper = nullptr; attributes[Attributes::Options] = QString(); attributes[Attributes::Version] = QString(); attributes[Attributes::Type] = QString(); attributes[Attributes::Object] = QString(); } void ForeignServer::setType(const QString &type) { this->type = type; } void ForeignServer::setVersion(const QString &version) { this->version = version; } void ForeignServer::setForeignDataWrapper(ForeignDataWrapper *fdw) { fdata_wrapper = fdw; } QString ForeignServer::getType(void) { return(type); } QString ForeignServer::getVersion(void) { return(version); } ForeignDataWrapper *ForeignServer::getForeignDataWrapper(void) { return(fdata_wrapper); } QString ForeignServer::getCodeDefinition(unsigned def_type) { return(getCodeDefinition(def_type, false)); } QString ForeignServer::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Version] = version; attributes[Attributes::Type] = type; attributes[Attributes::Fdw] = QString(); if(fdata_wrapper) { if(def_type == SchemaParser::SqlDefinition) attributes[Attributes::Fdw] = fdata_wrapper->getName(true); else attributes[Attributes::Fdw] = fdata_wrapper->getCodeDefinition(def_type, true); } attributes[Attributes::Options] = getOptionsAttribute(def_type); return(this->BaseObject::getCodeDefinition(def_type, reduced_form)); } QString ForeignServer::getAlterDefinition(BaseObject *object) { try { ForeignServer *server=dynamic_cast(object); attribs_map attribs; attributes[Attributes::AlterCmds] = BaseObject::getAlterDefinition(server); getAlteredAttributes(server, attribs); if(this->version != server->version) attribs[Attributes::Version] = server->version; copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/foreignserver.h000066400000000000000000000031411360462764600220020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Server \brief Implements the operations to manipulate foreign servers on the database. */ #ifndef FOREIGN_SERVER_H #define FOREIGN_SERVER_H #include "baseobject.h" #include "foreigndatawrapper.h" class ForeignServer: public BaseObject, public ForeignObject { private: //! \brief The foreign data wrapper which manages the server ForeignDataWrapper *fdata_wrapper; QString type, version; public: ForeignServer(void); void setType(const QString &type); void setVersion(const QString &version); void setForeignDataWrapper(ForeignDataWrapper *fdw); QString getType(void); QString getVersion(void); ForeignDataWrapper *getForeignDataWrapper(void); virtual QString getCodeDefinition(unsigned def_type); virtual QString getCodeDefinition(unsigned def_type, bool reduced_form); virtual QString getAlterDefinition(BaseObject *object); }; #endif pgmodeler-0.9.2/libpgmodeler/src/foreigntable.cpp000066400000000000000000000067441360462764600221320ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "foreigntable.h" ForeignTable::ForeignTable(void) : PhysicalTable() { obj_type = ObjectType::ForeignTable; attributes[Attributes::Server] = QString(); attributes[Attributes::Options] = QString(); foreign_server = nullptr; setName(trUtf8("new_foreign_table")); } ForeignTable::~ForeignTable(void) { destroyObjects(); } void ForeignTable::setForeignServer(ForeignServer *server) { setCodeInvalidated(foreign_server != server); foreign_server = server; } ForeignServer *ForeignTable::getForeignServer(void) { return(foreign_server); } void ForeignTable::addObject(BaseObject *object, int obj_idx) { if(object) { ObjectType obj_type = object->getObjectType(); // If the child object is of an invalid type we need to reject that object if(obj_type == ObjectType::Index || obj_type == ObjectType::Rule || obj_type == ObjectType::Policy || (obj_type == ObjectType::Constraint && dynamic_cast(object)->getConstraintType() != ConstraintType::Check)) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidObjectForeignTable) .arg(object->getName(true)) .arg(object->getTypeName()) .arg(this->getName(true)), ErrorCode::AsgInvalidObjectForeignTable,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } PhysicalTable::addObject(object, obj_idx); } void ForeignTable::setPartitioningType(PartitioningType) { PhysicalTable::setPartitioningType(PartitioningType::Null); } QString ForeignTable::__getCodeDefinition(unsigned def_type, bool incl_rel_added_objs) { setTableAttributes(def_type, incl_rel_added_objs); if(foreign_server) { attributes[Attributes::Server] = (def_type == SchemaParser::SqlDefinition ? foreign_server->getSignature() : foreign_server->getCodeDefinition(SchemaParser::XmlDefinition, true)); } attributes[Attributes::Options] = getOptionsAttribute(def_type); return(PhysicalTable::__getCodeDefinition(def_type)); } QString ForeignTable::getCodeDefinition(unsigned def_type) { QString code_def = PhysicalTable::getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); return(__getCodeDefinition(def_type, false)); } void ForeignTable::operator = (ForeignTable &tab) { (*dynamic_cast(this))=dynamic_cast(tab); } QString ForeignTable::getAlterDefinition(BaseObject *object) { try { attribs_map attribs; attributes[Attributes::AlterCmds] = BaseObject::getAlterDefinition(object); getAlteredAttributes(dynamic_cast(object), attribs); copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/foreigntable.h000066400000000000000000000053111360462764600215640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate foreign tables on the database. */ #ifndef FOREIGN_TABLE_H #define FOREIGN_TABLE_H #include "physicaltable.h" #include "foreignobject.h" #include "foreignserver.h" class ForeignTable: public PhysicalTable, public ForeignObject { private: //! \brief The foreign server in which the foreign table resides ForeignServer *foreign_server; public: ForeignTable(void); ~ForeignTable(void); void setForeignServer(ForeignServer *server); ForeignServer *getForeignServer(void); /*! \brief Adds an child object to the foreign table. * This will raise an error if the user try to add constraints other than CHECK, * indexes, rules and policies. This because foreign tables only accepts columns, check constraints, triggers */ void addObject(BaseObject *object, int obj_idx = -1); /*! \brief This method ignores any partitioning type provided for the foreign table. * It always set partitioning type as null since foreign tables doesn't support partitioning */ void setPartitioningType(PartitioningType); //! \brief Returns the SQL / XML definition for table virtual QString getCodeDefinition(unsigned def_type) final; //! \brief Copy the attributes between two tables void operator = (ForeignTable &table); //! \brief Returns the alter definition comparing the this table against the one provided via parameter virtual QString getAlterDefinition(BaseObject *object) final; /*! \brief Generates the table's SQL code considering adding the relationship added object or not. * Note if the method is called with incl_rel_added_objs = true it can produce an SQL/XML code * that does not reflect the real semantics of the table. So take care to use this method and always * invalidate the tables code (see setCodeInvalidated()) after retrieving the resulting code */ QString __getCodeDefinition(unsigned def_type, bool incl_rel_added_objs); friend class Relationship; friend class OperationList; }; #endif pgmodeler-0.9.2/libpgmodeler/src/function.cpp000066400000000000000000000360231360462764600213070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "function.h" Function::Function(void) { return_type=PgSqlType(QString("void")); language=nullptr; returns_setof=false; is_wnd_function=false; is_leakproof=false; obj_type=ObjectType::Function; execution_cost=100; row_amount=1000; attributes[Attributes::Parameters]=QString(); attributes[Attributes::ExecutionCost]=QString(); attributes[Attributes::RowAmount]=QString(); attributes[Attributes::ReturnType]=QString(); attributes[Attributes::FunctionType]=QString(); attributes[Attributes::Language]=QString(); attributes[Attributes::ReturnsSetOf]=QString(); attributes[Attributes::SecurityType]=QString(); attributes[Attributes::BehaviorType]=QString(); attributes[Attributes::Definition]=QString(); attributes[Attributes::Signature]=QString(); attributes[Attributes::RefType]=QString(); attributes[Attributes::WindowFunc]=QString(); attributes[Attributes::ReturnTable]=QString(); attributes[Attributes::Library]=QString(); attributes[Attributes::Symbol]=QString(); attributes[Attributes::LeakProof]=QString(); } void Function::setName(const QString &name) { BaseObject::setName(name); createSignature(); } void Function::setSchema(BaseObject *schema) { BaseObject::setSchema(schema); createSignature(); } void Function::addParameter(Parameter param) { vector::iterator itr,itr_end; bool found=false; itr=parameters.begin(); itr_end=parameters.end(); //Checks the duplicity of parameter names while(itr!=itr_end && !found) { /* Compares the parameters name storing in the 'found' flag if already exists in the function */ found=(itr->getName()==param.getName()); itr++; } //If a duplicated parameter is found an error is raised if(found) throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedParameterFunction) .arg(param.getName()) .arg(this->signature), ErrorCode::AsgDuplicatedParameterFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Inserts the parameter in the function parameters.push_back(param); createSignature(); } void Function::addReturnedTableColumn(const QString &name, PgSqlType type) { //Raises an error if the column name is empty if(name.isEmpty()) throw Exception(ErrorCode::AsgEmptyNameTableReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__); vector::iterator itr,itr_end; bool found=false; itr=ret_table_columns.begin(); itr_end=ret_table_columns.end(); //Checks the duplicity of table column names while(itr!=itr_end && !found) { /* Compares the column name storing in the 'found' flag if already exists in the returned table */ found=(itr->getName()==name); itr++; } //Raises an error if the column is duplicated if(found) throw Exception(Exception::getErrorMessage(ErrorCode::InsDuplicatedTableReturnType) .arg(name) .arg(this->signature), ErrorCode::InsDuplicatedTableReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__); Parameter p; p.setName(name); p.setType(type); ret_table_columns.push_back(p); setCodeInvalidated(true); } void Function::setParametersAttribute(unsigned def_type) { QString str_param; unsigned i, count; count=parameters.size(); for(i=0; i < count; i++) { str_param+=parameters[i].getCodeDefinition(def_type); } if(def_type==SchemaParser::SqlDefinition) str_param.remove(str_param.size()-2,2); attributes[Attributes::Parameters]=str_param; } void Function::setTableReturnTypeAttribute(unsigned def_type) { QString str_type; unsigned i, count; count=ret_table_columns.size(); for(i=0; i < count; i++) { str_type+=ret_table_columns[i].getCodeDefinition(def_type); } if(def_type==SchemaParser::SqlDefinition) str_type.remove(str_type.size()-2,2); attributes[Attributes::ReturnTable]=str_type; } void Function::setExecutionCost(unsigned exec_cost) { setCodeInvalidated(execution_cost != exec_cost); execution_cost=exec_cost; } void Function::setRowAmount(unsigned row_amount) { setCodeInvalidated(this->row_amount != row_amount); this->row_amount=row_amount; } void Function::setLibrary(const QString &library) { if(language->getName().toLower()!=~LanguageType("c")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgRefLibraryFuncLanguageNotC) .arg(this->getSignature()), ErrorCode::AsgRefLibraryFuncLanguageNotC,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->library != library); this->library=library; } void Function::setSymbol(const QString &symbol) { if(language->getName().toLower()!=~LanguageType("c")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgRefLibraryFuncLanguageNotC) .arg(this->getSignature()), ErrorCode::AsgRefLibraryFuncLanguageNotC,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->symbol != symbol); this->symbol=symbol; } void Function::setReturnType(PgSqlType type) { setCodeInvalidated(return_type != type); return_type=type; } void Function::setFunctionType(FunctionType func_type) { setCodeInvalidated(function_type != func_type); function_type=func_type; } void Function::setLanguage(BaseObject *language) { //Raises an error if the language is not allocated if(!language) throw Exception(ErrorCode::AsgNotAllocatedLanguage,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the language object is invalid else if(language->getObjectType()!=ObjectType::Language) throw Exception(ErrorCode::AsgInvalidLanguageObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->language != language); this->language=language; } void Function::setReturnSetOf(bool value) { setCodeInvalidated(returns_setof != value); returns_setof=value; } void Function::setWindowFunction(bool value) { setCodeInvalidated(is_wnd_function != value); is_wnd_function=value; } void Function::setLeakProof(bool value) { setCodeInvalidated(is_leakproof != value); is_leakproof=value; } void Function::setSecurityType(SecurityType sec_type) { setCodeInvalidated(security_type != sec_type); security_type=sec_type; } void Function::setBehaviorType(BehaviorType behav_type) { setCodeInvalidated(behavior_type != behav_type); behavior_type=behav_type; } void Function::setSourceCode(const QString &src_code) { if(language && language->getName().toLower()==~LanguageType("c")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgSourceCodeFuncCLanguage) .arg(this->getSignature()), ErrorCode::AsgSourceCodeFuncCLanguage,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->source_code != src_code); this->source_code=src_code; } PgSqlType Function::getReturnType(void) { return(return_type); } FunctionType Function::getFunctionType(void) { return(function_type); } BaseObject *Function::getLanguage(void) { return(language); } unsigned Function::getParameterCount(void) { return(parameters.size()); } unsigned Function::getReturnedTableColumnCount(void) { return(ret_table_columns.size()); } bool Function::isReturnSetOf(void) { return(returns_setof); } bool Function::isReturnTable(void) { return(ret_table_columns.size() > 0); } bool Function::isWindowFunction(void) { return(is_wnd_function); } bool Function::isLeakProof(void) { return(is_leakproof); } SecurityType Function::getSecurityType(void) { return(security_type); } BehaviorType Function::getBehaviorType(void) { return(behavior_type); } QString Function::getSourceCode(void) { return(source_code); } Parameter Function::getParameter(unsigned param_idx) { //Raises an error if the parameter index is out of bound if(param_idx>=parameters.size()) throw Exception(ErrorCode::RefParameterInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(parameters[param_idx]); } Parameter Function::getReturnedTableColumn(unsigned column_idx) { //Raises an error if the column index is out of bound if(column_idx>=ret_table_columns.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(ret_table_columns[column_idx]); } unsigned Function::getExecutionCost(void) { return(execution_cost); } unsigned Function::getRowAmount(void) { return(row_amount); } QString Function::getLibrary(void) { return(library); } QString Function::getSymbol(void) { return(symbol); } void Function::removeParameters(void) { parameters.clear(); createSignature(); } void Function::removeReturnedTableColumns(void) { ret_table_columns.clear(); setCodeInvalidated(true); } void Function::removeParameter(const QString &name, PgSqlType type) { vector::iterator itr,itr_end; itr=parameters.begin(); itr_end=parameters.end(); while(itr!=itr_end) { //Compares the iterator name and type with the passed name an type if(itr->getName()==name && itr->getType()==(~type)) { parameters.erase(itr); break; } itr++; } //After remove the parameter is necessary updated the signature createSignature(); } void Function::removeParameter(unsigned param_idx) { //Raises an error if parameter index is out of bound if(param_idx>=parameters.size()) throw Exception(ErrorCode::RefParameterInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); vector::iterator itr; itr=parameters.begin()+param_idx; parameters.erase(itr); createSignature(); } void Function::removeReturnedTableColumn(unsigned column_idx) { if(column_idx>=ret_table_columns.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); vector::iterator itr; itr=ret_table_columns.begin()+column_idx; ret_table_columns.erase(itr); setCodeInvalidated(true); } QString Function::getSignature(bool) { return(signature); } void Function::createSignature(bool format, bool prepend_schema) { QString str_params, aux_str; unsigned i, count; count=parameters.size(); for(i=0; i < count; i++) { //OUT parameters is not part of function's signature if(!parameters[i].isOut() || parameters[i].isVariadic() || (parameters[i].isIn() && parameters[i].isOut()) || (parameters[i].isIn() && !parameters[i].isOut())) { /* Removing the arg mode IN from parameter signature because this is de default for any kind of parameter * So in order to avoid signature conflicts (mainly whe diff functions) we remove it */ aux_str=parameters[i].getCodeDefinition(SchemaParser::SqlDefinition, true).replace(QRegExp("^(IN)( )"),""); str_params+=aux_str.trimmed(); parameters[i].setCodeInvalidated(true); } } str_params.remove(str_params.length()-1, 1); //Signature format NAME(IN|OUT PARAM1_TYPE,IN|OUT PARAM2_TYPE,...,IN|OUT PARAMn_TYPE) signature=this->getName(format, prepend_schema) + QString("(") + str_params + QString(")"); this->setCodeInvalidated(true); } QString Function::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString Function::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); setParametersAttribute(def_type); attributes[Attributes::ExecutionCost]=QString("%1").arg(execution_cost); attributes[Attributes::RowAmount]=QString("%1").arg(row_amount); attributes[Attributes::FunctionType]=(~function_type); if(language) { if(def_type==SchemaParser::SqlDefinition) { attributes[Attributes::Language]=language->getName(false); attributes[Attributes::ReturnType]=(*return_type); } else { attributes[Attributes::Language]=language->getCodeDefinition(def_type,true); attributes[Attributes::ReturnType]=return_type.getCodeDefinition(def_type); } if(language->getName()==~LanguageType(LanguageType::C)) { attributes[Attributes::Symbol]=symbol; attributes[Attributes::Library]=library; } } setTableReturnTypeAttribute(def_type); attributes[Attributes::ReturnsSetOf]=(returns_setof ? Attributes::True : QString()); attributes[Attributes::WindowFunc]=(is_wnd_function ? Attributes::True : QString()); attributes[Attributes::LeakProof]=(is_leakproof ? Attributes::True : QString()); attributes[Attributes::SecurityType]=(~security_type); attributes[Attributes::BehaviorType]=(~behavior_type); attributes[Attributes::Definition]=source_code; attributes[Attributes::Signature]=signature; return(BaseObject::getCodeDefinition(def_type, reduced_form)); } QString Function::getAlterDefinition(BaseObject *object) { Function *func=dynamic_cast(object); if(!func) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { attribs_map attribs; attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); if(this->source_code.simplified() != func->source_code.simplified() || this->library!=func->library || this->symbol!=func->symbol) { attribs[Attributes::Definition]=func->getCodeDefinition(SchemaParser::SqlDefinition); attribs[Attributes::Definition].replace(QString("CREATE FUNCTION"), QString("CREATE OR REPLACE FUNCTION")); } else { if(this->execution_cost!=func->execution_cost) attribs[Attributes::ExecutionCost]=QString::number(func->execution_cost); if(this->returns_setof && func->returns_setof && this->row_amount!=func->row_amount) { attribs[Attributes::ReturnsSetOf]=Attributes::True; attribs[Attributes::RowAmount]=QString::number(row_amount); } if(this->function_type!=func->function_type) attribs[Attributes::FunctionType]=~func->function_type; if(this->is_leakproof!=func->is_leakproof) attribs[Attributes::LeakProof]=(func->is_leakproof ? Attributes::True : Attributes::Unset); if(this->security_type!=func->security_type) attribs[Attributes::SecurityType]=~func->security_type; if((this->behavior_type!=func->behavior_type) && ((this->behavior_type==BehaviorType::CalledOnNullInput) || ((this->behavior_type==BehaviorType::Strict || this->behavior_type==BehaviorType::ReturnsNullOnNullInput) && func->function_type==BehaviorType::CalledOnNullInput))) attribs[Attributes::BehaviorType]=~func->behavior_type; } copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Function::configureSearchAttributes(void) { QStringList param_types; BaseObject::configureSearchAttributes(); search_attribs[Attributes::ReturnType] = ret_table_columns.empty() ? *return_type : QString(); for(auto ¶m : parameters) param_types += *param.getType(); search_attribs[Attributes::Type] = param_types.join("; "); } pgmodeler-0.9.2/libpgmodeler/src/function.h000066400000000000000000000167541360462764600207650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate stored procedures (function) on the database. \note Creation date: 28/09/2006 */ #ifndef FUNCTION_H #define FUNCTION_H #include "schema.h" #include "role.h" #include "parameter.h" class Function: public BaseObject { private: //! \brief Function unique signature QString signature; //! \brief Shared library (commonly developed in C language) that stores the function routine QString library; //! \brief Symbol that identify the function on the shared library QString symbol; //! \brief Function source code (except for C language defined functions) QString source_code; //! \brief Language that is used to construct the language BaseObject *language; //! \brief Function parameters vector parameters; //! \brief Indicates whether the function returns a set of data (RETURNS SET OF) bool returns_setof, //! \brief Indicate whether the object is a windows function or not is_wnd_function, //! \brief Indicate whether the object is leak proof or not is_leakproof; //! \brief Type of execution behavior applied to the function BehaviorType behavior_type; //! \brief Function type. It can be VOLATILE, IMMUTABLE, STABLE FunctionType function_type; //! \brief Function return type PgSqlType return_type; /*! \brief Stores the table columns returned by the clause RETURNS TABLE. This clause instead of return a specific element returns a whole table. This structure is available only on PostgreSQL 8.4 and later */ vector ret_table_columns; //! \brief Function security type. It can be SECURITY [INVOKER | DEFINER] SecurityType security_type; //! \brief Execution cost for the function unsigned execution_cost; //! \brief Estimated returned row (tuple) amount unsigned row_amount; //! \brief Formats the function parameter attribute to be used by the SchemaParser void setParametersAttribute(unsigned def_type); //! \brief Formats the function return type to be used by the SchemaParser void setTableReturnTypeAttribute(unsigned def_type); protected: virtual void configureSearchAttributes(void); public: Function(void); //! \brief Sets the function name updating its signature void setName(const QString &name); //! \brief Sets the function schema updating its signature void setSchema(BaseObject *schema); //! \brief Adds a parameter to the function void addParameter(Parameter param); //! \brief Adds a column to the function returned table void addReturnedTableColumn(const QString &name, PgSqlType type); //! \brief Defines the function source code (if its not use the C language) void setSourceCode(const QString &src_code); //! \brief Defines the shared library that stores the function routine void setLibrary(const QString &library); //! \brief Defines the symbol that identifies the function on shared library void setSymbol(const QString &symbol); //! \brief Defines the language used to construct the function void setLanguage(BaseObject *language); //! \brief Defines the execution cost for the function void setExecutionCost(unsigned exec_cost); //! \brief Defines the estimated amount of rows (tuples) returned by the function void setRowAmount(unsigned row_amount); //! \brief Defines whether returns a set of values or not void setReturnSetOf(bool value); //! \brief Defines whether the function is a windows function or not void setWindowFunction(bool value); //! \brief Defines whether the function is leak proof or not void setLeakProof(bool value); //! \brief Defines the function's execution behavior void setBehaviorType(BehaviorType behav_type); //! \brief Defines the function type (VOLATILE, IMMUTABLE, STABLE) void setFunctionType(FunctionType func_type); //! \brief Defines the function return type void setReturnType(PgSqlType type); //! \brief Defines the security type of the function void setSecurityType(SecurityType sec_type); //! \brief Returns the function's source code QString getSourceCode(void); //! \brief Returns the shared library that stores the function definition QString getLibrary(void); //! \brief Returns the symbol that identifies the function on the shared library QString getSymbol(void); //! \brief Returns the language used to construct the function BaseObject *getLanguage(void); //! \brief Returns the function parameter count unsigned getParameterCount(void); //! \brief Returns the returned table column count unsigned getReturnedTableColumnCount(void); //! \brief Returns a parameter using its index Parameter getParameter(unsigned param_idx); //! \brief Returns a column from returned table using its index Parameter getReturnedTableColumn(unsigned column_idx); //! \brief Indicates whether the function returns setof or not bool isReturnSetOf(void); //! \brief Indicates whether the fucntion returns a table or not bool isReturnTable(void); //! \brief Indicates whether the function is window or not bool isWindowFunction(void); //! \brief Indicates whether the function is leak proof or not bool isLeakProof(void); //! \brief Returns the function execution behavior BehaviorType getBehaviorType(void); //! \brief Returns the function type FunctionType getFunctionType(void); //! \brief Returns the function returned type PgSqlType getReturnType(void); //! \brief Returns the security type used by the function SecurityType getSecurityType(void); //! \brief Returns the function's execution cost unsigned getExecutionCost(void); //! \brief Returns the estimated returned row amount unsigned getRowAmount(void); //! \brief Removes a parameter using its name and type void removeParameter(const QString &name, PgSqlType type); //! \brief Removes a parameter using its index void removeParameter(unsigned param_idx); //! \brief Removes all the parameters from the function void removeParameters(void); //! \brief Removes a column from returned table using its index void removeReturnedTableColumn(unsigned column_idx); //! \brief Removes all the columns from returned table column void removeReturnedTableColumns(void); //! \brief Returns the complete function signature virtual QString getSignature(bool=true); /*! \brief Generates the function's signature. The 'format' parameter is used to adequately format the function and parameters names. By default this formating is always done. */ void createSignature(bool format=true, bool prepend_schema=true); //! \brief Returns the SQL / XML code definition for the function virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getAlterDefinition(BaseObject *object) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/genericsql.cpp000066400000000000000000000155651360462764600216260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "genericsql.h" #include "tableobject.h" GenericSQL::GenericSQL(void) { obj_type = ObjectType::GenericSql; attributes[Attributes::Definition] = QString(); attributes[Attributes::Objects] = QString(); } void GenericSQL::setDefinition(const QString &def) { setCodeInvalidated(definition != def); definition = def; } QString GenericSQL::getDefinition(void) { return(definition); } vector GenericSQL::getObjectsReferences(void) { return(objects_refs); } int GenericSQL::getObjectRefNameIndex(const QString &ref_name) { int idx = -1; vector::iterator itr = objects_refs.begin(), itr_end = objects_refs.end(); if(ref_name.isEmpty()) return(-1); while(itr != itr_end) { if((*itr).ref_name == ref_name) { idx = itr - objects_refs.begin(); break; } itr++; } return(idx); } bool GenericSQL::isObjectReferenced(BaseObject *object) { bool found = false; BaseObject *ref_obj = nullptr; vector::iterator itr = objects_refs.begin(), itr_end = objects_refs.end(); if(!object) return(false); while(itr != itr_end && !found) { ref_obj = (*itr).object; found = (ref_obj == object); if(!found && TableObject::isTableObject(ref_obj->getObjectType())) found = (dynamic_cast(ref_obj)->getParentTable() == object); itr++; } return(found); } bool GenericSQL::isReferRelationshipAddedObject(void) { bool found = false; vector::iterator itr = objects_refs.begin(), itr_end = objects_refs.end(); TableObject *tab_obj = nullptr; while(itr != itr_end && !found) { tab_obj = dynamic_cast(itr->object); found = (tab_obj && tab_obj->isAddedByRelationship()); itr++; } return(found); } vector GenericSQL::getReferencedObjects(void) { vector ref_objs; for(auto &ref : objects_refs) ref_objs.push_back(ref.object); return(ref_objs); } void GenericSQL::validateObjectReference(ObjectRefConfig ref, bool ignore_duplic) { if(!ref.object) throw Exception(ErrorCode::AsgNotAllocatedObjectReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!BaseObject::isValidName(ref.ref_name)) throw Exception(ErrorCode::AsgInvalidNameObjReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!ignore_duplic && getObjectRefNameIndex(ref.ref_name) >= 0) throw Exception(Exception::getErrorMessage(ErrorCode::InsDuplicatedObjectReference).arg(ref.ref_name), ErrorCode::InsDuplicatedObjectReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); } void GenericSQL::addObjectReference(BaseObject *object, const QString &ref_name, bool use_signature, bool format_name) { try { ObjectRefConfig ref = ObjectRefConfig(ref_name, object, use_signature, format_name); validateObjectReference(ref, false); objects_refs.push_back(ref); setCodeInvalidated(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void GenericSQL::updateObjectReference(const QString &ref_name, BaseObject *object, const QString &new_ref_name, bool use_signature, bool format_name) { int idx = getObjectRefNameIndex(ref_name); if(idx < 0) return; try { ObjectRefConfig ref = ObjectRefConfig(new_ref_name, object, use_signature, format_name); vector::iterator itr = objects_refs.begin() + idx; int idx_aux = getObjectRefNameIndex(new_ref_name); if(idx_aux != idx) throw Exception(Exception::getErrorMessage(ErrorCode::InsDuplicatedObjectReference).arg(new_ref_name), ErrorCode::InsDuplicatedObjectReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); validateObjectReference(ref, true); (*itr) = ref; setCodeInvalidated(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void GenericSQL::removeObjectReference(const QString &ref_name) { int idx = getObjectRefNameIndex(ref_name); if(idx >= 0) objects_refs.erase(objects_refs.begin() + idx); setCodeInvalidated(true); } void GenericSQL::removeObjectReferences(void) { objects_refs.clear(); setCodeInvalidated(true); } QString GenericSQL::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); QString fmt_definition = definition, name_attr = QString("%1%2%3").arg(SchemaParser::CharIniAttribute) .arg(Attributes::Name) .arg(SchemaParser::CharEndAttribute); if(!objects_refs.empty()) { QString ref_name, ref_value; attribs_map obj_attrs; for(auto &ref : objects_refs) { if(def_type == SchemaParser::XmlDefinition) { obj_attrs[Attributes::Name] = ref.object->getSignature(); obj_attrs[Attributes::Type] = ref.object->getSchemaName(); obj_attrs[Attributes::RefName] = ref.ref_name; obj_attrs[Attributes::FormatName] = ref.format_name ? Attributes::True : QString(); obj_attrs[Attributes::UseSignature] = ref.use_signature ? Attributes::True : QString(); schparser.ignoreUnkownAttributes(true); attributes[Attributes::Objects] += schparser.getCodeDefinition(Attributes::Object, obj_attrs, SchemaParser::XmlDefinition); } else { /* In order to use a reference name in the object's SQL code, the reference should be writter in the for * {ref_name} so it can be replaced by the corresponding value in the SQL code */ ref_name = QString("%1%2%3").arg(SchemaParser::CharIniAttribute) .arg(ref.ref_name) .arg(SchemaParser::CharEndAttribute); // Configuring the value of the reference ref_value = ref.use_signature ? ref.object->getSignature(ref.format_name) : ref.object->getName(ref.format_name); fmt_definition = fmt_definition.replace(ref_name, ref_value); } } } // Special case for the {name} attribute which is created automatically when there's no one defined by the user if(def_type == SchemaParser::SqlDefinition && fmt_definition.contains(name_attr) && getObjectRefNameIndex(Attributes::Name) < 0) fmt_definition = fmt_definition.replace(name_attr, this->getName(true)); attributes[Attributes::Definition] = fmt_definition; return(this->BaseObject::__getCodeDefinition(def_type)); } pgmodeler-0.9.2/libpgmodeler/src/genericsql.h000066400000000000000000000074221360462764600212640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class GenericSQL \brief This class is used to represent generic sql commands as database objects */ #ifndef GENERIC_SQL_H #define GENERIC_SQL_H #include "baseobject.h" #include class GenericSQL: public BaseObject{ protected: //! \brief This is a internal structure used to hold object references configuration struct ObjectRefConfig { QString ref_name; // Name of the reference (in SQL it be used between {} in order to be parsed) BaseObject *object; // The object being referenced bool use_signature, // Indicates that the signature of the object should be used instead of the name format_name; // Indicates that the name of the object need to be automatically quoted or the schema name appended ObjectRefConfig(const QString &_ref_name, BaseObject *_object, bool _use_signature, bool _format_name) : ref_name(_ref_name), object(_object), use_signature(_use_signature), format_name(_format_name) {} }; //! \brief Returns a copy of the objects references list vector getObjectsReferences(void); private: //! \brief The SQL definition of the generic object QString definition; //! \brief The list of references to other object in the model vector objects_refs; /*! \brief Returns the index of a object reference searching by its name. * A negative return value indicates the reference doens't exist */ int getObjectRefNameIndex(const QString &ref_name); /*! \brief Check if the provided object reference is correclty configured. * The method will raise exceptions if any validation rule is broken. * The parameter ignore_duplic makes the method ignore duplicated references names */ void validateObjectReference(ObjectRefConfig ref, bool ignore_duplic); public: GenericSQL(void); void setDefinition(const QString &def); QString getDefinition(void); void addObjectReference(BaseObject *object, const QString &ref_name, bool use_signature, bool format_name); void updateObjectReference(const QString &ref_name, BaseObject *object, const QString &new_ref_name, bool use_signature, bool format_name); void removeObjectReference(const QString &ref_name); void removeObjectReferences(void); //! \brief Returns true when the provided object is being referenced by the generic SQL object bool isObjectReferenced(BaseObject *object); /*! \brief Returns whether the object references columns or constraints added * by relationship to their parent tables. This method is used as auxiliary * to control which generic SQL object references objects added by the * relationship in order to avoid referece breaking due constants * connections and disconnections of relationships */ bool isReferRelationshipAddedObject(void); /*! \brief Returns a list of objectes being referenced by the generic object. * For performance reasons this method doesn't eliminate duplicated values in * the retunring list*/ vector getReferencedObjects(void); virtual QString getCodeDefinition(unsigned def_type); friend class GenericSQLWidget; }; #endif pgmodeler-0.9.2/libpgmodeler/src/index.cpp000066400000000000000000000267751360462764600206060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "index.h" Index::Index(void) { obj_type=ObjectType::Index; index_attribs[Unique]=index_attribs[Concurrent]= index_attribs[FastUpdate]=index_attribs[Buffering]=false; fill_factor=90; attributes[Attributes::Unique]=QString(); attributes[Attributes::Concurrent]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::IndexType]=QString(); attributes[Attributes::Columns]=QString(); attributes[Attributes::Expression]=QString(); attributes[Attributes::Factor]=QString(); attributes[Attributes::Predicate]=QString(); attributes[Attributes::OpClass]=QString(); attributes[Attributes::NullsFirst]=QString(); attributes[Attributes::AscOrder]=QString(); attributes[Attributes::DeclInTable]=QString(); attributes[Attributes::Elements]=QString(); attributes[Attributes::FastUpdate]=QString(); attributes[Attributes::Buffering]=QString(); attributes[Attributes::StorageParams]=QString(); } void Index::setIndexElementsAttribute(unsigned def_type) { QString str_elem; unsigned i, count; count=idx_elements.size(); for(i=0; i < count; i++) { str_elem+=idx_elements[i].getCodeDefinition(def_type); if(i < (count-1) && def_type==SchemaParser::SqlDefinition) str_elem+=','; } attributes[Attributes::Elements]=str_elem; } int Index::getElementIndex(IndexElement elem) { int idx=0; bool found=false; while(idx < static_cast(idx_elements.size()) && !found) { found=(idx_elements[idx]==elem); if(!found) idx++; } return(found ? idx : -1); } void Index::addIndexElement(IndexElement elem) { if(getElementIndex(elem) >= 0) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(elem.getExpression().isEmpty() && !elem.getColumn()) throw Exception(ErrorCode::AsgInvalidExpressionObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); idx_elements.push_back(elem); setCodeInvalidated(true); validateElements(); } void Index::addIndexElement(const QString &expr, Collation *coll, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first) { try { IndexElement elem; //Raises an error if the expression is empty if(expr.isEmpty()) throw Exception(ErrorCode::AsgInvalidExpressionObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Configures the element elem.setExpression(expr); elem.setOperatorClass(op_class); elem.setCollation(coll); elem.setSortingEnabled(use_sorting); elem.setSortingAttribute(IndexElement::NullsFirst, nulls_first); elem.setSortingAttribute(IndexElement::AscOrder, asc_order); if(getElementIndex(elem) >= 0) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); idx_elements.push_back(elem); setCodeInvalidated(true); validateElements(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Index::addIndexElement(Column *column, Collation *coll, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first) { try { IndexElement elem; //Case the column is not allocated raises an error if(!column) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedColumn) .arg(this->getName()) .arg(this->getTypeName()), ErrorCode::AsgNotAllocatedColumn, __PRETTY_FUNCTION__,__FILE__,__LINE__); //Configures the element elem.setColumn(column); elem.setOperatorClass(op_class); elem.setCollation(coll); elem.setSortingEnabled(use_sorting); elem.setSortingAttribute(IndexElement::NullsFirst, nulls_first); elem.setSortingAttribute(IndexElement::AscOrder, asc_order); if(getElementIndex(elem) >= 0) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); idx_elements.push_back(elem); setCodeInvalidated(true); validateElements(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Index::addIndexElements(vector &elems) { vector elems_bkp=idx_elements; try { idx_elements.clear(); for(unsigned i=0; i < elems.size(); i++) addIndexElement(elems[i]); } catch(Exception &e) { idx_elements = elems_bkp; throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Index::removeIndexElement(unsigned idx_elem) { if(idx_elem >= idx_elements.size()) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); idx_elements.erase(idx_elements.begin() + idx_elem); setCodeInvalidated(true); } void Index::removeIndexElements(void) { idx_elements.clear(); setCodeInvalidated(true); } IndexElement Index::getIndexElement(unsigned elem_idx) { if(elem_idx >= idx_elements.size()) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(idx_elements[elem_idx]); } vector Index::getIndexElements(void) { return(idx_elements); } unsigned Index::getIndexElementCount(void) { return(idx_elements.size()); } void Index::setIndexAttribute(unsigned attrib_id, bool value) { if(attrib_id > Buffering) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(index_attribs[attrib_id] != value); index_attribs[attrib_id]=value; } void Index::setFillFactor(unsigned factor) { setCodeInvalidated(fill_factor != factor); fill_factor=factor; } void Index::setIndexingType(IndexingType idx_type) { setCodeInvalidated(indexing_type != idx_type); this->indexing_type=idx_type; validateElements(); } void Index::setPredicate(const QString &expr) { setCodeInvalidated(predicate != expr); predicate=expr; } unsigned Index::getFillFactor(void) { return(fill_factor); } bool Index::getIndexAttribute(unsigned attrib_id) { if(attrib_id > Buffering) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(index_attribs[attrib_id]); } IndexingType Index::getIndexingType(void) { return(indexing_type); } QString Index::getPredicate(void) { return(predicate); } bool Index::isReferRelationshipAddedColumn(void) { vector::iterator itr, itr_end; Column *col=nullptr; bool found=false; itr=idx_elements.begin(); itr_end=idx_elements.end(); //Checks if some of the elements if referencing columns added by relationship while(itr!=itr_end && !found) { col=(*itr).getColumn(); found=(col && col->isAddedByRelationship()); itr++; } return(found); } vector Index::getRelationshipAddedColumns(void) { vector cols; Column *col=nullptr; for(auto &elem : idx_elements) { col=elem.getColumn(); if(col && col->isAddedByRelationship()) cols.push_back(col); } return(cols); } bool Index::isReferCollation(Collation *collation) { vector::iterator itr, itr_end; bool found=false; if(!collation) return(false); itr=idx_elements.begin(); itr_end=idx_elements.end(); //Checks if some of the elements is referencing the collation while(itr!=itr_end && !found) { found=((*itr).getCollation()==collation); itr++; } return(found); } bool Index::isReferColumn(Column *column) { vector::iterator itr, itr_end; bool found=false; if(!column) return(false); itr=idx_elements.begin(); itr_end=idx_elements.end(); while(itr!=itr_end && !found) { found=((*itr).getColumn()==column); itr++; } return(found); } QString Index::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); setIndexElementsAttribute(def_type); attributes[Attributes::Unique]=(index_attribs[Unique] ? Attributes::True : QString()); attributes[Attributes::Concurrent]=(index_attribs[Concurrent] ? Attributes::True : QString()); attributes[Attributes::IndexType]=(~indexing_type); attributes[Attributes::Predicate]=predicate; attributes[Attributes::StorageParams]=QString(); if(getParentTable()) { attributes[Attributes::Table]=getParentTable()->getName(true); if(def_type==SchemaParser::SqlDefinition && getParentTable()->getSchema()) attributes[Attributes::Schema]=getParentTable()->getSchema()->getName(true); } if(this->indexing_type==IndexingType::Gin) attributes[Attributes::StorageParams]=attributes[Attributes::FastUpdate]=(index_attribs[FastUpdate] ? Attributes::True : QString()); if(this->indexing_type==IndexingType::Gist) attributes[Attributes::StorageParams]=attributes[Attributes::Buffering]=(index_attribs[Buffering] ? Attributes::True : QString()); if(this->indexing_type!=IndexingType::Gin && fill_factor >= 10) { attributes[Attributes::Factor]=QString("%1").arg(fill_factor); attributes[Attributes::StorageParams]=Attributes::True; } else if(def_type==SchemaParser::XmlDefinition) attributes[Attributes::Factor]=QString("0"); /* Case the index doesn't referece some column added by relationship it will be declared inside the parent table construction by the use of 'decl-in-table' schema attribute */ if(!isReferRelationshipAddedColumn()) attributes[Attributes::DeclInTable]=Attributes::True; return(BaseObject::__getCodeDefinition(def_type)); } QString Index::getSignature(bool format) { if(!getParentTable() || !getParentTable()->getSchema()) return(BaseObject::getSignature(format)); return(QString("%1.%2").arg(getParentTable()->getSchema()->getName(format)).arg(this->getName(format))); } QString Index::getAlterDefinition(BaseObject *object) { Index *index=dynamic_cast(object); if(!index) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { attribs_map attribs; attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); if(this->indexing_type==index->indexing_type) { if(this->indexing_type != IndexingType::Gin && this->fill_factor!=index->fill_factor && index->fill_factor >= 10) attribs[Attributes::Factor]=QString::number(index->fill_factor); if(this->indexing_type==IndexingType::Gin && this->index_attribs[FastUpdate] != index->index_attribs[FastUpdate]) attribs[Attributes::FastUpdate]=(index->index_attribs[FastUpdate] ? Attributes::True : Attributes::Unset); if(this->indexing_type==IndexingType::Gist && this->index_attribs[Buffering] != index->index_attribs[Buffering]) attribs[Attributes::Buffering]=(index->index_attribs[Buffering] ? Attributes::True : Attributes::Unset); } copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Index::validateElements(void) { if(indexing_type!=IndexingType::Btree) { for(unsigned i=0; i < idx_elements.size(); i++) { if(idx_elements[i].isSortingEnabled()) { idx_elements[i].setSortingEnabled(false); setCodeInvalidated(true); } } } } pgmodeler-0.9.2/libpgmodeler/src/index.h000066400000000000000000000117611360462764600202400ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Index \brief Implements the operations to manipulate indexes on the database. \note Creation date: 23/09/2006 */ #ifndef INDEX_H #define INDEX_H #include "tableobject.h" #include "indexelement.h" class Index: public TableObject{ private: //! \brief Stores the elements that defines the index vector idx_elements; //! \brief Predicate expression for the index QString predicate; //! \brief Fill factor used by the index unsigned fill_factor; //! \brief Indexing method used by the index IndexingType indexing_type; //! \brief Boolean attributes that define some index features (UNIQUE, CONCURRENT, FAST UPDATE, BUFFERING) bool index_attribs[4]; //! \brief Formats the elements string used by the SchemaParser void setIndexElementsAttribute(unsigned def_type); /*! \brief Executes any validation over the index's elements. Currently, this method disable sorting when the indexing type is 'gin' */ void validateElements(void); public: static constexpr unsigned Unique=0, Concurrent=1, FastUpdate=2, Buffering=3; Index(void); //! \brief Adds an element to the index using an column void addIndexElement(Column *column, Collation *coll, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first); //! \brief Adds an element to the index using an expression void addIndexElement(const QString &expr, Collation *coll, OperatorClass *op_class, bool use_sorting, bool asc_order, bool nulls_first); //! \brief Adds an element to the index using other pre-configured element void addIndexElement(IndexElement elem); //! \brief Adds several elements to the index using a defined vector void addIndexElements(vector &elems); //! \brief Returns the specified element index int getElementIndex(IndexElement elem); //! \brief Returns one element using its index IndexElement getIndexElement(unsigned elem_idx); //! \brief Returns a list of the index elements vector getIndexElements(void); //! \brief Remove an element using its index void removeIndexElement(unsigned idx_elem); //! \brief Remove all elements from the index void removeIndexElements(void); //! \brief Defines the predicate used by the index void setPredicate(const QString &expr); //! \brief Defines the indexing method used by the index void setIndexingType(IndexingType idx_type); /*! \brief Configures the attributes for the indexs. These attributes can be referencede using the UNIQUE, CONCURRENT and FAST_UPDATE constants */ void setIndexAttribute(unsigned attrib_id, bool value); //! \brief Defines the index fill factor void setFillFactor(unsigned factor); //! \brief Gets the index conditional expression QString getPredicate(void); //! \brief Gets the index element count unsigned getIndexElementCount(void); //! \brief Returns the indexing method used by the index IndexingType getIndexingType(void); //! \brief Returns the current state of one index attribute (UNIQUE, CONCURRENT, FAST UPDATE) bool getIndexAttribute(unsigned attrib_id); //! \brief Returns the index fill factor unsigned getFillFactor(void); //! \brief Returns the SQL / XML definition for the index virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool format=true) final ; virtual QString getAlterDefinition(BaseObject *object) final; /*! \brief Returns whether the index references columns added by relationship. This method is used as auxiliary to control which index reference columns added by the relationship in order to avoid referece breaking due constants connections and disconnections of relationships */ bool isReferRelationshipAddedColumn(void); /*! \brief Returns the list of all columns that is created by relationships. This method is slower than isReferRelationshipAddedColumn() so it's not recommended to use it only check if the object is referencing columns added by relationship */ vector getRelationshipAddedColumns(void); //! \brief Returns if some index element is referencing the specified collation bool isReferCollation(Collation *collation); //! \brief Returns if some index element is referencing the specified column bool isReferColumn(Column *column); }; #endif pgmodeler-0.9.2/libpgmodeler/src/indexelement.cpp000066400000000000000000000027641360462764600221500ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "indexelement.h" IndexElement::IndexElement(void) : Element() { collation=nullptr; } void IndexElement::setCollation(Collation *collation) { this->collation=collation; } Collation *IndexElement::getCollation(void) { return(collation); } QString IndexElement::getCodeDefinition(unsigned def_type) { attribs_map attributes; schparser.setPgSQLVersion(BaseObject::getPgSQLVersion()); attributes[Attributes::Collation]=QString(); configureAttributes(attributes, def_type); if(collation) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Collation]=collation->getName(true); else attributes[Attributes::Collation]=collation->getCodeDefinition(def_type, true); } return(schparser.getCodeDefinition(Attributes::IndexElement,attributes, def_type)); } pgmodeler-0.9.2/libpgmodeler/src/indexelement.h000066400000000000000000000027201360462764600216050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate index elements. */ #ifndef INDEX_ELEMENT_H #define INDEX_ELEMENT_H #include "column.h" #include "operatorclass.h" #include "collation.h" #include "element.h" class IndexElement: public Element { private: //! \brief Collation referenced by the element Collation *collation; public: IndexElement(void); virtual ~IndexElement(void){} //! \brief Defines the collation referenced by the element void setCollation(Collation *collation); //! \brief Get the collation referenced by the element Collation *getCollation(void); //! \brief Returns the SQL / XML code definition for the index element virtual QString getCodeDefinition(unsigned def_type) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/language.cpp000066400000000000000000000116111360462764600212410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "language.h" Language::Language(void) { obj_type=ObjectType::Language; is_trusted=false; for(unsigned i=ValidatorFunc; i <= InlineFunc; i++) functions[i]=nullptr; attributes[Attributes::Trusted]=QString(); attributes[Attributes::HandlerFunc]=QString(); attributes[Attributes::ValidatorFunc]=QString(); attributes[Attributes::InlineFunc]=QString(); } void Language::setName(const QString &name) { //Raises an error if the user try to set an system reserved language name (C, SQL) if(name.toLower()==~LanguageType("c") || name.toLower()==~LanguageType("sql")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgReservedName) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Language)), ErrorCode::AsgReservedName,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObject::setName(name); } void Language::setTrusted(bool value) { setCodeInvalidated(is_trusted != value); is_trusted=value; } void Language::setFunction(Function *func, unsigned func_type) { LanguageType lang=LanguageType::C; if(!func || (func && /* The handler function must be written in C and have 'language_handler' as return type */ ((func_type==HandlerFunc && func->getReturnType()==QString("language_handler") && func->getParameterCount()==0 && func->getLanguage()->getName()==(~lang)) || /* The validator function must be written in C and return 'void' also must have only one parameter of the type 'oid' */ (func_type==ValidatorFunc && func->getReturnType()==QString("void") && func->getParameterCount()==1 && func->getParameter(0).getType() == QString("oid") && func->getLanguage()->getName()==(~lang)) || /* The inline function must be written in C and return 'void' also must have only one parameter of the type 'internal' */ (func_type==InlineFunc && func->getReturnType()==QString("void") && func->getParameterCount()==1 && func->getParameter(0).getType() == QString("internal") && func->getLanguage()->getName()==(~lang)) ))) { setCodeInvalidated(functions[func_type] != func); this->functions[func_type]=func; } //Raises an error in case the function return type doesn't matches the required by each rule else if((func_type==HandlerFunc && func->getReturnType()!=QString("language_handler")) || ((func_type==ValidatorFunc || func_type==InlineFunc) && func->getReturnType()!=QString("void"))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidReturnType) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Language)), ErrorCode::AsgFunctionInvalidReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else //Raises an error in case the function has invalid parameters (count and types) throw Exception(ErrorCode::AsgFunctionInvalidParameters,__PRETTY_FUNCTION__,__FILE__,__LINE__); } Function * Language::getFunction(unsigned func_type) { if(func_type > InlineFunc) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(functions[func_type]); } bool Language::isTrusted(void) { return(is_trusted); } QString Language::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString Language::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); unsigned i; QString attribs_func[3]={Attributes::ValidatorFunc, Attributes::HandlerFunc, Attributes::InlineFunc}; attributes[Attributes::Trusted]=(is_trusted ? Attributes::True : QString()); if(!reduced_form && def_type==SchemaParser::XmlDefinition) reduced_form=(!functions[ValidatorFunc] && !functions[HandlerFunc] && !functions[InlineFunc] && !this->getOwner()); for(i=0; i < 3; i++) { if(functions[i]) { if(def_type==SchemaParser::SqlDefinition) attributes[attribs_func[i]]=functions[i]->getName(true); else { functions[i]->setAttribute(Attributes::RefType, attribs_func[i]); attributes[attribs_func[i]]=functions[i]->getCodeDefinition(def_type, true); } } } return(BaseObject::getCodeDefinition(def_type, reduced_form)); } pgmodeler-0.9.2/libpgmodeler/src/language.h000066400000000000000000000046331360462764600207140ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Language \brief Implements the operations to manipulate procedural languages on the database. \note Creation date: 19/05/2008 */ #ifndef LANGUAGE_H #define LANGUAGE_H #include "baseobject.h" #include "function.h" #include "role.h" class Language: public BaseObject{ private: /*! \brief Indicates whether the language is trusted on the database which means that the object can be used by an unprivileged user without compromise the entire database security */ bool is_trusted; //! \brief Functions that defines the language behavior Function *functions[3]; public: /*! \brief Constants used to reference the language's functions: > VALIDATOR: Function that validates the code written in the language's syntax > HANDLER: Function that executes the functions written in the language's syntax > INLINE: Function that executes inline instructions (DO's) (only on PostgreSQL 9.x) */ static constexpr unsigned ValidatorFunc=0, HandlerFunc=1, InlineFunc=2; Language(void); //! \brief Sets the language name void setName(const QString &name); //! \brief Sets whether the language is trusted or not void setTrusted(bool value); //! \brief Sets one of the language auxiliary functions void setFunction(Function *func, unsigned func_type); //! \brief Returs the trusted state of the language bool isTrusted(void); //! \brief Returns one of the auxiliary functions Function *getFunction(unsigned func_type); //! \brief Returns the SQL / XML code definition for the language virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getCodeDefinition(unsigned def_type) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/operation.cpp000066400000000000000000000054001360462764600214550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operation.h" Operation::Operation(void) { parent_obj=nullptr; pool_obj=nullptr; original_obj=nullptr; object_idx=-1; chain_type=NoChain; op_type=NoOperation; } QString Operation::generateOperationId(void) { QString addr; QTextStream stream(&addr); QCryptographicHash hash(QCryptographicHash::Md5); //Stores the permission address on a string stream << reinterpret_cast(original_obj); stream << reinterpret_cast(pool_obj); stream << reinterpret_cast(parent_obj); //Generates an unique id through md5 hash hash.addData(QByteArray(addr.toStdString().c_str())); return(hash.result().toHex()); } void Operation::setObjectIndex(int idx) { object_idx=idx; } void Operation::setChainType(unsigned type) { chain_type=(type > ChainEnd ? NoChain : type); } void Operation::setOperationType(unsigned type) { op_type=(type > ObjectMoved ? NoOperation : type); } void Operation::setOriginalObject(BaseObject *object) { original_obj=object; operation_id=generateOperationId(); } void Operation::setPoolObject(BaseObject *object) { pool_obj=object; operation_id=generateOperationId(); } void Operation::setParentObject(BaseObject *object) { parent_obj=object; operation_id=generateOperationId(); } void Operation::setPermissions(const vector &perms) { permissions=perms; } void Operation::setXMLDefinition(const QString &xml_def) { xml_definition=xml_def; } int Operation::getObjectIndex(void) { return(object_idx); } unsigned Operation::getChainType(void) { return(chain_type); } unsigned Operation::getOperationType(void) { return(op_type); } BaseObject *Operation::getOriginalObject(void) { return(original_obj); } BaseObject *Operation::getPoolObject(void) { return(pool_obj); } BaseObject *Operation::getParentObject(void) { return(parent_obj); } vector Operation::getPermissions(void) { return(permissions); } QString Operation::getXMLDefinition(void) { return(xml_definition); } bool Operation::isOperationValid(void) { return(operation_id==generateOperationId()); } pgmodeler-0.9.2/libpgmodeler/src/operation.h000066400000000000000000000100651360462764600211250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Operation \brief Implements the class that stores operations executed over an object */ #ifndef OPERATION_H #define OPERATION_H #include "baseobject.h" #include "permission.h" #include class Operation { private: /*! \brief Uniquely identifies the object. This id is used to check if the operation object's somehow where delete (changing their addresses). This will avoid the operation list to try to execute an invalid operation */ QString operation_id; /*! \brief Reference to the parent object of the original object that has suffered the operation, This attribute is used only in the case of table objects such as columns, indexes, constraints, rules. For other object types there is no need to use this attribute because the parent object for other objects is always the database model */ BaseObject *parent_obj; //! \brief Reference (on the pool) to the copy of the original object BaseObject *pool_obj; //! \brief Reference to the original object that generates the operation. BaseObject *original_obj; /*! \brief Stores the XML definition of the special objects this means the objects that reference columns added by relationship. This is the case of triggers, indexes, sequences, constraints. */ QString xml_definition; //! \brief Operation type (Constants OBJECT_[MODIFIED | CREATED | REMOVED | MOVED] unsigned op_type; //! \brief Operation chain type. This attribute is used to redo/undo several operations at once unsigned chain_type; //! \brief Object index inside the list on its parent object int object_idx; //! \brief Stores the object's permission before it's removal vector permissions; //! \brief Generate an unique id for the operation based upon the memory addresses of objects held by it QString generateOperationId(void); public: //! \brief Constants used to reference the type of operations static constexpr unsigned NoOperation=0, ObjectModified=1, ObjectCreated=2, ObjectRemoved=3, /*! \brief This type of operation has the same effect of operation OBJECT_MODIFIED except that it not (re)validate relationships as happens with operations. This type of operation (OBJECT_MOVED) is useful to undo position changes of graphical objects without executing unnecessary revalidations of relationships */ ObjectMoved=4; //! \brief Operation chain types static constexpr unsigned NoChain=0, //! \brief The operation is not part of a chain ChainStart=1, //! \brief The operation is the head of the chain ChainMiddle=2, //! \brief The operation is in the middle of the chain ChainEnd=3; //! \brief The operation is the last on the chain Operation(void); void setObjectIndex(int idx); void setChainType(unsigned type); void setOperationType(unsigned type); void setOriginalObject(BaseObject *object); void setPoolObject(BaseObject *object); void setParentObject(BaseObject *object); void setPermissions(const vector &perms); void setXMLDefinition(const QString &xml_def); int getObjectIndex(void); unsigned getChainType(void); unsigned getOperationType(void); BaseObject *getOriginalObject(void); BaseObject *getPoolObject(void); BaseObject *getParentObject(void); vector getPermissions(void); QString getXMLDefinition(void); bool isOperationValid(void); }; #endif pgmodeler-0.9.2/libpgmodeler/src/operationlist.cpp000066400000000000000000000762451360462764600223700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operationlist.h" unsigned OperationList::max_size=500; OperationList::OperationList(DatabaseModel *model) { /* Raises an error if the user tries to allocate an operation list linked to to an unallocated model */ if(!model) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->model=model; xmlparser=model->getXMLParser(); current_index=0; next_op_chain=Operation::NoChain; ignore_chain=false; operations.reserve(max_size); } OperationList::~OperationList(void) { removeOperations(); } unsigned OperationList::getCurrentSize(void) { return(operations.size()); } unsigned OperationList::getMaximumSize(void) { return(max_size); } int OperationList::getCurrentIndex(void) { return(current_index); } void OperationList::startOperationChain(void) { /* If the chaining is started and the user try it initializes again, the earlier chaining is finished */ if(next_op_chain!=Operation::NoChain) finishOperationChain(); /* The next operation inserted on the list will be the start of the chaining */ next_op_chain=Operation::ChainStart; } void OperationList::finishOperationChain(void) { /* If the chain is not ignored indicates that the next element of the list no longer will be part of chaining */ if(!ignore_chain) next_op_chain=Operation::NoChain; else if(ignore_chain) /* If the chain is canceled indicates that the next element of the list still part of the chaining */ next_op_chain=Operation::ChainMiddle; if(operations.size() > 0 && !ignore_chain) { unsigned idx=operations.size()-1; /* Marks the last operatin as being the end of chaining in case it is on the middle of chain */ if(operations[idx]->getChainType()==Operation::ChainMiddle) operations[idx]->setChainType(Operation::ChainEnd); /* If the last operation is marked as CHAIN_START indicates that the chaining was open but only one operation is recorded and thus the operation is marked as NO_CHAIN because as it is only one operation there is no need to treat it as chaining */ else if(operations[idx]->getChainType()==Operation::ChainStart) operations[idx]->setChainType(Operation::NoChain); } } void OperationList::ignoreOperationChain(bool value) { ignore_chain=value; } bool OperationList::isOperationChainStarted(void) { return(next_op_chain==Operation::ChainStart || next_op_chain==Operation::ChainMiddle); } bool OperationList::isObjectRegistered(BaseObject *object, unsigned op_type) { bool registered=false; vector::iterator itr=operations.begin(); while(itr!=operations.end() && !registered) { registered=((*itr)->getOriginalObject()==object && (*itr)->getOperationType()==op_type); itr++; } return(registered); } bool OperationList::isRedoAvailable(void) { /* The redo operation only can be performed if the current index from the list of operations is at most the penultimate element and the list can not be empty */ return(!operations.empty() && current_index < static_cast(operations.size())); } bool OperationList::isUndoAvailable(void) { /* For the undo operation be performed is enough that the list of operations is not empty */ return(!operations.empty() && current_index > 0); } void OperationList::setMaximumSize(unsigned max) { //Raises an error if a zero max size is assigned to the list if(max==0) throw Exception(ErrorCode::AsgInvalidMaxSizeOpList,__PRETTY_FUNCTION__,__FILE__,__LINE__); max_size=max; } void OperationList::addToPool(BaseObject *object, unsigned op_type) { ObjectType obj_type; try { //Raises an error if the object to be added is not allocated if(!object) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); obj_type=object->getObjectType(); //Stores a copy of the object if its about to be moved or modified if(op_type==Operation::ObjectModified || op_type==Operation::ObjectMoved) { BaseObject *copy_obj=nullptr; if(obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::Database) PgModelerNs::copyObject(©_obj, object, obj_type); else throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the copy fails (returning a null object) if(!copy_obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else //Inserts the copy on the pool object_pool.push_back(copy_obj); } else //Inserts the original object on the pool (in case of adition or deletion operations) object_pool.push_back(object); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void OperationList::removeOperations(void) { BaseObject *object=nullptr; TableObject *tab_obj=nullptr; BaseTable *tab=nullptr; Operation *oper=nullptr; vector invalid_objs; //Destroy the operations while(!operations.empty()) { oper=operations.back(); /* If the operation is not valid means that in some moment the pool object inside it was destroyed (by a relationship invalidation for instance) and to avoid crashes this object is stored in a invalid objects list */ if(!oper->isOperationValid()) invalid_objs.push_back(oper->getPoolObject()); delete(oper); operations.pop_back(); } //Destroy the object pool while(!object_pool.empty()) removeFromPool(0); //Case there is not removed object while(!not_removed_objs.empty()) { object=not_removed_objs.back(); //If the object is not an invalid one, proceed with its deallocation if(std::find(invalid_objs.begin(), invalid_objs.end(), object)==invalid_objs.end()) { if(unallocated_objs.count(object)==0) tab_obj=dynamic_cast(object); //Deletes the object if its not unallocated already or referenced on the model if(unallocated_objs.count(object)==0 && (!tab_obj && model->getObjectIndex(object) < 0)) { if(object->getObjectType()==ObjectType::Table) { vector list=dynamic_cast
(object)->getObjects(); while(!list.empty()) { unallocated_objs[list.back()]=true; list.pop_back(); } } unallocated_objs[object]=true; delete(object); } else if(tab_obj && unallocated_objs.count(tab_obj)==0) { tab=dynamic_cast(tab_obj->getParentTable()); //Deletes the object if its not unallocated already or referenced by some table if(!tab || (unallocated_objs.count(tab)==1) || (tab && unallocated_objs.count(tab)==0 && tab->getObjectIndex(tab_obj) < 0)) { unallocated_objs[tab_obj]=true; delete(tab_obj); } } } not_removed_objs.pop_back(); tab_obj=nullptr; } current_index=0; unallocated_objs.clear(); } void OperationList::validateOperations(void) { vector::iterator itr, itr_end; Operation *oper=nullptr; itr=operations.begin(); itr_end=operations.end(); while(itr!=itr_end) { oper=(*itr); //Case the object isn't on the pool if(!isObjectOnPool((*itr)->getPoolObject()) || !oper->isOperationValid()) { //Remove the operation operations.erase(itr); delete(oper); itr=operations.begin(); itr_end=operations.end(); } else itr++; } } bool OperationList::isObjectOnPool(BaseObject *object) { bool found=false; vector::iterator itr, itr_end; if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=object_pool.begin(); itr_end=object_pool.end(); while(!found && itr!=itr_end) { found=*(itr)==object; itr++; } return(found); } void OperationList::removeFromPool(unsigned obj_idx) { BaseObject *object=nullptr; vector::iterator itr; //Avoiding the removal of an object in invalid index (out of bound) if(obj_idx >= object_pool.size()) return; //Gets the element to bo removed through its index itr=object_pool.begin() + obj_idx; object=(*itr); //Removes the object from pool object_pool.erase(itr); /* Stores the object that was in the pool on the 'not_removed_objs' vector. The object will be deleted in the destructor of the list. Note: The object is not deleted immediately because the model / table / list of operations may still referencing the object or it becomes referenced when an operation is performed on the list. */ not_removed_objs.push_back(object); } int OperationList::registerObject(BaseObject *object, unsigned op_type, int object_idx, BaseObject *parent_obj) { ObjectType obj_type; Operation *operation=nullptr; BaseTable *parent_tab=nullptr; Relationship *parent_rel=nullptr; TableObject *tab_obj=nullptr; tab_obj=dynamic_cast(object); int obj_idx=-1; try { //Raises an error if the user tries to register an operation with null object if(!object) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); obj_type=object->getObjectType(); if(tab_obj && !parent_obj) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(parent_obj && (((obj_type==ObjectType::Column || obj_type==ObjectType::Constraint) && (parent_obj->getObjectType()!=ObjectType::Relationship && !PhysicalTable::isPhysicalTable(parent_obj->getObjectType()))) || ((obj_type==ObjectType::Trigger || obj_type==ObjectType::Rule || obj_type==ObjectType::Index) && !dynamic_cast(parent_obj)))) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); //If the operations list is full makes the automatic cleaning before inserting a new operation if(current_index == static_cast(max_size-1)) removeOperations(); /* If adding an operation and the current index is not pointing to the end of the list (available redo / user ran undo operations) all elements from the current index to the end of the list will be deleted as well as the objects in the pool that were linked to the excluded operations */ if(current_index>=0 && static_cast(current_index)!=operations.size()) { //Gets the last operation index int i=operations.size()-1; //Removes all the operation while the current index isn't reached while(i >= current_index) { removeFromPool(i); i--; } //Validates the remaining operatoins after the deletion validateOperations(); } //Creates the new operation operation=new Operation; operation->setOperationType(op_type); operation->setChainType(next_op_chain); operation->setOriginalObject(object); //Adds the object on te pool addToPool(object, op_type); //Assigns the pool object to the operation operation->setPoolObject(object_pool.back()); //Stores the object's permission befor its removal if(op_type==Operation::ObjectRemoved) { vector perms; model->getPermissions(object, perms); operation->setPermissions(perms); } if(next_op_chain==Operation::ChainStart) next_op_chain=Operation::ChainMiddle; /* Performing specific operations according to the type of object. If the object has a parent object, it must be discovered and moreover it is necessary to find and store the index of the object in the list on the parent object */ if(tab_obj) { if(parent_obj->getObjectType()==ObjectType::Relationship) parent_rel=dynamic_cast(parent_obj); else parent_tab=dynamic_cast(parent_obj); if(((obj_type==ObjectType::Trigger && dynamic_cast(tab_obj)->isReferRelationshipAddedColumn()) || (obj_type==ObjectType::Index && dynamic_cast(tab_obj)->isReferRelationshipAddedColumn()) || (obj_type==ObjectType::Constraint && dynamic_cast(tab_obj)->isReferRelationshipAddedColumn()))) { if(op_type==Operation::ObjectRemoved) tab_obj->setParentTable(parent_tab); if(tab_obj->getObjectType()==ObjectType::Constraint) operation->setXMLDefinition(dynamic_cast(tab_obj)->getCodeDefinition(SchemaParser::XmlDefinition, true)); else operation->setXMLDefinition(tab_obj->getCodeDefinition(SchemaParser::XmlDefinition)); } operation->setParentObject(parent_obj); /* If there is a parent relationship will get the index of the object. Only columns and constraints are handled case the parent is a relationship */ if(parent_rel && (obj_type==ObjectType::Column || obj_type==ObjectType::Constraint)) { //Case a specific index wasn't specified if(object_idx < 0) //Stores on the operation the index on its parent obj_idx=parent_rel->getObjectIndex(tab_obj); else //Assigns the specific index to operation obj_idx=object_idx; } //Case there is a parent table will get the object's index else if(parent_tab) { if(object_idx < 0) //Stores on the operation the index of object on its parent obj_idx=parent_tab->getObjectIndex(object->getName(false), obj_type); else obj_idx=object_idx; } //Raises an error if both parent table / relationship isn't allocated else throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { if((obj_type==ObjectType::Sequence && dynamic_cast(object)->isReferRelationshipAddedColumn()) || (obj_type==ObjectType::View && dynamic_cast(object)->isReferRelationshipAddedColumn()) || (obj_type==ObjectType::GenericSql && dynamic_cast(object)->isReferRelationshipAddedObject())) operation->setXMLDefinition(object->getCodeDefinition(SchemaParser::XmlDefinition)); //Case a specific index wasn't specified if(object_idx < 0) //Stores on the operation the object index on the model obj_idx=model->getObjectIndex(object); else //Assigns the specific index to object obj_idx=object_idx; } if(obj_type==ObjectType::Column && dynamic_cast(object)->getType().isUserType()) operation->setXMLDefinition(object->getCodeDefinition(SchemaParser::XmlDefinition)); operation->setObjectIndex(obj_idx); operations.push_back(operation); current_index=operations.size(); //Returns the last operation position as operation's ID return(operations.size()-1); } catch(Exception &e) { if(operation) { removeFromPool(object_pool.size()-1); delete(operation); } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void OperationList::getOperationData(unsigned oper_idx, unsigned &oper_type, QString &obj_name, ObjectType &obj_type) { Operation *operation=nullptr; BaseObject *pool_obj=nullptr; if(oper_idx >= operations.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); operation=operations[oper_idx]; oper_type=operation->getOperationType(); if(operation->isOperationValid()) { pool_obj=operation->getPoolObject(); obj_type=pool_obj->getObjectType(); obj_name=pool_obj->getName(true); if(TableObject::isTableObject(obj_type)) obj_name=operation->getParentObject()->getName(true) + QString(".") + obj_name; } else { obj_type=ObjectType::BaseObject; obj_name=trUtf8("(invalid object)"); } } unsigned OperationList::getChainSize(void) { int i=current_index-1; unsigned size=0; if(i < 0 && !operations.empty()) i=0; //Checks if the current operations is chained if(!operations.empty() && operations[i]->getChainType()!=Operation::NoChain) { unsigned chain_type=Operation::NoChain; int inc=0; //Case the operation is the end of a chain runs the list in reverse order (from end to start) if(operations[i]->getChainType()==Operation::ChainEnd) { chain_type=Operation::ChainStart; inc=-1; } //Case the operation is the start of a chain runs the list in normal order (from start to end) else if(operations[i]->getChainType()==Operation::ChainStart) { chain_type=Operation::ChainEnd; inc=1; } //Calculates the size of chain while(i>=0 && i < static_cast(operations.size()) && size < operations.size() && operations[i]->getChainType()!=chain_type) { i+=inc; size++; } } return(size); } void OperationList::undoOperation(void) { if(isUndoAvailable()) { Operation *operation=nullptr; bool chain_active=false; Exception error; unsigned chain_size=0, pos=0; //if(!this->signalsBlocked()) chain_size=getChainSize(); do { /* In the undo operation, it is necessary to obtain the object at current index decremented by 1 since the current index always points to the element after the last element */ operation=operations[current_index-1]; /* If it is detected that the operation is chained with other and active chaining flag is cleared marks the flag to start the execution several operations at once */ if(!ignore_chain && !chain_active && operation->getChainType()!=Operation::NoChain) chain_active=true; /* If the chaining is active and the current operation is not part of chain, aborts execution of the operation */ else if(chain_active && (operation->getChainType()==Operation::ChainEnd || operation->getChainType()==Operation::NoChain)) break; try { if(chain_size > 0 && operation->isOperationValid()) pos++; //Executes the undo operation executeOperation(operation, false); } catch(Exception &e) { this->removeOperations(); error=e; } current_index--; } /* Performs the operations while the current operation is part of chain or the undo option is available */ while(!ignore_chain && isUndoAvailable() && operation->getChainType()!=Operation::NoChain); if(error.getErrorCode()!=ErrorCode::Custom) throw Exception(ErrorCode::UndoRedoOperationInvalidObject,__PRETTY_FUNCTION__,__FILE__,__LINE__, &error); } } void OperationList::redoOperation(void) { if(isRedoAvailable()) { Operation *operation=nullptr; bool chain_active=false; Exception error; unsigned chain_size=0, pos=0; chain_size=getChainSize(); do { //Gets the current operation operation=operations[current_index]; /* If it is detected that the operation is chained with other and active chaining flag is cleared marks the flag to start the execution several operations at once */ if(!ignore_chain && !chain_active && operation->getChainType()!=Operation::NoChain) chain_active=true; /* If the chaining is active and the current operation is not part of chain or it is at the start of chain, aborts execution of the operation */ else if(chain_active && (operation->getChainType()==Operation::ChainStart || operation->getChainType()==Operation::NoChain)) break; try { if(chain_size > 0 && operation->isOperationValid()) pos++; //Executes the redo operation (second argument as 'true') executeOperation(operation, true); } catch(Exception &e) { this->removeOperations(); error=e; } current_index++; } /* Performs the operations while the current operation is part of chain or the redo option is available */ while(!ignore_chain && isRedoAvailable() && operation->getChainType()!=Operation::NoChain); if(error.getErrorCode()!=ErrorCode::Custom) throw Exception(ErrorCode::UndoRedoOperationInvalidObject,__PRETTY_FUNCTION__,__FILE__,__LINE__, &error); } } void OperationList::executeOperation(Operation *oper, bool redo) { if(oper && oper->isOperationValid()) { BaseObject *orig_obj=nullptr, *bkp_obj=nullptr, *object=nullptr, *aux_obj=nullptr, *parent_obj=nullptr; ObjectType obj_type; BaseTable *parent_tab=nullptr; Relationship *parent_rel=nullptr; QString xml_def; unsigned op_type=Operation::NoOperation; int obj_idx=-1; object=oper->getPoolObject(); obj_type=object->getObjectType(); parent_obj=oper->getParentObject(); xml_def=oper->getXMLDefinition(); op_type=oper->getOperationType(); obj_idx=oper->getObjectIndex(); /* Converting the parent object, if any, to the correct class according to the type of the parent object. If ObjectType::Table|ObjectType::View, the pointer 'parent_tab' get the reference to table/view and will be used as referential in the operations below. If the parent object is a relationship, the pointer 'parent_rel' get the reference to the relationship */ if(parent_obj) { if(parent_obj->getObjectType()==ObjectType::Relationship) parent_rel=dynamic_cast(parent_obj); else parent_tab=dynamic_cast(parent_obj); } /* If the XML definition of object is set indicates that it is referencing a column included by relationship (special object) */ if(!xml_def.isEmpty() && ((op_type==Operation::ObjectRemoved && !redo) || (op_type==Operation::ObjectCreated && redo) || (op_type==Operation::ObjectModified || op_type==Operation::ObjectMoved))) { //Resets the XML parser and loads the buffer xml from the operation xmlparser->restartParser(); xmlparser->loadXMLBuffer(xml_def); if(obj_type==ObjectType::Trigger) aux_obj=model->createTrigger(); else if(obj_type==ObjectType::Index) aux_obj=model->createIndex(); else if(obj_type==ObjectType::Constraint) aux_obj=model->createConstraint(parent_obj); else if(obj_type==ObjectType::Sequence) aux_obj=model->createSequence(); else if(obj_type==ObjectType::View) aux_obj=model->createView(); else if(obj_type==ObjectType::Column) aux_obj=model->createColumn(); else if(obj_type==ObjectType::GenericSql) aux_obj=model->createGenericSQL(); } /* If the operation is a modified/moved object, the object copy stored in the pool will be restored */ if(op_type==Operation::ObjectModified || op_type==Operation::ObjectMoved) { if(obj_type==ObjectType::Relationship) { /* Due to the complexity of the class Relationship and the strong link between all relationships of the model it is necessary to store XML for special objects and disconnect ALL relationships, perform the modification at it and the revalidating all relationships again. */ model->storeSpecialObjectsXML(); model->disconnectRelationships(); } //Gets the object in the current state from the parent object if(parent_tab) orig_obj=dynamic_cast(parent_tab->getObject(obj_idx, obj_type)); else if(parent_rel) orig_obj=dynamic_cast(parent_rel->getObject(obj_idx, obj_type)); else orig_obj=model->getObject(obj_idx, obj_type); if(aux_obj) oper->setXMLDefinition(orig_obj->getCodeDefinition(SchemaParser::XmlDefinition)); //For pk constraint, before restore the previous configuration, uncheck the not-null flag of the source columns if(obj_type==ObjectType::Constraint) dynamic_cast(orig_obj)->setColumnsNotNull(false); /* The original object (obtained from the table, relationship or model) will have its previous values restored with the existing copy on the pool. After restoring the object on the pool will have the same attributes as the object before being restored to enable redo operations */ PgModelerNs::copyObject(reinterpret_cast(&bkp_obj), orig_obj, obj_type); PgModelerNs::copyObject(reinterpret_cast(&orig_obj), object, obj_type); PgModelerNs::copyObject(reinterpret_cast(&object), bkp_obj, obj_type); object=orig_obj; if(aux_obj) PgModelerNs::copyObject(reinterpret_cast(&object), aux_obj, obj_type); //For pk constraint, after restore the previous configuration, check the not-null flag of the new source columns if(obj_type==ObjectType::Constraint) dynamic_cast(orig_obj)->setColumnsNotNull(true); } /* If the operation is of object removed and is not a redo, or if the object was previously created and wants to redo the operation the existing pool object will be inserted into table or in your relationship on its original index */ else if((op_type==Operation::ObjectRemoved && !redo) || (op_type==Operation::ObjectCreated && redo)) { if(aux_obj) PgModelerNs::copyObject(reinterpret_cast(&object), aux_obj, obj_type); if(parent_tab) { parent_tab->addObject(dynamic_cast(object), obj_idx); if(object->getObjectType()==ObjectType::Constraint && dynamic_cast(object)->getConstraintType()==ConstraintType::ForeignKey) model->updateTableFKRelationships(dynamic_cast
(parent_tab)); } else if(parent_rel) parent_rel->addObject(dynamic_cast(object), obj_idx); else if(object->getObjectType()==ObjectType::Table) dynamic_cast
(object)->getCodeDefinition(SchemaParser::SqlDefinition); model->addObject(object, obj_idx); if(op_type==Operation::ObjectRemoved) model->addPermissions(oper->getPermissions()); } /* If the operation is a previously created object or if the object was removed and wants to redo the operation it'll be excluded from the table or relationship */ else if((op_type==Operation::ObjectCreated && !redo) || (op_type==Operation::ObjectRemoved && redo)) { if(parent_tab) parent_tab->removeObject(object); else if(parent_rel) parent_rel->removeObject(dynamic_cast(object)); else model->removeObject(object, obj_idx); } /* If the parent table or parent relationship is set indicates that the operation was performed on a child object of these objects */ if(parent_tab || parent_rel) { if(parent_tab) { parent_tab->setCodeInvalidated(true); parent_tab->setModified(true); if(parent_tab->getSchema()) dynamic_cast(parent_tab->getSchema())->setModified(true); if(object->getObjectType()==ObjectType::Column || object->getObjectType()==ObjectType::Constraint) { model->validateRelationships(dynamic_cast(object), dynamic_cast
(parent_tab)); if(object->getObjectType()==ObjectType::Constraint && dynamic_cast(object)->getConstraintType()==ConstraintType::ForeignKey) model->updateTableFKRelationships(dynamic_cast
(parent_tab)); else if(object->getObjectType() == ObjectType::Column) model->updateViewsReferencingTable(dynamic_cast
(parent_tab)); } } else if(parent_rel) { parent_rel->setCodeInvalidated(true); parent_rel->forceInvalidate(); model->validateRelationships(); } } /* If the object in question is graphical it has the modified flag marked to force the redraw at the time of its restoration */ else if(BaseGraphicObject::isGraphicObject(obj_type)) { BaseGraphicObject *graph_obj=dynamic_cast(object); if(op_type==Operation::ObjectModified || op_type==Operation::ObjectMoved) graph_obj->setModified(true); //Case the object is a view is necessary to update the table-view relationships on the model if(obj_type==ObjectType::View && op_type==Operation::ObjectModified) model->updateViewRelationships(dynamic_cast(graph_obj)); else if((obj_type==ObjectType::Relationship || (PhysicalTable::isPhysicalTable(obj_type) && model->getRelationship(dynamic_cast(object), nullptr))) && op_type==Operation::ObjectModified) model->validateRelationships(); //If a object had its schema restored is necessary to update the envolved schemas if(BaseTable::isBaseTable(obj_type) && ((bkp_obj && graph_obj->getSchema()!=bkp_obj->getSchema() && op_type==Operation::ObjectModified) || op_type==Operation::ObjectMoved)) { dynamic_cast(graph_obj->getSchema())->setModified(true); if(bkp_obj) dynamic_cast(bkp_obj->getSchema())->setModified(op_type==Operation::ObjectModified); } } else if(op_type==Operation::ObjectModified) { if(obj_type==ObjectType::Schema) { model->validateSchemaRenaming(dynamic_cast(object), bkp_obj->getName()); dynamic_cast(object)->setModified(true); } else if(obj_type==ObjectType::Tag) { vector refs; model->getObjectReferences(object, refs); while(!refs.empty()) { dynamic_cast(refs.back())->setModified(true); refs.pop_back(); } } } //Case the object is a type update the tables that are referencing it if(op_type==Operation::ObjectModified && (object->getObjectType()==ObjectType::Type || object->getObjectType()==ObjectType::Domain || object->getObjectType()==ObjectType::Table || object->getObjectType()==ObjectType::ForeignTable || object->getObjectType()==ObjectType::View || object->getObjectType()==ObjectType::Extension)) { vector ref_objs; model->getObjectReferences(object, ref_objs); for(auto &obj : ref_objs) { if(obj->getObjectType()==ObjectType::Column) dynamic_cast(obj)->getParentTable()->setModified(true); } } } } void OperationList::removeLastOperation(void) { if(!operations.empty()) { Operation *oper=nullptr; bool end=false; vector::reverse_iterator itr; int oper_idx=operations.size()-1; //Gets the last operation on the list using reverse iterator itr=operations.rbegin(); while(!end) { oper=(*itr); //Removes the object related to the operation from the pool removeFromPool(oper_idx); /* Stop condition for removing the operation: 1) The operation is not chained with others, or 2) If the last operation at the end of a chain all chained operations are removed including the first operation of the chain, when the latter is removed the iteration is stopped.*/ end=(ignore_chain || (!ignore_chain && (oper->getChainType()==Operation::NoChain || oper->getChainType()==Operation::ChainStart))); itr++; oper_idx--; } /* If the head of chaining is removed (CHAIN_START) marks that the next element in the list is the new start of chain */ if(oper && oper->getChainType()==Operation::ChainStart) next_op_chain=Operation::ChainStart; //Erasing the excluded operations for(int i=operations.size()-1; i > oper_idx ; i--) operations.erase(operations.begin() + i); //Validates the remaining operations validateOperations(); /* Points the current index to the end of list if it is beyond the last element */ if(static_cast(current_index) > operations.size()) current_index=operations.size(); } } void OperationList::updateObjectIndex(BaseObject *object, unsigned new_idx) { vector::iterator itr, itr_end; Operation *oper=nullptr; if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=operations.begin(); itr_end=operations.end(); while(itr!=itr_end) { oper=(*itr); if(oper->getOriginalObject()==object) oper->setObjectIndex(new_idx); itr++; } } pgmodeler-0.9.2/libpgmodeler/src/operationlist.h000066400000000000000000000167521360462764600220320ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class OperationList \brief Implements the operations to maintain a list of modifications made by the user on database model objects. This class permits that user undo / redo all the operations made. \note Creation date: 17/07/2006 */ #ifndef OPERATIONLIST_H #define OPERATIONLIST_H #include "databasemodel.h" #include "pgmodelerns.h" #include "operation.h" class OperationList: public QObject { private: Q_OBJECT //! \brief Inidcates that operation chaining is ignored temporarily bool ignore_chain; XmlParser *xmlparser; //! \brief List of objects that were removed / modified on the model vector object_pool; /*! \brief List of objects that at the time of deletion from pool were still referenced somehow on the model. The object is stored in this secondary list and deleted when the whole list of operations is destroyed */ vector not_removed_objs; /*! \brief Stores the objects that were unallocated on the removeOperations() method. This maps is used in order to avoid double delete on pointers. */ map unallocated_objs; //! \brief Stores the operations executed by the user vector operations; //! \brief Database model that is linked with this operation list DatabaseModel *model; //! \brief Maximum number of stored operations (global) static unsigned max_size; /*! \brief Stores the type of chain to the next operation to be stored in the list. This attribute is used in conjunction with the chaining initialization / finalization methods. */ unsigned next_op_chain; //! \brief Current operation index int current_index; /*! \brief Validates operations by checking whether they have registered objects in the pool. If found any operation whose object is not in the pool it will be removed because an object outside the pool does not give a guarantee that is being referenced in the model. */ void validateOperations(void); //! \brief Checks whether the passed object is in the pool bool isObjectOnPool(BaseObject *object); //! \brief Adds the object on the pool according to the operation type passed void addToPool(BaseObject *object, unsigned op_type); /*! \brief Removes one object from the pool using its index and deallocating it in case the object is not referenced on the model */ void removeFromPool(unsigned obj_idx); /*! \brief Executes the passed operation. The default behavior is the 'undo' if the user passes the parameter 'redo=true' the method executes the redo function */ void executeOperation(Operation *operacao, bool redo); //! \brief Returns the chain size from the current element unsigned getChainSize(void); public: OperationList(DatabaseModel *model); ~OperationList(void); /*! \brief Starts chaining operations. This means that all operations added after calling this method will be considered to be performed all at once with a single call to the redoOperation / undoOperation methods */ void startOperationChain(void); /*! \brief Finalizes the chaining marking the last operation on the list as the end of operation chain */ void finishOperationChain(void); /*! \brief Cancels the execution of operations in the form of chaining, but if the list is open with chaining operations included will be chained too. This method helps in situations where is necessary to remove operations or execute them one by one but keeping the chaining created earlier. Note: The user must cancel the annulment of chaining to be able to finalize the operations chaining. If it does not happens the operations will be created chained indefinitely */ void ignoreOperationChain(bool value); //! \brief Returns if the operation chaining where started bool isOperationChainStarted(void); //! \brief Returns if an operation of the specified op_type is already registered for the object bool isObjectRegistered(BaseObject *object, unsigned op_type); //! \brief Undo the current operation on the list void undoOperation(void); //! \brief Redo the current operation on the list void redoOperation(void); //! \brief Removes all the operations from the list void removeOperations(void); //! \brief Gets the data from the operation with specified index void getOperationData(unsigned oper_idx, unsigned &oper_type, QString &obj_name, ObjectType &obj_type); //! \brief Sets the maximum size for the list static void setMaximumSize(unsigned max); /*! \brief Registers in the list of operations that the passed object suffered some kind of modification (modified, removed, inserted, moved) in addition the method stores its original content. This method should ALWAYS be called before the object in question suffers any operation in the model. If this method is called after an operation on the object the order of restoration / re-execution of operations can be broken and cause segmentations fault. In case of success this method returns an integer indicating the last registered operation ID */ int registerObject(BaseObject *object, unsigned op_type, int object_idx=-1, BaseObject *parent_obj=nullptr); //! \brief Gets the maximum size for the operation list unsigned getMaximumSize(void); //! \brief Gets the current size for the operation list unsigned getCurrentSize(void); //! \brief Gets the current operation index int getCurrentIndex(void); //! \brief Returns if the list is prepared to execute redo operations bool isRedoAvailable(void); //! \brief Returns if the list is prepared to execute undo operations bool isUndoAvailable(void); /*! \brief Removes the last operation from the list. This method should be used with care as it can break the chain of operations. It should be used only when an exception is thrown after adding some object on the list and if the user wants to discard this operation due the thrown exception. If the last operation is part of a chain the entire chain of operations is removed. Warning: The execution of this method is different from the undo method because the objects are removed pool but their states prior to adding it to the list are not restored so this method can not be used deliberately. */ void removeLastOperation(void); /*! \brief Updates the index of the object when it suffers a movement in the parente object. Generally this method need not be called manually but in the case of table objects (like columns, rules, constraints, indexes and triggers) which can be moved (to have their position changed in the parent object). This method updates the index of the object with the new value for the operations which refer the object is not executed incorrectly using previous index */ void updateObjectIndex(BaseObject *object, unsigned new_idx); }; #endif pgmodeler-0.9.2/libpgmodeler/src/operator.cpp000066400000000000000000000273201360462764600213150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operator.h" Operator::Operator(void) { unsigned i; obj_type=ObjectType::Operator; for(i=FuncOperator; i <= FuncRestrict; i++) functions[i]=nullptr; for(i=Operator::OperCommutator; i <= OperNegator; i++) operators[i]=nullptr; hashes=merges=false; argument_types[LeftArg]=PgSqlType(QString("\"any\"")); argument_types[RightArg]=PgSqlType(QString("\"any\"")); attributes[Attributes::LeftType]=QString(); attributes[Attributes::RightType]=QString(); attributes[Attributes::CommutatorOp]=QString(); attributes[Attributes::NegatorOp]=QString(); attributes[Attributes::RestrictionFunc]=QString(); attributes[Attributes::JoinFunc]=QString(); attributes[Attributes::OperatorFunc]=QString(); attributes[Attributes::Hashes]=QString(); attributes[Attributes::Merges]=QString(); attributes[Attributes::Signature]=QString(); attributes[Attributes::RefType]=QString(); } bool Operator::isValidName(const QString &name) { //Warning: Do not alter the sequence of characters or the validation will fail QString valid_chars=QString("+-*/<>=~!@#%^&|'?"); int pos, len; bool valid=true; //Checks if the size of the name is valid valid=(name.size() <= static_cast(ObjectNameMaxLength)); /* Checking if the name is valid according the conditions: 1) The name has only the chars defined in 'valid_chars' */ len=name.size(); for(pos=0; pos < len && valid; pos++) valid=!(valid_chars.indexOf(name[pos]) < 0); //2) The name doesn't has sequences like -- or /* that defines SQL comments if(valid) valid=(name.indexOf(QLatin1String("--")) < 0); if(valid) valid=(name.indexOf(QLatin1String("/*")) < 0); //3) Case the name end with - or + it may own one or more chars in the set ~!@#%^&|'? if(name[name.size()-1]=='-' || name[name.size()-1]=='+') { //The set ~!@#%^&|' is defined from position 7 in the valid_chars string len=valid_chars.size(); for(pos=7; pos < len && valid; pos++) valid|=(name.indexOf(valid_chars[pos]) >= 0); } return(valid); } void Operator::setName(const QString &name) { if(name.isEmpty()) throw Exception(ErrorCode::AsgEmptyNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!isValidName(name)) throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->obj_name=name; } void Operator::setFunction(Function *func, unsigned func_type) { //Raises an error if the function type is invalid if(func_type > FuncRestrict) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(func_type==FuncOperator) { //Raises an error if the function is not allocated if(!func) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Operator)), ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the parameter count is invalid. To be used by the operator the function must own 1 or 2 parameters */ else if(func->getParameterCount()==0 || func->getParameterCount() > 2) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Operator)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { unsigned param_count=func->getParameterCount(); PgSqlType param_type1=PgSqlType(QString("\"any\"")), param_type2=PgSqlType(QString("\"any\"")); //Get the function parameter to make validations param_type1=func->getParameter(0).getType(); if(param_count==2) param_type2=func->getParameter(1).getType(); //Validates the function parameters according to the operator arguments //ERROR 1: The function have parameters of the type 'any' if((param_type1==QString("\"any\"") || (param_count==2 && param_type2==QString("\"any\""))) || //ERROR 2: The function parameter count is 1 and the type of operator argument is not 'any' (param_count==1 && argument_types[0]!=QString("\"any\"") && argument_types[1]!=QString("\"any\"")) || //ERROR 3: The function parameter count is 2 and the operator arguments is not 'any' (param_count==2 && ((argument_types[0]==QString("\"any\"") && argument_types[1]!=QString("\"any\"")) || (argument_types[0]!=QString("\"any\"") && argument_types[1]==QString("\"any\"")))) || /* ERROR 4: The function parameter count is 2 and the argument types differs from parameters type */ (param_count==2 && ((argument_types[0]==QString("\"any\"") || argument_types[1]==QString("\"any\"")) || (argument_types[0]!=param_type1 || argument_types[1]!=param_type2))) || //ERROR 5: When the function has 1 parameter the type differ from the operator argument (param_count==1 && ((argument_types[0]!=QString("\"any\"") && argument_types[0]!=param_type1) || (argument_types[1]!=QString("\"any\"") && argument_types[1]!=param_type1)))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParameters) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Operator)), ErrorCode::AsgFunctionInvalidParameters,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } setCodeInvalidated(functions[func_type] != func); functions[func_type]=func; } void Operator::setArgumentType(PgSqlType arg_type, unsigned arg_id) { //Raises an error if the argument id is invalid if(arg_id > RightArg) throw Exception(ErrorCode::RefOperatorArgumentInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(argument_types[arg_id] != arg_type); argument_types[arg_id]=arg_type; } void Operator::setOperator(Operator *oper, unsigned op_type) { //Raises an error if the operator type is invalid if(op_type > OperNegator) throw Exception(ErrorCode::RefOperatorInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { /* Validating the Commutator OP: According to the PostgreSQL documentation the commutator must have its right argument as the same type of left argument from the commuted operator. That is, if the operator ++(typeA, typeB) is being defined and its commutator operator is +*+ then the signature of the latter should be +*+ (typeB, typeA). Raises an error when this condition is not satisfied. */ if(oper && op_type==OperCommutator && argument_types[LeftArg]!=oper->argument_types[RightArg]) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidCommutatorOperator) .arg(oper->getSignature(true)) .arg(this->getSignature(true)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); } /* Validating Negator OP: According to the PostgreSQL documentation the negator operator must have its arguments as the same type of arguments from the operator to be defined. That is, if the operator !!(typeA) is being set and its negator is !*! then the signature of the latter should be !*! (typeA). Raises an error when this condition is not satisfied. */ else if(oper && op_type==OperNegator && (argument_types[LeftArg]!=oper->argument_types[LeftArg] && argument_types[RightArg]!=oper->argument_types[RightArg])) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidNegatorOperator) .arg(oper->getSignature(true)) .arg(this->getSignature(true)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); } setCodeInvalidated(operators[op_type] != oper); operators[op_type]=oper; } } void Operator::setHashes(bool value) { setCodeInvalidated(hashes != value); hashes=value; } void Operator::setMerges(bool value) { setCodeInvalidated(merges != value); merges=value; } Function *Operator::getFunction(unsigned func_type) { //Raises an error if the function type is invalid if(func_type > FuncRestrict) throw Exception(ErrorCode::RefOperatorInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(functions[func_type]); } PgSqlType Operator::getArgumentType(unsigned arg_id) { //Raises an error if the argument id is invalid if(arg_id > RightArg) throw Exception(ErrorCode::RefOperatorArgumentInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(argument_types[arg_id]); } Operator *Operator::getOperator(unsigned op_type) { //Raises an error if the operator type is invalid if(op_type > OperNegator) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(operators[op_type]); } bool Operator::isHashes(void) { return(hashes); } bool Operator::isMerges(void) { return(merges); } QString Operator::getSignature(bool format_name) { QString signature; QStringList args; unsigned i; signature=this->getName(format_name); for(i=0; i < 2; i++) { if(argument_types[i]==QString("\"any\"")) args.push_back(QString("NONE")); else args.push_back(argument_types[i].getTypeName(true)); } signature+=QString("(") + args.join(',') + QString(")"); return(signature); } QString Operator::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString Operator::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); unsigned i; QString type_attribs[]={Attributes::LeftType, Attributes::RightType}, op_attribs[]={ Attributes::CommutatorOp, Attributes::NegatorOp }, func_attribs[]={Attributes::OperatorFunc, Attributes::JoinFunc, Attributes::RestrictionFunc}; for(i=Operator::LeftArg; i <= Operator::RightArg; i++) { if(def_type==SchemaParser::SqlDefinition) { if(argument_types[i]!=QString("\"any\"")) attributes[type_attribs[i]]=~argument_types[i]; } else { attributes[type_attribs[i]]=argument_types[i]. getCodeDefinition(SchemaParser::XmlDefinition,type_attribs[i]); } } for(i=Operator::OperCommutator; i <= Operator::OperNegator; i++) { if(operators[i]) { if(def_type==SchemaParser::SqlDefinition) attributes[op_attribs[i]]=operators[i]->getName(true); else { operators[i]->attributes[Attributes::RefType]=op_attribs[i]; attributes[op_attribs[i]]=operators[i]->getCodeDefinition(def_type, true); } } } for(i=Operator::FuncOperator; i <= Operator::FuncRestrict; i++) { if(functions[i]) { if(def_type==SchemaParser::SqlDefinition) attributes[func_attribs[i]]=functions[i]->getName(true); else { functions[i]->setAttribute(Attributes::RefType, func_attribs[i]); attributes[func_attribs[i]]=functions[i]->getCodeDefinition(def_type, true); } } } attributes[Attributes::Hashes]=(hashes ? Attributes::True : QString()); attributes[Attributes::Merges]=(merges ? Attributes::True : QString()); attributes[Attributes::Signature]=getSignature(); return(BaseObject::getCodeDefinition(def_type, reduced_form)); } void Operator::configureSearchAttributes(void) { QStringList arg_types; BaseObject::configureSearchAttributes(); arg_types += *argument_types[0]; arg_types += *argument_types[1]; search_attribs[Attributes::Type] = arg_types.join("; "); } pgmodeler-0.9.2/libpgmodeler/src/operator.h000066400000000000000000000064231360462764600207630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate operators on the database. \note Creation date: 16/04/2008 */ #ifndef OPERATOR_H #define OPERATOR_H #include "baseobject.h" #include "function.h" #include "schema.h" #include "role.h" class Operator: public BaseObject { private: //! \brief Stores the functions that defines the operator Function *functions[3]; //! \brief Stores the arguments types (left and right) used by the operator PgSqlType argument_types[2]; //! \brief Stores the auxiliary operators Operator *operators[2]; bool hashes, //! \brief Indicates that the operator can execute a hash join merges; //! \brief Indicates that the operator can execute a merge join protected: virtual void configureSearchAttributes(void); public: static constexpr unsigned FuncOperator=0, FuncJoin=1, FuncRestrict=2, LeftArg=0, RightArg=1, OperCommutator=0, OperNegator=1; Operator(void); //! \brief Defines the name of the operator void setName(const QString &name); //! \brief Defines the function used by the operator (constants FUNC_[OPERATOR | JOIN | RESTRICT]) void setFunction(Function *func, unsigned func_type); //! \brief Defines the argument data type for operator (constants ARG_[LEFT | RIGHT]) void setArgumentType(PgSqlType arg_type, unsigned arg_id); //! \brief Defines the auxiliary operators (constants OPER_[COMMUTATOR | NEGATOR]) void setOperator(Operator *oper, unsigned op_type); //! \brief Defines that the operator accepts hash join void setHashes(bool value); //! \brief Defines that the operator accepts merge join void setMerges(bool value); //! \brief Returns the function used by the operator referencing it by its type Function *getFunction(unsigned func_type); //! \brief Returns the type of the passed argument id PgSqlType getArgumentType(unsigned arg_id); //! \brief Returns on of the auxiliary operators Operator *getOperator(unsigned op_type); //! \brief Returns whether the operator accepts hash join bool isHashes(void); //! \brief Returns whether the operator accepts merge join bool isMerges(void); //! \brief Validates the passed name using the naming rule for operators static bool isValidName(const QString &name); //! \brief Returns the SQL / XML definition for the operator virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getCodeDefinition(unsigned def_type) final; //! \brief Returns the operator signature virtual QString getSignature(bool format_name=true); }; #endif pgmodeler-0.9.2/libpgmodeler/src/operatorclass.cpp000066400000000000000000000117461360462764600223500ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operatorclass.h" OperatorClass::OperatorClass(void) { obj_type=ObjectType::OpClass; family=nullptr; is_default=false; attributes[Attributes::Family]=QString(); attributes[Attributes::Elements]=QString(); attributes[Attributes::IndexType]=QString(); attributes[Attributes::Type]=QString(); attributes[Attributes::Default]=QString(); } OperatorClass::~OperatorClass(void) { elements.clear(); } void OperatorClass::setDataType(PgSqlType data_type) { //A null datatype is not accepted by the operator class if(data_type==PgSqlType::Null) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->data_type != data_type); this->data_type=data_type; } void OperatorClass::setFamily(OperatorFamily *family) { setCodeInvalidated(this->family != family); this->family=family; } void OperatorClass::setIndexingType(IndexingType index_type) { setCodeInvalidated(indexing_type != index_type); this->indexing_type=index_type; } void OperatorClass::setDefault(bool value) { setCodeInvalidated(is_default != value); is_default=value; } void OperatorClass::setElementsAttribute(unsigned def_type) { QString str_elems; unsigned i, count; /* Concatenates the code definition from elements separating them by comma. */ count=elements.size(); for(i=0; i < count; i++) { str_elems+=elements[i].getCodeDefinition(def_type); if(def_type==SchemaParser::SqlDefinition && i < count-1) str_elems+=QString(",\n"); } attributes[Attributes::Elements]=str_elems; } void OperatorClass::addElement(OperatorClassElement elem) { //The operator class does not accept duplicate elements on the list //if(isElementExists(elem)) // throw Exception(ERR_INS_DUPLIC_ELEMENT,__PRETTY_FUNCTION__,__FILE__,__LINE__); elements.push_back(elem); } void OperatorClass::removeElement(unsigned elem_idx) { //Raises an error in case the element index is out of bound if(elem_idx >= elements.size()) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Removes the item from the elements list elements.erase(elements.begin() + elem_idx); setCodeInvalidated(true); } void OperatorClass::removeElements(void) { elements.clear(); setCodeInvalidated(true); } OperatorClassElement OperatorClass::getElement(unsigned elem_idx) { //Raises an error in case the element index is out of bound if(elem_idx >= elements.size()) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Returns the element on the specified index return(elements[elem_idx]); } bool OperatorClass::isElementExists(OperatorClassElement elem) { bool exists=false; vector::iterator itr, itr_end; OperatorClassElement elem_aux; itr=elements.begin(); itr_end=elements.end(); while(itr!=itr_end && !exists) { elem_aux=(*itr); exists=(elem_aux==elem); itr++; } return(exists); } unsigned OperatorClass::getElementCount(void) { return(elements.size()); } PgSqlType OperatorClass::getDataType(void) { return(data_type); } OperatorFamily *OperatorClass::getFamily(void) { return(family); } IndexingType OperatorClass::getIndexingType(void) { return(indexing_type); } bool OperatorClass::isDefault(void) { return(is_default); } QString OperatorClass::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString OperatorClass::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); setElementsAttribute(def_type); attributes[Attributes::IndexType]=(~indexing_type); attributes[Attributes::Default]=(is_default ? Attributes::True : QString()); if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Type]=(*data_type); else attributes[Attributes::Type]=data_type.getCodeDefinition(def_type); if(family) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Family]=family->getName(true); else attributes[Attributes::Family]=family->getSignature(); } attributes[Attributes::Signature]=getSignature(); return(BaseObject::getCodeDefinition(def_type, reduced_form)); } QString OperatorClass::getSignature(bool format) { return(BaseObject::getSignature(format) + QString(" USING %1").arg(~indexing_type)); } pgmodeler-0.9.2/libpgmodeler/src/operatorclass.h000066400000000000000000000066771360462764600220240ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class OperatorClass \brief This class is used to generate the XML/SQL code related to PostgreSQL operator classes. This type of object indicates to RDBMS how a data type can be used in a particular indexing method. \note Creation date: 08/07/2008 */ #ifndef OPERATOR_CLASS_H #define OPERATOR_CLASS_H #include "baseobject.h" #include "operatorclasselement.h" #include "operatorfamily.h" class OperatorClass: public BaseObject { private: //! \brief Data type witch the operator class acts on PgSqlType data_type; //! \brief Operator family that the operator class is part OperatorFamily *family; //! \brief Indexing type (method) adopted by the operator class IndexingType indexing_type; /*! \brief Indicates if the operator class is the default for the specified data type */ bool is_default; //! \brief Operator class attributes list vector elements; /*! \brief Formats the elements string used by the SchemaParser on the SQL/XML code definition for operator classes */ void setElementsAttribute(unsigned def_type); public: OperatorClass(void); ~OperatorClass(void); //! \brief Sets the data type that the operator class works on void setDataType(PgSqlType data_type); //! \brief Sets the operator family that the operator class is part void setFamily(OperatorFamily *family); //! \brief Set the indexing type used by the operator class void setIndexingType(IndexingType index_type); //! \brief Sets if the opertor class is default for the specified data type void setDefault(bool value); //! \brief Methods used to manipulate the elements FUNCTION, OPERATOR and STORAGE void addElement(OperatorClassElement elem); void removeElement(unsigned elem_idx); OperatorClassElement getElement(unsigned elem_idx); bool isElementExists(OperatorClassElement elem); void removeElements(void); //! \brief Methods used to obtain the class attributes PgSqlType getDataType(void); OperatorFamily *getFamily(void); IndexingType getIndexingType(void); bool isDefault(void); unsigned getElementCount(void); //! \brief Returns the SQL/XML code definition for operator class virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool format=true) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/operatorclasselement.cpp000066400000000000000000000134131360462764600237130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operatorclasselement.h" OperatorClassElement::OperatorClassElement(void) { element_type=OperatorElem; function=nullptr; _operator=nullptr; strategy_number=0; op_family=nullptr; } void OperatorClassElement::setFunction(Function *func, unsigned stg_number) { //Raises an exception case the function is not allocated if(!func) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error case the stratagy number is zero (invalid) else if(stg_number==0) throw Exception(ErrorCode::AsgInvalidSupportStrategyNumber,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Clear the attributes not related to the FUNCTION element type this->_operator=nullptr; this->op_family=nullptr; //Configure the attributes that belongs to the element type this->function=func; this->strategy_number=stg_number; this->element_type=FunctionElem; } void OperatorClassElement::setOperator(Operator *oper, unsigned stg_number) { //Raises an error in case the operator is not allocated if(!oper) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error case the stratagy number is zero (invalid) else if(stg_number==0) throw Exception(ErrorCode::AsgInvalidSupportStrategyNumber,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Clear the attributes not related to the OPERATOR element type this->function=nullptr; //Configure the attributes that belongs to the element type this->_operator=oper; this->strategy_number=stg_number; this->element_type=OperatorElem; } void OperatorClassElement::setOperatorFamily(OperatorFamily *op_family) { if(this->element_type==OperatorElem) { if(op_family && op_family->getIndexingType()!=IndexingType::Btree) throw Exception(ErrorCode::AsgInvalidOpFamilyOpClassElem,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->op_family=op_family; } } void OperatorClassElement::setStorage(PgSqlType storage) { //Clear the attributes not related to the STORAGE element type this->function=nullptr; this->_operator=nullptr; this->op_family=nullptr; this->strategy_number=0; //Configure the attributes that belongs to the element type this->storage=storage; this->element_type=StorageElem; } unsigned OperatorClassElement::getElementType(void) { return(element_type); } Function *OperatorClassElement::getFunction(void) { return(function); } Operator *OperatorClassElement::getOperator(void) { return(_operator); } OperatorFamily *OperatorClassElement::getOperatorFamily(void) { return(op_family); } PgSqlType OperatorClassElement::getStorage(void) { return(storage); } unsigned OperatorClassElement::getStrategyNumber(void) { return(strategy_number); } QString OperatorClassElement::getCodeDefinition(unsigned def_type) { SchemaParser schparser; attribs_map attributes; attributes[Attributes::Type]=QString(); attributes[Attributes::StrategyNum]=QString(); attributes[Attributes::Signature]=QString(); attributes[Attributes::Function]=QString(); attributes[Attributes::Operator]=QString(); attributes[Attributes::Storage]=QString(); attributes[Attributes::OpFamily]=QString(); attributes[Attributes::Definition]=QString(); if(element_type==FunctionElem && function && strategy_number > 0) { //FUNCTION support_number [ ( op_type [ , op_type ] ) ] funcname ( argument_type [, ...] ) attributes[Attributes::Function]=Attributes::True; attributes[Attributes::StrategyNum]=QString("%1").arg(strategy_number); if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Signature]=function->getSignature(); else attributes[Attributes::Definition]=function->getCodeDefinition(def_type,true); } else if(element_type==OperatorElem && _operator && strategy_number > 0) { //OPERATOR strategy_number operator_name [ ( op_type, op_type ) ] [ FOR SEARCH | FOR ORDER BY sort_family_name ] attributes[Attributes::Operator]=Attributes::True; attributes[Attributes::StrategyNum]=QString("%1").arg(strategy_number); if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Signature]=_operator->getSignature(); else attributes[Attributes::Definition]=_operator->getCodeDefinition(def_type,true); if(op_family) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::OpFamily]=op_family->getName(true); else attributes[Attributes::Definition]+=op_family->getCodeDefinition(def_type,true); } } else if(element_type==StorageElem && storage!=PgSqlType::Null) { //STORAGE storage_type attributes[Attributes::Storage]=Attributes::True; if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Type]=(*storage); else attributes[Attributes::Definition]=storage.getCodeDefinition(def_type); } return(schparser.getCodeDefinition(Attributes::Element,attributes, def_type)); } bool OperatorClassElement::operator == (OperatorClassElement &elem) { return(this->element_type == elem.element_type && this->storage == elem.storage && this->function == elem.function && this->_operator == elem._operator && this->strategy_number == elem.strategy_number && this->op_family == elem.op_family); } pgmodeler-0.9.2/libpgmodeler/src/operatorclasselement.h000066400000000000000000000071071360462764600233630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class OperatorClassElement \brief Implements the operations to manipulate operator class elements (storage, operator, function). \note Creation date: 08/07/2008 */ #ifndef OPERATOR_CLASS_ELEMENT_H #define OPERATOR_CLASS_ELEMENT_H #include "baseobject.h" #include "operator.h" #include "function.h" #include "operatorfamily.h" class OperatorClassElement { private: /*! \brief Type of the operator class element. This can have 3 possible values: 0 -> OPERATOR_ELEM 1 -> FUNCTION_ELEM 2 -> STORAGE_ELEM */ unsigned element_type; //! \brief Function used by the element (only for type FUNCTION_ELEM) Function *function; //! \brief Operator used by the element (only for type OPERATOR_ELEM) Operator *_operator; //! \brief Operator family used by the element (only for type OPERATOR_ELEM) OperatorFamily *op_family; /*! \brief PostgreSQL type used in the indexing method of operator class. (only for type STORAGE_ELEM) */ PgSqlType storage; /*! \brief Strategy number (or support number for functions). This attribute must have a value greater than 0 (only for OPERATOR_ELEM and FUNCTION_ELEM) */ unsigned strategy_number; public: //! \brief Constants used to reference the element types static constexpr unsigned OperatorElem=0, FunctionElem=1, StorageElem=2; OperatorClassElement(void); virtual ~OperatorClassElement(void){} //! \brief Defines the element as a function clause void setFunction(Function *func, unsigned stg_number); //! \brief Defines the element as an operator clause void setOperator(Operator *oper, unsigned stg_number); //! \brief Defines operator family used by the element (only for Operator elements) void setOperatorFamily(OperatorFamily *op_family); //! \brief Defines the element as a storage clause void setStorage(PgSqlType storage); //! \brief Returns the element type unsigned getElementType(void); /*! \brief Returns the current assigned function. This method returns nullptr when the element is not an FUNCTION_ELEM */ Function *getFunction(void); /*! \brief Returns the current assigned operator. This method returns nullptr when the element is not an OPERATOR_ELEM */ Operator *getOperator(void); /*! \brief Returns the operator family used by element. This method returns nullptr when the element is not an OPERATOR_ELEM */ OperatorFamily *getOperatorFamily(void); //! \brief Storage type of the element PgSqlType getStorage(void); //! \brief Returns the strategy (support) number of the element unsigned getStrategyNumber(void); //! \brief Returns the SQL / XML code definition for the element virtual QString getCodeDefinition(unsigned def_type) final; //! \brief Operator to compare two elements, returns true when all atributes has the same configuration bool operator == (OperatorClassElement &elem); }; #endif pgmodeler-0.9.2/libpgmodeler/src/operatorfamily.cpp000066400000000000000000000032501360462764600225130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operatorfamily.h" OperatorFamily::OperatorFamily(void) { obj_type=ObjectType::OpFamily; attributes[Attributes::IndexType]=QString(); } void OperatorFamily::setIndexingType(IndexingType idx_type) { setCodeInvalidated(indexing_type != idx_type); indexing_type=idx_type; } IndexingType OperatorFamily::getIndexingType(void) { return(indexing_type); } QString OperatorFamily::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString OperatorFamily::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Signature]=getSignature(); attributes[Attributes::IndexType]=(~indexing_type); return(BaseObject::getCodeDefinition(def_type,reduced_form)); } QString OperatorFamily::getSignature(bool format) { return(BaseObject::getSignature(format) + QString(" USING %1").arg(~indexing_type)); } pgmodeler-0.9.2/libpgmodeler/src/operatorfamily.h000066400000000000000000000031641360462764600221640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class OperatorFamily \brief Implements the operations to manipulate operator family on the database. \note Creation date: 08/07/2008 */ #ifndef OPERATOR_FAMILY_H #define OPERATOR_FAMILY_H #include "baseobject.h" class OperatorFamily: public BaseObject { private: //! \brief Indexing type used by the operator family IndexingType indexing_type; public: OperatorFamily(void); //! \brief Sets the indexing type of the operator family void setIndexingType(IndexingType idx_type); //! \brief Returns the indexing type of the operator family IndexingType getIndexingType(void); //! \brief Returns the SQL / XML code definition for the operator family virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool format=true) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/parameter.cpp000066400000000000000000000060621360462764600214420ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "parameter.h" Parameter::Parameter(void) { obj_type=ObjectType::Parameter; is_in=is_out=is_variadic=false; } Parameter::Parameter(const QString &name, PgSqlType type, bool in, bool out, bool variadic) : Parameter() { setName(name); setType(type); setIn(in); setOut(out); setVariadic(variadic); } void Parameter::setType(PgSqlType type) { if(!type.isArrayType() && !type.isPolymorphicType() && is_variadic) throw Exception(ErrorCode::InvUsageVariadicParamMode ,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->type != type); this->type=type; } void Parameter::setIn(bool value) { setCodeInvalidated(is_in != value); is_in=value; is_variadic=false; } void Parameter::setOut(bool value) { setCodeInvalidated(is_out != value); is_out=value; is_variadic=false; } void Parameter::setVariadic(bool value) { if(value && !type.isArrayType() && !type.isPolymorphicType()) throw Exception(ErrorCode::InvUsageVariadicParamMode ,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(is_variadic != value); is_variadic=value; if(value) is_in=is_out=false; } bool Parameter::isIn(void) { return(is_in); } bool Parameter::isOut(void) { return(is_out); } bool Parameter::isVariadic(void) { return(is_variadic); } void Parameter::operator = (const Parameter ¶m) { this->obj_name=param.obj_name; this->type=param.type; this->default_value=param.default_value; this->is_in=param.is_in; this->is_out=param.is_out; this->is_variadic=param.is_variadic; setCodeInvalidated(true); } QString Parameter::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); return(this->getCodeDefinition(def_type, false)); } QString Parameter::getCodeDefinition(unsigned def_type, bool reduced_form) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Name]=BaseObject::formatName(obj_name); else attributes[Attributes::Name]=obj_name; attributes[Attributes::ParamIn]=(is_in ? Attributes::True : QString()); attributes[Attributes::ParamOut]=(is_out ? Attributes::True : QString()); attributes[Attributes::ParamVariadic]=(is_variadic ? Attributes::True : QString()); attributes[Attributes::DefaultValue]=default_value; attributes[Attributes::Type]=type.getCodeDefinition(def_type); return(BaseObject::getCodeDefinition(def_type, reduced_form)); } pgmodeler-0.9.2/libpgmodeler/src/parameter.h000066400000000000000000000032261360462764600211060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate stored procedures (function) parameters. */ #ifndef PARAMETER_H #define PARAMETER_H #include "column.h" class Parameter: public Column { private: /*! \brief This attributes indicates whether the parameter is in, out or both (IN, OUT, INOUT, VARIADIC) */ bool is_in, is_out, is_variadic; public: Parameter(void); Parameter(const QString &name, PgSqlType type, bool in = false, bool out = false, bool variadic = false); void setType(PgSqlType type); void setIn(bool value); void setOut(bool value); void setVariadic(bool value); bool isIn(void); bool isOut(void); bool isVariadic(void); //! \brief Returns the SQL / XML code definition for the parameter virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; void operator = (const Parameter ¶m); }; #endif pgmodeler-0.9.2/libpgmodeler/src/partitionkey.cpp000066400000000000000000000027301360462764600222020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "partitionkey.h" PartitionKey::PartitionKey(void) { collation = nullptr; } void PartitionKey::setCollation(Collation *collation) { this->collation=collation; } Collation *PartitionKey::getCollation(void) { return(collation); } QString PartitionKey::getCodeDefinition(unsigned def_type) { attribs_map attribs; schparser.setPgSQLVersion(BaseObject::getPgSQLVersion()); attribs[Attributes::Collation]=QString(); configureAttributes(attribs, def_type); if(collation) { if(def_type==SchemaParser::SqlDefinition) attribs[Attributes::Collation]=collation->getName(true); else attribs[Attributes::Collation]=collation->getCodeDefinition(def_type, true); } return(schparser.getCodeDefinition(Attributes::PartitionKey, attribs, def_type)); } pgmodeler-0.9.2/libpgmodeler/src/partitionkey.h000066400000000000000000000025621360462764600216520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate partition key elements. */ #ifndef PARTITION_KEY_H #define PARTITION_KEY_H #include "element.h" class PartitionKey: public Element { private: //! \brief Collation referenced by the element Collation *collation; public: PartitionKey(void); //! \brief Defines the collation referenced by the element void setCollation(Collation *collation); //! \brief Get the collation referenced by the element Collation *getCollation(void); //! \brief Returns the SQL / XML code definition for the partition key virtual QString getCodeDefinition(unsigned def_type) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/permission.cpp000066400000000000000000000357621360462764600216630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "permission.h" const QString Permission::priv_codes=QString("rawdDxtCcTXU"); Permission::Permission(BaseObject *obj) { unsigned priv_id; //Initializes all the privileges as unchecked for(priv_id=PrivSelect; priv_id<=PrivUsage; priv_id++) privileges[priv_id]=grant_option[priv_id]=false; //Raises an error if the object associated to the permission is no allocated if(!obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the object type to be associated to the permission is invalid according to the rule (see class definition) */ if(!acceptsPermission(obj->getObjectType())) throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->object=obj; this->obj_type=ObjectType::Permission; revoke=cascade=false; attributes[Attributes::Object]=QString(); attributes[Attributes::Type]=QString(); attributes[Attributes::Parent]=QString(); attributes[Attributes::GrantOp]=QString(); attributes[Attributes::Roles]=QString(); attributes[Attributes::Privileges]=QString(); attributes[Attributes::Cascade]=QString(); attributes[Attributes::PrivilegesGop]=QString(); } bool Permission::acceptsPermission(ObjectType obj_type, int privilege) { bool result=false; unsigned priv_id=static_cast(privilege); result=(obj_type==ObjectType::Table || obj_type==ObjectType::Column || obj_type==ObjectType::View || obj_type==ObjectType::Sequence || obj_type==ObjectType::Database || obj_type==ObjectType::Function || obj_type==ObjectType::Aggregate || obj_type==ObjectType::Language || obj_type==ObjectType::Schema || obj_type==ObjectType::Tablespace || obj_type==ObjectType::Domain || obj_type==ObjectType::Type || obj_type==ObjectType::ForeignDataWrapper || obj_type==ObjectType::ForeignServer || obj_type==ObjectType::ForeignTable); //Validating privilege if(result && priv_id <= PrivUsage) { /* Some privileges are valid only for certain types of objects. If the user try to assign a privilege P for an object that does not accept this privilege the same is ignored. The schema below shows the privileges for each object: Table: SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER Column: SELECT | INSERT | UPDATE | REFERENCES Sequence: USAGE | SELECT | UPDATE Database: CREATE | CONNECT | TEMPORARY | TEMP Function: EXECUTE Aggregate: EXECUTE Linguage: USAGE Schema: CREATE | USAGE Tablespace: CREATE View: SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER Foreign Data Wrapper: USAGE Foreign Server: USAGE */ result=result && (((obj_type==ObjectType::Table || obj_type==ObjectType::View || obj_type==ObjectType::ForeignTable) && (priv_id==PrivSelect || priv_id==PrivInsert || priv_id==PrivUpdate || priv_id==PrivDelete || priv_id==PrivReferences || priv_id==PrivTrigger)) || ((obj_type==ObjectType::Table || obj_type==ObjectType::View || obj_type==ObjectType::ForeignTable) && priv_id==PrivTruncate) || (obj_type==ObjectType::Column && (priv_id==PrivSelect ||priv_id==PrivInsert || priv_id==PrivUpdate || priv_id==PrivReferences)) || (obj_type==ObjectType::Sequence && (priv_id==PrivUsage || priv_id==PrivSelect || priv_id==PrivUpdate)) || (obj_type==ObjectType::Database && (priv_id==PrivCreate || priv_id==PrivConnect || priv_id==PrivTemporary)) || ((obj_type==ObjectType::Function || obj_type==ObjectType::Aggregate) && priv_id==PrivExecute) || ((obj_type==ObjectType::Language || obj_type==ObjectType::Type || obj_type==ObjectType::Domain) && priv_id==PrivUsage) || (obj_type==ObjectType::Schema && (priv_id==PrivUsage || priv_id==PrivCreate)) || (obj_type==ObjectType::Tablespace && priv_id==PrivCreate) || ((obj_type==ObjectType::ForeignDataWrapper || obj_type==ObjectType::ForeignServer) && priv_id==PrivUsage)); } return(result); } bool Permission::isRoleExists(Role *role) { if(!role) return(false); return(std::find(roles.begin(), roles.end(), role) != roles.end()); } void Permission::addRole(Role *role) { //Raises an error if the role is not allocated if(!role) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the role already exists in the permission if(isRoleExists(role)) throw Exception(ErrorCode::InsDuplicatedRolePermission,__PRETTY_FUNCTION__,__FILE__,__LINE__); roles.push_back(role); setCodeInvalidated(true); //Updates the permission Id generatePermissionId(); } void Permission::setPrivilege(unsigned priv_id, bool value, bool grant_op) { //Caso o tipo de privilégio sejá inválido dispara uma exceção if(priv_id > PrivUsage) throw Exception(ErrorCode::RefInvalidPrivilegeType,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!acceptsPermission(object->getObjectType(), priv_id)) //Raises an error if the privilege is invalid according to the object type throw Exception(ErrorCode::AsgInvalidPrivilegeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated((privileges[priv_id] != value) || grant_option[priv_id] != grant_op); privileges[priv_id]=value; this->grant_option[priv_id]=grant_op; generatePermissionId(); } void Permission::setRevoke(bool value) { setCodeInvalidated(revoke != value); revoke=value; } void Permission::setCascade(bool value) { setCodeInvalidated(revoke && (cascade != value)); cascade=(revoke && value); } bool Permission::isRevoke(void) { return(revoke); } bool Permission::isCascade(void) { return(cascade); } bool Permission::isSimilarTo(Permission *perm) { if(!perm) return(false); QStringList rol_names, fmt_rol_names; vector*> vect_roles={ &this->roles, &perm->roles }; BaseObject *object=this->getObject(), *aux_object=perm->getObject(); //Generating a list with role names of both permissions for(auto &roles : vect_roles) { for(auto &role : *roles) rol_names.append(role->getName()); rol_names.sort(); fmt_rol_names.append(rol_names.join(',')); rol_names.clear(); } return(((object==aux_object) || (object && aux_object && object->getSignature()==aux_object->getSignature())) && this->getPermissionString()==perm->getPermissionString() && this->revoke==perm->revoke && fmt_rol_names[0]==fmt_rol_names[1]); } void Permission::removeRole(unsigned role_idx) { if(role_idx > roles.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); roles.erase(roles.begin() + role_idx); generatePermissionId(); setCodeInvalidated(true); } void Permission::removeRoles(void) { roles.clear(); generatePermissionId(); setCodeInvalidated(true); } Role *Permission::getRole(unsigned role_idx) { if(role_idx > roles.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(roles[role_idx]); } vector Permission::getRoles(void) { return(roles); } unsigned Permission::getRoleCount(void) { return(roles.size()); } BaseObject *Permission::getObject(void) { return(object); } bool Permission::getPrivilege(unsigned priv_id) { //Raises an error if the privilege is invalid if(priv_id > PrivUsage) throw Exception(ErrorCode::RefInvalidPrivilegeType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(privileges[priv_id]); } bool Permission::getGrantOption(unsigned priv_id) { //Raises an error if the privilege is invalid if(priv_id > PrivUsage) throw Exception(ErrorCode::RefInvalidPrivilegeType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(grant_option[priv_id]); } QString Permission::getPermissionString(void) { QString str_priv; unsigned i; /* Schema to build the privilege string: rolename=xxxx -- privileges granted to a role =xxxx -- privileges granted to PUBLIC r -- SELECT ("read") a -- INSERT ("append") w -- UPDATE ("write") d -- DELETE D -- TRUNCATE x -- REFERENCES t -- TRIGGER C -- CREATE c -- CONNECT T -- TEMPORARY X -- EXECUTE U -- USAGE arwdDxt -- ALL PRIVILEGES (for tables, varies for other objects) * -- grant option for preceding privilege /yyyy -- role that granted this privilege */ for(i=0; i < 12; i++) { if(privileges[i]) str_priv.append(priv_codes[i]); if(grant_option[i]) str_priv.append(QChar('*')); } return(str_priv); } QString Permission::parsePermissionString(QString perm_str, vector &privs, vector &gop_privs) { QString role; QRegExp regexp(QString("(.)*(\\=)([%1*])+((\\/)(.)+)?").arg(priv_codes)); privs.clear(); gop_privs.clear(); //Checking if the permission string is valid if(!perm_str.isEmpty() && regexp.exactMatch(perm_str)) { QStringList list=perm_str.remove(perm_str.indexOf('/'), perm_str.size()).split('='); QChar chr; QString codes=list[1]; int priv=-1, i=0; bool gop=false; role=list[0]; while(i < codes.size()) { chr=codes[i]; //Get the privilege code if(chr!='*') priv=priv_codes.indexOf(chr); //Checking if the next char is the GRANT OPTION descriptor if(((i+1) < codes.size()) && (codes[i+1]=='*')) { i+=2; gop=true; } else i++; if(priv >= 0) { /* If the grant option flag is checked insert the privilege on the grant option list instead of ordinary privilete list */ if(gop) gop_privs.push_back(priv); else privs.push_back(priv); priv=-1; gop=false; } } } return(role); } void Permission::generatePermissionId(void) { vector::iterator itr, itr_end; vector addr_vect; Role *role=nullptr; QString str_aux, addr; unsigned i, count; QTextStream stream(&addr); QCryptographicHash hash(QCryptographicHash::Md5); //Stores the permission address on a string stream << reinterpret_cast(this); str_aux=addr.mid(2); addr.clear(); //Generates the id only when there is associated roles to the permission if(roles.size() > 0) { itr=roles.begin(); itr_end=roles.end(); while(itr!=itr_end) { role=(*itr); //Convertes the role address to string and use it as the id for the permission stream << reinterpret_cast(role); addr_vect.push_back(addr.mid(2)); itr++; } sort(addr_vect.begin(), addr_vect.end()); count=addr_vect.size(); for(i=0; i < count; i++) { str_aux+=QString("%1").arg(addr_vect[i]); if(i < count-1) str_aux+='.'; } } /* If no role is associated with permissions (public) generates an identifier with zeros indicating that permission is not linked directly to any role on the model */ else str_aux+=QString("000000"); //Generates an unique name for the permission through md5 hash hash.addData(QByteArray(str_aux.toStdString().c_str())); str_aux=hash.result().toHex(); this->obj_name=(!revoke ? QString("grant_") : QString("revoke_")) + str_aux.mid(0,10); } QString Permission::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); unsigned i, count; ObjectType obj_type; QString priv_vect[12]={ Attributes::SelectPriv, Attributes::InsertPriv, Attributes::UpdatePriv, Attributes::DeletePriv, Attributes::TruncatePriv, Attributes::ReferencesPriv, Attributes::TriggerPriv, Attributes::CreatePriv, Attributes::ConnectPriv, Attributes::TemporaryPriv, Attributes::ExecutPriv, Attributes::UsagePriv }; obj_type=object->getObjectType(); attributes[Attributes::Revoke]=(revoke ? Attributes::True : QString()); attributes[Attributes::Cascade]=(cascade ? Attributes::True : QString()); if(def_type==SchemaParser::SqlDefinition) { if(obj_type == ObjectType::View || obj_type == ObjectType::ForeignTable) //Views, Tables and foreign tables use the same keyword when setting permission (TABLE) attributes[Attributes::Type] = BaseObject::getSQLName(ObjectType::Table); else if(obj_type == ObjectType::ForeignServer) attributes[Attributes::Type] = QString("FOREIGN ") + object->getSQLName(); else attributes[Attributes::Type] = BaseObject::getSQLName(obj_type); } else attributes[Attributes::Type]=BaseObject::getSchemaName(obj_type); if(obj_type==ObjectType::Column) { attributes[Attributes::Object]=object->getName(true); attributes[Attributes::Parent]=dynamic_cast(object)->getParentTable()->getName(true); } else attributes[Attributes::Object]=object->getSignature(); if(def_type==SchemaParser::XmlDefinition) { for(i=0; i < 12; i++) { if(privileges[i] && grant_option[i]) attributes[priv_vect[i]]=Attributes::GrantOp; else if(privileges[i]) attributes[priv_vect[i]]=Attributes::True; else attributes[priv_vect[i]]=QString(); } } else { QStringList priv_list, gop_priv_list; for(i=0; i < 12; i++) { if(privileges[i] && !grant_option[i]) priv_list.push_back(object->getObjectType() == ObjectType::Column ? QString("%1(%2)").arg(priv_vect[i].toUpper()).arg(object->getName(true)) : priv_vect[i].toUpper()); else if(grant_option[i]) gop_priv_list.push_back(object->getObjectType() == ObjectType::Column ? QString("%1(%2)").arg(priv_vect[i].toUpper()).arg(object->getName(true)) : priv_vect[i].toUpper()); } attributes[Attributes::Privileges] = priv_list.join(QChar(',')); attributes[Attributes::PrivilegesGop] = gop_priv_list.join(QChar(',')); } count=roles.size(); for(i=0; i < count; i++) attributes[Attributes::Roles]+=roles[i]->getName(true) + QString(","); attributes[Attributes::Roles].remove(attributes[Attributes::Roles].size()-1,1); return(BaseObject::__getCodeDefinition(def_type)); } QString Permission::getSignature(bool format) { QStringList rol_names, words; QString signature; for(Role *role : roles) rol_names.push_back(role->getName(format)); rol_names.sort(); signature=QString("=") + getPermissionString(); if(roles.empty()) signature=QString("PUBLIC") + signature; else signature=rol_names.join(',') + signature; words=this->obj_name.split("_"); signature=words[0] + QChar(':') + signature + QString(" [id:%1]").arg(words[1]); return(signature); } QString Permission::getDropDefinition(bool cascade) { try { QString def; this->setRevoke(!revoke); this->setCascade(cascade); def=this->getCodeDefinition(SchemaParser::SqlDefinition); this->setRevoke(revoke); this->setCascade(this->cascade); return(def); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/permission.h000066400000000000000000000124001360462764600213100ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Permission \brief Implements the operations to manipulate object permissions. \note Creation date: 16/09/2010 */ #ifndef PERMISSION_H #define PERMISSION_H #include "baseobject.h" #include "function.h" #include "role.h" #include #include #include #include class Permission: public BaseObject { /*! \brief Permissions on PostgreSQL are only applied to the following object type: * table * column * view * sequence * database * foreign-data wrapper * foreign server * large objects (not implemented) * function * aggregate * linguage * schema * tablespace */ private: static const QString priv_codes; //! \brief Object which the permission is applied BaseObject *object; /*! \brief Roles that has permissions over the object. This vector can be empty indicating that all roles on the cluster has permission over the object. */ vector roles; //! \brief Privileges set applied to the object (Accessed via constants PRIV_???) bool privileges[13], //! \brief Indicates if the permission treats a REVOKE command. revoke, //! \brief Indicates if the revoke is applied in a cascade way. cascade; /*! \brief Indicates whether a privilege with given index can be assigned to other roles over the same object (WITH GRANT OPTION). This attribute is not applicable when there is no specified role (PUBLIC). This attribute is ignored when there is no defined role as holder of the privilege. */ bool grant_option[13]; /*! \brief Generates a unique identifier for permission using the attribute 'name' of base class BaseObject. This is only used to avoid duplicate permissions in the model */ void generatePermissionId(void); public: //! \brief Constants used to reference the privileges static constexpr unsigned PrivSelect=0, PrivInsert=1, PrivUpdate=2, PrivDelete=3, PrivTruncate=4, PrivReferences=5, PrivTrigger=6, PrivCreate=7, PrivConnect=8, PrivTemporary=9, PrivExecute=10, PrivUsage=11; /*! \brief In the constructor is required to specify which object will receive the permissions this can not be changed after the object instance of the class is created. */ Permission(BaseObject *obj); //! \brief Adds a role that will have privileges over the object void addRole(Role *role); //! \brief Sets the state of one permission's privilege (Accessed via constants PRIV_???) void setPrivilege(unsigned priv_id, bool value, bool grant_op); void setRevoke(bool value); void setCascade(bool value); //! \brief Remove a role using its index void removeRole(unsigned role_idx); //! \brief Remove all roles from the permission void removeRoles(void); //! \brief Gets the role count associated to the permission unsigned getRoleCount(void); //! \brief Gets one role from permission using its index Role *getRole(unsigned role_idx); //! \brief Returns all the roles that is used by the permission vector getRoles(void); //! \brief Gets the object that is subject to the privileges BaseObject *getObject(void); //! \brief Gets the actual state of the GRANT OPTION for the given privilege bool getGrantOption(unsigned priv_id); //! \brief Gets the current state for the given privilege bool getPrivilege(unsigned priv_id); /*! \brief Returns a string containing all the privileges configured as the internal format of permissions as documented on PostgreSQL GRANT command */ QString getPermissionString(void); /*! \brief Parses the permission string (e.g. postgres=arwdDxt/postgres) and returns the role name which owns the permission. The parameter vectors stores the ordinary privileges as well the GRANT OPTION privileges */ static QString parsePermissionString(QString perm_str, vector &privs, vector &gop_privs); //! \brief Indicates whether the role is present on the permission bool isRoleExists(Role *role); bool isRevoke(void); bool isCascade(void); //! \brief Returns the the specified permission is semantically the same as this permission bool isSimilarTo(Permission *perm); //! \brief Returns if the passed object type accepts permission static bool acceptsPermission(ObjectType obj_type, int privilege=-1); //! \brief Returns the SQL / XML definition for the permission virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool format=false) final; virtual QString getDropDefinition(bool cascade) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/pgmodelerns.cpp000066400000000000000000000210511360462764600217740ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pgmodelerns.h" #include "databasemodel.h" #include #include namespace PgModelerNs { template void copyObject(BaseObject **psrc_obj, Class *copy_obj) { Class *orig_obj=nullptr; //Gets the objects stored in the pointer orig_obj=dynamic_cast(*psrc_obj); //Raises an error if the copy object is not allocated if(!copy_obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Allocates the source object if its not allocated if(!orig_obj) { orig_obj=new Class; (*psrc_obj)=orig_obj; } //Makes the copy between the objects (*orig_obj)=(*copy_obj); } void copyObject(BaseObject **psrc_obj, BaseObject *copy_obj, ObjectType obj_type) { switch(obj_type) { case ObjectType::Relationship: Relationship *rel1; rel1=new Relationship(dynamic_cast(copy_obj)); if(!(*psrc_obj)) (*psrc_obj)=rel1; else (*(dynamic_cast(*psrc_obj)))=(*rel1); break; case ObjectType::BaseRelationship: BaseRelationship *rel; rel=new BaseRelationship(dynamic_cast(copy_obj)); if(!(*psrc_obj)) (*psrc_obj)=rel; else (*(dynamic_cast(*psrc_obj)))=(*rel); break; case ObjectType::Column: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Constraint: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Trigger: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Rule: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Index: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Policy: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Table: copyObject(psrc_obj, dynamic_cast
(copy_obj)); break; case ObjectType::Textbox: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::OpClass: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Conversion: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Cast: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Domain: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Tablespace: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Schema: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::OpFamily: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Function: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Aggregate: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Language: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Operator: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Role: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Sequence: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Type: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::View: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Collation: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Extension: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::Tag: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::EventTrigger: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::GenericSql: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::ForeignDataWrapper: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::ForeignServer: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::UserMapping: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; case ObjectType::ForeignTable: copyObject(psrc_obj, dynamic_cast(copy_obj)); break; default: throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } bool isReservedKeyword(const QString &word) { static QHash keywords={ {QChar('A'), {QString("ALL"), QString("ANALYSE"), QString("ANALYZE"), QString("AND"), QString("ANY"), QString("AS"), QString("ASC"), QString("AUTHORIZATION")}}, {QChar('B'), {QString("BETWEEN"), QString("BIGINT"), QString("BINARY"), QString("BIT"), QString("BOOLEAN"), QString("BOTH")}}, {QChar('C'), {QString("CASE"), QString("CAST"), QString("CHAR"), QString("CHARACTER"), QString("CHECK"), QString("COALESCE"), QString("COLLATE"), QString("COLUMN"), QString("CONSTRAINT"), QString("CONVERT"), QString("CREATE"), QString("CROSS"), QString("CURRENT_DATE"), QString("CURRENT_TIME"), QString("CURRENT_TIMESTAMP"), QString("CURRENT_USER")}}, {QChar('D'), {QString("DEC"), QString("DECIMAL"), QString("DEFAULT"), QString("DEFERRABLE"), QString("DESC"), QString("DISTINCT"), QString("DO")}}, {QChar('E'), {QString("ELSE"), QString("END"), QString("EXCEPT"), QString("EXISTS"), QString("EXTRACT")}}, {QChar('F'), {QString("FALSE"), QString("FLOAT"), QString("FOR"), QString("FOREIGN"), QString("FREEZE"), QString("FROM"), QString("FULL")}}, {QChar('G'), {QString("GRANT"), QString("GROUP")}}, {QChar('H'), {QString("HAVING")}}, {QChar('I'), {QString("ILIKE"), QString("IN"), QString("INITIALLY"), QString("INNER"), QString("INT"), QString("INTEGER"), QString("INTERSECT"), QString("INTERVAL"), QString("INTO"), QString("IS"), QString("ISNULL")}}, {QChar('J'), {QString("JOIN")}}, {QChar('L'), {QString("LEADING"), QString("LEFT"), QString("LIKE"), QString("LIMIT"), QString("LOCALTIME"), QString("LOCALTIMESTAMP")}}, {QChar('N'), {QString("NATURAL"), QString("NCHAR"), QString("NEW"), QString("NOCREATEDB"), QString("NOCREATEUSER"), QString("NONE"), QString("NOT"), QString("NOTHING"), QString("NOTIFY"), QString("NOTNULL"), QString("NULL"), QString("NULLIF"), QString("NUMERIC")}}, {QChar('O'), {QString("OFF"), QString("OFFSET"), QString("OLD"), QString("ON"), QString("ONLY"), QString("OR"), QString("ORDER"), QString("OUTER"), QString("OVERLAPS"), QString("OVERLAY")}}, {QChar('P'), {QString("PLACING"), QString("POSITION"), QString("PRIMARY")}}, {QChar('R'), {QString("REAL"), QString("REFERENCES"), QString("RIGHT"), QString("ROW")}}, {QChar('S'), {QString("SELECT"), QString("SESSION_USER"), QString("SETOF"), QString("SIMILAR"), QString("SMALLINT"), QString("SOME"), QString("SUBSTRING")}}, {QChar('T'), {QString("TABLE"), QString("THEN"), QString("TIME"), QString("TIMESTAMP"), QString("TO"), QString("TRAILING"), QString("TREAT"), QString("TRIM"), QString("TRUE")}}, {QChar('U'), {QString("UNION"), QString("UNIQUE"), QString("USER"), QString("USING")}}, {QChar('V'), {QString("VARCHAR"), QString("VERBOSE")}}, {QChar('W'), {QString("WHEN"), QString("WHERE")}} }; if(word.isEmpty()) return(false); else { QChar chr=word.at(0).toUpper(); if(!keywords.contains(chr)) return(false); else return(keywords[chr].contains(word.toUpper())); } } } pgmodeler-0.9.2/libpgmodeler/src/pgmodelerns.h000066400000000000000000000106441360462764600214470ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \namespace PgModelerNS \brief This namespace is used to organize all functions or constants used in the libpgmodeler package. */ #ifndef PGMODELER_NS_H #define PGMODELER_NS_H #include "baseobject.h" namespace PgModelerNs { //! \brief Default char used as unescaped value start delimiter static const QChar UnescValueStart='/'; //! \brief Default char used as unescaped value end delimiter static const QChar UnescValueEnd='/'; /*! \brief Template function that makes a copy from 'copy_obj' to 'psrc_obj' doing the cast to the correct object type. If the source object (psrc_obj) is not allocated the function allocates the attributes before copying. Both objects must be the same type if both are allocated. -- Brainfuck syntax style! :p -- */ template extern void copyObject(BaseObject **psrc_obj, Class *copy_obj); /*! \brief This functions is a second way to make a copy between two objects. It simply calls the template function above. */ extern void copyObject(BaseObject **psrc_obj, BaseObject *copy_obj, ObjectType obj_type); //! \brief Returns true if the specified word is a PostgreSQL reserved word. extern bool isReservedKeyword(const QString &word); /*! \brief Generates a unique name based upon the specified object and the list of objects of the same type. User can specify a suffix for the generated name as well if the comparison inside the method must be done with formated names. The last optinal parameter indicates that the suffix should be used only in case of conflicts */ template QString generateUniqueName(BaseObject *obj, vector &obj_vector, bool fmt_name=false, const QString &suffix=QString(), bool use_suf_on_conflict=false) { unsigned counter=0; int len=0; QString aux_name, obj_name, id; Class *aux_obj=nullptr; typename std::vector::iterator itr=obj_vector.begin(), itr_end=obj_vector.end(); QChar oper_uniq_chr='?'; //Char appended at end of operator names in order to resolve conflicts ObjectType obj_type; if(!obj) return(""); //Cast objects will not have the name changed since their name are automatically generated else if(obj->getObjectType()==ObjectType::Cast || obj->getObjectType()==ObjectType::Database) return(obj->getName()); obj_name=obj->getName(fmt_name); obj_type=obj->getObjectType(); if(!use_suf_on_conflict && obj_type!=ObjectType::Operator) obj_name += suffix; counter = (use_suf_on_conflict && obj_type!= ObjectType::Operator? 0 : 1); id=QString::number(obj->getObjectId()); len=obj_name.size() + id.size(); //If the name length exceeds the maximum size if(len > BaseObject::ObjectNameMaxLength) { //Remove the last chars in the count of 3 + length of id obj_name.chop(id.size() + 3); //Append the id of the object on its name (this is not applied to operators) if(obj_type!=ObjectType::Operator) obj_name+=QString("_") + id; } aux_name=obj_name; //Check if the object's new name conflicts with some of the objects within the list while(itr!=itr_end) { aux_obj=(*itr); itr++; //If a conflicting object is found if(/*aux_obj!=obj &&*/ aux_obj->getName(fmt_name)==aux_name) { //For operators is appended a '?' on the name if(obj_type==ObjectType::Operator) aux_name=QString("%1%2").arg(obj_name).arg(QString("").leftJustified(counter++, oper_uniq_chr)); else { aux_name=QString("%1%2%3") .arg(obj_name) .arg(use_suf_on_conflict ? suffix : QString()) .arg(use_suf_on_conflict && counter == 0 ? QString() : QString::number(counter)); counter++; } itr=obj_vector.begin(); } } if(aux_name!=obj_name) obj_name=aux_name; return(obj_name); } } #endif pgmodeler-0.9.2/libpgmodeler/src/pgsqltypes.cpp000066400000000000000000001435561360462764600217070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pgsqltypes.h" /******************** * CLASS: BaseType * ********************/ QString BaseType::type_list[BaseType::TypesCount]= { /* Tipo vazio, quando se instância a classe TipoBase ao usar o operador ~ este será o único tipo retornado */ //offsets 0 "", //Types used by the class ActionType //offsets 1 to 5 "NO ACTION", "RESTRICT", "CASCADE", "SET NULL", "SET DEFAULT", //Types used by the class ConstraintType //offsets 6 to 10 "PRIMARY KEY", "FOREIGN KEY", "CHECK", "UNIQUE", "EXCLUDE", //Types used by the class EventType //offsets 11 to 15 "ON SELECT", "ON INSERT", "ON DELETE", "ON UPDATE", "ON TRUNCATE", //Types used by the class ExecutionType //offsets 16 to 17 "ALSO", "INSTEAD", //Types used by the class FunctionType //offsets 18 to 20 "VOLATILE", "STABLE", "IMMUTABLE", //Types used by the class IndexingType //offsets 21 to 26 "btree", "gist", "hash", "gin", "spgist", "brin", //Types used by the class PgSQLType //offsets 27 to 88 //Note: the type char is different from "char" (with quotes) //Reference: http://www.postgresql.org/docs/9.2/static/datatype-character.html "smallint", "integer", "bigint", "decimal", "numeric", "real", "double precision", "float", "serial", "bigserial", "money", "character varying", "varchar", "character", "char", "\"char\"", "text", "bytea", "timestamp", "date", "time","timetz","timestamptz", "interval", "boolean", "bool", "point", "line", "lseg", "box", "path", "polygon", "circle", "cidr", "inet", "macaddr", "macaddr8", "bit", "bit varying", "varbit", "uuid", "xml", "json", "jsonb", "smallserial", "int2vector", "int2", "int4", "int8", "float4", "float8", "bpchar", "name", "abstime", "aclitem", "gtsvector", "refcursor", "reltime", "tinterval", "tsquery", "tsvector", "txid_snapshot", //Spatial type specifics for the PostGiS extension //offsets 89 to 102 "box2d","box3d","geometry", "geometry_dump","geography", "geomval", "addbandarg", "rastbandarg", "raster", "reclassarg", "unionarg", "\"TopoGeometry\"", "getfaceedges_returntype", "validatetopology_returntype", //Range-types //offsets 103 to 108 "int4range", "int8range", "numrange", "tsrange","tstzrange","daterange", //Object Identification type (OID) //offsets 109 to 123 "oid", "regproc", "regprocedure", "regoper", "regoperator", "regclass", "regrole", "regnamespace", "regtype", "regconfig", "regdictionary", "xid", "cid", "tid", "oidvector", //Pseudo-types //offsets 124 to 138 "\"any\"","anyarray","anyelement","anyenum", "anynonarray", "anyrange", "cstring","internal","language_handler", "record","trigger","void","opaque", "fdw_handler", "event_trigger", //Interval types //offsets 139 to 151 "YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND","YEAR TO MONTH", "DAY TO HOUR","DAY TO MINUTE","DAY TO SECOND", "HOUR TO MINUTE","HOUR TO SECOND","MINUTE TO SECOND", //Types used by the class BehaviorType //offsets 152 to 154 "CALLED ON NULL INPUT", "RETURNS NULL ON NULL INPUT", "STRICT", //Types used by the class SecurityType //offsets 155 to 156 "SECURITY INVOKER", "SECURITY DEFINER", //Types used by the class LanguageType //offsets 157 to 163 "sql", "c", "plpgsql", "pltcl", "plperl", "plpython", "internal", //Types used by the class EncodingType //offsets 164 to 205 "UTF8", "BIG5", "EUC_CN", "EUC_JP", "EUC_JIS_2004", "EUC_KR", "EUC_TW", "GB18030", "GBK", "ISO_8859_5", "ISO_8859_6", "ISO_8859_7", "ISO_8859_8", "JOHAB", "KOI8R", "KOI8U", "LATIN1", "LATIN2", "LATIN3", "LATIN4", "LATIN5", "LATIN6", "LATIN7", "LATIN8", "LATIN9", "LATIN10", "MULE_INTERNAL", "SJIS", "SHIFT_JIS_2004", "SQL_ASCII", "UHC", "WIN866", "WIN874", "WIN1250", "WIN1251", "WIN1252", "WIN1253", "WIN1254", "WIN1255", "WIN1256", "WIN1257", "WIN1258", //Types used by the class StorageType //offsets 206 to 209 "plain", "external", "extended", "main", //Types used by the class MatchType //offsets 210 to 212 "MATCH FULL", "MATCH PARTIAL", "MATCH SIMPLE", //Types used by the class DeferralType //offsets 213 to 214 "INITIALLY IMMEDIATE", "INITIALLY DEFERRED", //Types used by the class CategoryType //offsets 215 to 228 - See table 44-43 on PostgreSQL 8.4 documentation "U", //User-defined types "A", //Array types "B", //Boolean types "C", //Composite types "D", //Date/time types "E", //Enum types "G", //Geometric types "I", //Network address types "N", //Numeric types "P", //Pseudo-types "S", //String types "T", //Timespan types "V", //Bit-string types "X", //Unknown type //Types used by the class FiringType //offsets 229 to 231 "BEFORE", "AFTER", "INSTEAD OF", /* Auxiliary types used by PostGiS types class SpatialType. These types accepts variations Z, M e ZM. > Example: POINT, POINTZ, POINTM, POINTZM Reference: http://postgis.refractions.net/documentation/manual-2.0/using_postgis_dbmanagement.html */ //offsets 232 to 247 "POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", "MULTIPOLYGON", "GEOMETRY", "GEOMETRYCOLLECTION", "POLYHEDRALSURFACE", "TRIANGLE", "TIN", "CIRCULARSTRING", "COMPOUNDCURVE", "CURVEPOLYGON", "MULTICURVE", "MULTISURFACE", //Types used by the class EventTriggerType //offsets 248 to 251 "ddl_command_start", "ddl_command_end", "sql_drop", "table_rewrite", //Types used by the class IdentityType //offsets 252 to 253 "ALWAYS", "BY DEFAULT", //Types used by the class PolicyCmdType //offsets 254 to 258 "ALL", "SELECT", "INSERT", "DELETE", "UPDATE", //Types used by the class PartitioningType //offsets 259 to 261 "RANGE", "LIST", "HASH", }; BaseType::BaseType(void) { type_idx=BaseType::Null; } QString BaseType::getTypeString(unsigned type_id) { if(type_id > TypesCount) throw Exception(ErrorCode::RefTypeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(type_list[type_id]); } void BaseType::setType(unsigned type_id,unsigned offset,unsigned count) { //Raises an error if the type count is invalid if(count==0 || count > this->TypesCount) throw Exception(ErrorCode::ObtTypesInvalidQuantity,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the type id is invalid else if(!isTypeValid(type_id,offset,count)) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else type_idx=type_id; } bool BaseType::isTypeValid(unsigned type_id,unsigned offset,unsigned count) { //Returns if the type id is valid according to the specified interval (offset-count) return((type_id>=offset && type_id<=(offset+count-1)) || type_id==BaseType::Null); } void BaseType::getTypes(QStringList &types,unsigned offset,unsigned count) { //Raises an error if the type count is invalid if(count==0 || count > BaseType::TypesCount) throw Exception(ErrorCode::ObtTypesInvalidQuantity,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { unsigned idx,total; types.clear(); total=offset+count; for(idx=offset; idx VarZm) variation=VarZm; else variation=var; } unsigned SpatialType::getVariation(void) { return(variation); } void SpatialType::getTypes(QStringList &type_list) { BaseType::getTypes(type_list,Offset,TypesCount); } void SpatialType::setSRID(int srid) { if(srid < -1) srid=-1; this->srid=srid; } int SpatialType::getSRID(void) { return(srid); } QString SpatialType::operator * (void) { if(this->type_idx!=BaseType::Null) { QString var_str; switch(variation) { case VarZ: var_str+=QString("Z"); break; case VarM: var_str+=QString("M"); break; case VarZm: var_str+=QString("ZM"); break; default: var_str=QString(); break; } if(srid > 0) return(QString("(%1%2, %3)").arg(type_list[type_idx]).arg(var_str)).arg(srid); else return(QString("(%1%2)").arg(type_list[type_idx]).arg(var_str)); } else return(QString()); } /******************** * CLASS: PgSQLType * ********************/ vector PgSqlType::user_types; PgSqlType::PgSqlType(void) { type_idx=Offset; length=0; precision=-1; dimension=0; with_timezone=false; } PgSqlType::PgSqlType(const QString &type_name) : PgSqlType() { (*this)=type_name; } PgSqlType::PgSqlType(void *ptype) : PgSqlType() { (*this) << ptype; } PgSqlType::PgSqlType(void *ptype, unsigned dimension, unsigned length, int precision, bool with_timezone, IntervalType interv_type, SpatialType spatial_type) : PgSqlType() { (*this) << ptype; setDimension(dimension); setLength(length); setPrecision(precision); setWithTimezone(with_timezone); setIntervalType(interv_type); setSpatialType(spatial_type); } PgSqlType::PgSqlType(const QString &type_name, unsigned dimension, unsigned length, int precision, bool with_timezone, IntervalType interv_type, SpatialType spatial_type) : PgSqlType() { (*this)=type_name; setDimension(dimension); setLength(length); setPrecision(precision); setWithTimezone(with_timezone); setIntervalType(interv_type); setSpatialType(spatial_type); } PgSqlType::PgSqlType(unsigned type_id, unsigned dimension, unsigned length, int precision, bool with_timezone, IntervalType interv_type, SpatialType spatial_type) : PgSqlType() { (*this)=type_id; setDimension(dimension); setLength(length); setPrecision(precision); setWithTimezone(with_timezone); setIntervalType(interv_type); setSpatialType(spatial_type); } PgSqlType PgSqlType::parseString(const QString &str) { QString type_str=str.toLower().simplified(), sptype, interv; bool with_tz=false; unsigned dim=0, srid=0; int prec=-1, len = -1; int start=-1, end=-1; QStringList value, intervals; PgSqlType type; //Checking if the string contains one of interval types IntervalType::getTypes(intervals); while(!intervals.isEmpty()) { interv=intervals.back(); intervals.pop_back(); start=type_str.indexOf(QRegExp(QString("( )") + interv.toLower())); if(start>=0) { type_str.remove(start, interv.size()+1); break; } else interv.clear(); } //Check if the type contains "with time zone" descriptor with_tz=QRegExp(QString("(.)*(with time zone)(.)*")).exactMatch(type_str); //Removes the timezone descriptor type_str.remove(QRegExp(QString("(with)(out)*( time zone)"))); //Count the dimension of the type and removes the array descriptor dim=type_str.count(QString("[]")); type_str.remove(QString("[]")); //Check if the type is a variable length type, e.g varchar(200) if(QRegExp(QString("(.)+\\(( )*[0-9]+( )*\\)")).indexIn(type_str) >=0) { start=type_str.indexOf('('); end=type_str.indexOf(')', start); len=type_str.mid(start+1, end-start-1).toInt(); } //Check if the type is a numeric type, e.g, numeric(10,2) else if(QRegExp(QString("(.)+\\(( )*[0-9]+( )*(,)( )*[0-9]+( )*\\)")).indexIn(type_str) >=0) { start=type_str.indexOf('('); end=type_str.indexOf(')', start); value=type_str.mid(start+1, end-start-1).split(','); len=value[0].toInt(); prec=value[1].toUInt(); } //Check if the type is a spatial type (PostGiS), e.g, geography(POINTZ, 4296) else if(QRegExp(QString("(.)+\\(( )*[a-z]+(( )*(,)( )*[0-9]+( )*)?\\)"), Qt::CaseInsensitive).indexIn(type_str) >=0) { start=type_str.indexOf('('); end=type_str.indexOf(')', start); value=type_str.mid(start+1, end-start-1).split(','); sptype=value[0].toUpper(); if(value.size() > 1) srid=value[1].toUInt(); } //If the string matches one of the regexp above remove the analyzed parts if(start >=0 && end>=0) type_str.remove(start, end-start+1); /* The resultant string must be only the name of the type without [] and (). NOTE: Since the string was converted to lower case at start it's necessary to get it's original form from the input string in order to correctly create the type. */ type_str=str.mid(str.indexOf(type_str, 0, Qt::CaseInsensitive),type_str.length()).trimmed(); try { try { //Creates the type based on the extracted values type=PgSqlType(type_str); } catch(Exception &) { /* In case of error (specially with PostGiS types) split the string to remove the schema name and try to create the type once more */ QStringList typname=type_str.split('.'); if(typname.size()==2) type=PgSqlType(typname[1]); else { /* One last try it to check if the type has an entry on user defined types as pg_catalog.[type name] */ type=PgSqlType(QString("pg_catalog.") + type_str); } } type.setWithTimezone(with_tz); type.setDimension(dim); if(type.isNumericType() && len > 0 && prec >=0) { type.setLength(len); type.setPrecision(prec); } else if(type.isDateTimeType() && len >= 0) type.setPrecision(len); else if(type.hasVariableLength() && len > 0) type.setLength(len); if(!interv.isEmpty()) type.setIntervalType(IntervalType(interv)); else if(!sptype.isEmpty()) type.setSpatialType(SpatialType(sptype, srid)); return(type); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, str); } } void PgSqlType::getTypes(QStringList &type_list, bool oids, bool pseudos) { unsigned idx,total; type_list.clear(); total=Offset+TypesCount; for(idx=Offset; idx=OidStart && idx<=OidEnd) || (pseudos && idx>=PseudoStart && idx<=PseudoEnd)) type_list.push_back(BaseType::type_list[idx]); } } unsigned PgSqlType::operator = (unsigned type_id) { if(type_id>=Offset) setUserType(type_id); else if(type_id > 0) BaseType::setType(type_id,Offset,TypesCount); else if(type_id==0) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(type_idx); } unsigned PgSqlType::operator = (const QString &type_name) { unsigned type_idx, usr_type_idx; type_idx=getBaseTypeIndex(type_name); usr_type_idx=getUserTypeIndex(type_name, nullptr); if(type_idx==0 && usr_type_idx==0) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(type_idx!=0) { BaseType::setType(type_idx,Offset,TypesCount); return(type_idx); } else { setUserType(usr_type_idx); return(usr_type_idx); } } void *PgSqlType::getUserTypeReference(void) { if(this->isUserType()) return(user_types[this->type_idx - (PseudoEnd + 1)].ptype); else return(nullptr); } unsigned PgSqlType::getUserTypeConfig(void) { if(this->isUserType()) return(user_types[this->type_idx - (PseudoEnd + 1)].type_conf); else return(0); } unsigned PgSqlType::getTypeId(void) { return(!(*this)); } QString PgSqlType::getTypeName(bool incl_dimension) { if(incl_dimension) { QString type; type=~(*this); if(type!=QString("void") && dimension > 0) type+=QString("[]").repeated(dimension); return(type); } return(~(*this)); } QString PgSqlType::getSQLTypeName(void) { return(*(*this)); } bool PgSqlType::isRegistered(const QString &type, void *pmodel) { if(getBaseTypeIndex(type)!=BaseType::Null) return(true); else return(getUserTypeIndex(type, nullptr, pmodel)!=BaseType::Null); } bool PgSqlType::operator == (unsigned type_id) { return(this->type_idx==type_id); } bool PgSqlType::operator == (const QString &type_name) { unsigned idx,total; bool found=false; total=Offset + TypesCount; for(idx=Offset; idxtype_idx!=type.type_idx); } bool PgSqlType::operator != (unsigned type_id) { return(this->type_idx!=type_id); } bool PgSqlType::operator == (PgSqlType type) { return(this->type_idx==type.type_idx); } bool PgSqlType::operator == (void *ptype) { int idx; idx=getUserTypeIndex(QString(),ptype); return(static_cast(type_idx) == idx); } IntervalType PgSqlType::getIntervalType(void) { return(interval_type); } SpatialType PgSqlType::getSpatialType(void) { return(spatial_type); } bool PgSqlType::isWithTimezone(void) { return(with_timezone); } bool PgSqlType::isOIDType(void) { return(type_idx>=OidStart && type_idx<=OidEnd); } bool PgSqlType::isPseudoType(void) { return(type_idx>=PseudoStart && type_idx<=PseudoEnd); } unsigned PgSqlType::operator << (void *ptype) { setUserType(ptype); return(type_idx); } void PgSqlType::setIntervalType(IntervalType interv_type) { interval_type=interv_type; } void PgSqlType::setSpatialType(SpatialType spat_type) { spatial_type=spat_type; } void PgSqlType::setWithTimezone(bool with_tz) { this->with_timezone=with_tz; } void PgSqlType::setUserType(unsigned type_id) { unsigned lim1, lim2; lim1=PseudoEnd + 1; lim2=lim1 + PgSqlType::user_types.size(); if(PgSqlType::user_types.size() > 0 && (type_id >= lim1 && type_id < lim2)) type_idx=type_id; else throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } void PgSqlType::setUserType(void *ptype) { int idx; idx=getUserTypeIndex(QString(),ptype); if(idx <= 0) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else type_idx=idx; } void PgSqlType::addUserType(const QString &type_name, void *ptype, void *pmodel, unsigned type_conf) { if(!type_name.isEmpty() && ptype && pmodel && (type_conf==UserTypeConfig::DomainType || type_conf==UserTypeConfig::SequenceType || type_conf==UserTypeConfig::TableType || type_conf==UserTypeConfig::ViewType || type_conf==UserTypeConfig::ExtensionType || type_conf==UserTypeConfig::ForeignTableType || type_conf==UserTypeConfig::BaseType) && getUserTypeIndex(type_name,ptype,pmodel)==0) { UserTypeConfig cfg; cfg.name=type_name; cfg.ptype=ptype; cfg.pmodel=pmodel; cfg.type_conf=type_conf; PgSqlType::user_types.push_back(cfg); } } void PgSqlType::removeUserType(const QString &type_name, void *ptype) { if(PgSqlType::user_types.size() > 0 && !type_name.isEmpty() && ptype) { vector::iterator itr, itr_end; itr=PgSqlType::user_types.begin(); itr_end=PgSqlType::user_types.end(); while(itr!=itr_end) { if(itr->name==type_name && itr->ptype==ptype) break; else itr++; } if(itr!=itr_end) { itr->name=QString("__invalidated_type__"); itr->ptype=nullptr; itr->invalidated=true; } } } void PgSqlType::renameUserType(const QString &type_name, void *ptype,const QString &new_name) { if(PgSqlType::user_types.size() > 0 && !type_name.isEmpty() && ptype && type_name!=new_name) { vector::iterator itr, itr_end; itr=PgSqlType::user_types.begin(); itr_end=PgSqlType::user_types.end(); while(itr!=itr_end) { if(!itr->invalidated && itr->name==type_name && itr->ptype==ptype) { itr->name=new_name; break; } itr++; } } } void PgSqlType::removeUserTypes(void *pmodel) { if(pmodel) { vector::iterator itr; unsigned idx=0; itr=user_types.begin(); while(itr!=user_types.end()) { if(itr->pmodel==pmodel) { user_types.erase(itr); itr=user_types.begin() + idx; } else { idx++; itr++; } } } } unsigned PgSqlType::getBaseTypeIndex(const QString &type_name) { QString aux_name=type_name; aux_name.remove(QString("[]")); aux_name.remove(QRegExp(QString("( )(with)(out)?(.)*"))); aux_name=aux_name.trimmed(); return(getType(aux_name,Offset,TypesCount)); } unsigned PgSqlType::getUserTypeIndex(const QString &type_name, void *ptype, void *pmodel) { if(PgSqlType::user_types.size() > 0 && (!type_name.isEmpty() || ptype)) { vector::iterator itr, itr_end; int idx=0; itr=PgSqlType::user_types.begin(); itr_end=PgSqlType::user_types.end(); while(itr!=itr_end) { if(!itr->invalidated && (((!type_name.isEmpty() && itr->name==type_name) || (ptype && itr->ptype==ptype)) && ((pmodel && itr->pmodel==pmodel) || !pmodel))) break; idx++; itr++; } if(itr!=itr_end) return(PseudoEnd + 1 + idx); else return(BaseType::Null); } else return(BaseType::Null); } QString PgSqlType::getUserTypeName(unsigned type_id) { unsigned lim1, lim2; lim1=PseudoEnd + 1; lim2=lim1 + PgSqlType::user_types.size(); if(PgSqlType::user_types.size() > 0 && (type_id >= lim1 && type_id < lim2)) return(PgSqlType::user_types[type_id - lim1].name); else return(QString()); } void PgSqlType::getUserTypes(QStringList &type_list, void *pmodel, unsigned inc_usr_types) { unsigned idx,total; type_list.clear(); total=PgSqlType::user_types.size(); for(idx=0; idx < total; idx++) { //Only the user defined types of the specified model are retrieved if(!user_types[idx].invalidated && user_types[idx].pmodel==pmodel && ((inc_usr_types & user_types[idx].type_conf) == user_types[idx].type_conf)) type_list.push_back(user_types[idx].name); } } void PgSqlType::getUserTypes(vector &ptypes, void *pmodel, unsigned inc_usr_types) { unsigned idx, total; ptypes.clear(); total=PgSqlType::user_types.size(); for(idx=0; idx < total; idx++) { //Only the user defined types of the specified model are retrieved if(!user_types[idx].invalidated && user_types[idx].pmodel==pmodel && ((inc_usr_types & user_types[idx].type_conf) == user_types[idx].type_conf)) ptypes.push_back(user_types[idx].ptype); } } QString PgSqlType::operator ~ (void) { if(type_idx >= PseudoEnd + 1) return(user_types[type_idx - (PseudoEnd + 1)].name); else { QString name=BaseType::type_list[type_idx]; if(with_timezone && (name==QString("time") || name==QString("timestamp"))) name+=QString(" with time zone"); return(name); } } bool PgSqlType::isArrayType(void) { return(dimension > 0); } bool PgSqlType::isUserType(void) { return(type_idx > PseudoEnd); } bool PgSqlType::isNetworkType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("cidr") || curr_type==QString("inet") || curr_type==QString("macaddr") || curr_type==QString("macaddr8"))); } bool PgSqlType::isGiSType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("geography") || curr_type==QString("geometry") || curr_type==QString("geometry_dump"))); } bool PgSqlType::isRangeType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("int4range") || curr_type==QString("int8range") || curr_type==QString("numrange") || curr_type==QString("tsrange") || curr_type==QString("tstzrange") || curr_type==QString("daterange"))); } bool PgSqlType::isSerialType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("serial") || curr_type==QString("smallserial") || curr_type==QString("bigserial"))); } bool PgSqlType::isDateTimeType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("time") || curr_type==QString("timestamp") || curr_type==QString("interval") || curr_type==QString("date") || curr_type==QString("timetz") || curr_type==QString("timestamptz"))); } bool PgSqlType::isNumericType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("numeric") || curr_type==QString("decimal"))); } bool PgSqlType::isIntegerType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("smallint") || curr_type==QString("integer") || curr_type==QString("bigint") || curr_type==QString("int4") || curr_type==QString("int8") || curr_type==QString("int2"))); } bool PgSqlType::hasVariableLength(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(!isUserType() && (curr_type==QString("numeric") || curr_type==QString("decimal") || curr_type==QString("character varying") || curr_type==QString("varchar") || curr_type==QString("character") || curr_type==QString("char") || curr_type==QString("bit") || curr_type==QString("bit varying") || curr_type==QString("varbit"))); } bool PgSqlType::isCharacterType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(curr_type==QString("\"char\"") || curr_type==QString("char") || curr_type==QString("character") || curr_type==QString("varchar") || curr_type==QString("character varying") || curr_type==QString("text")); } bool PgSqlType::isPolymorphicType(void) { QString curr_type=(!isUserType() ? type_list[this->type_idx] : QString()); return(curr_type==QString("anyarray") || curr_type==QString("anyelement") || curr_type==QString("anyenum") || curr_type==QString("anynonarray") || curr_type==QString("anyrange") || curr_type==QString("\"any\"")); } bool PgSqlType::acceptsPrecision(void) { return(isNumericType() || (!isUserType() && type_list[this->type_idx]!=QString("date") && isDateTimeType())); } bool PgSqlType::canCastTo(PgSqlType type) { // If the types are the same of belongs to the same category they naturally can be casted if(this->type_idx==type.type_idx || (isCharacterType() && type.isCharacterType()) || (isDateTimeType() && type.isDateTimeType()) || (isNumericType() && type.isNumericType()) || (isNetworkType() && type.isNetworkType()) || //Polymorphics anyarray, anyrange, anynoarray, anyenum to anyelement ((isPolymorphicType() && type==QString("anyelement")) || ((*this)==QString("anyelement") && type.isPolymorphicType())) || //Character to network address ((isCharacterType() || isNetworkType()) && (type.isCharacterType() || type.isNetworkType())) || //Integer to OID ((isIntegerType() || isOIDType()) && (type.isIntegerType() || type.isOIDType())) || //abstime to integer ((((*this)==QString("integer") || (*this)==QString("int4")) && type==QString("abstime")) || (((*this)==QString("abstime") && (type==QString("integer") || type==QString("int4")))))) return(true); return(false); } bool PgSqlType::isEquivalentTo(PgSqlType type) { unsigned this_idx=0, type_idx=0; static vector types={{QString("int2"),QString("smallint")}, {QString("int4"),QString("integer")}, {QString("int8"),QString("bigint")}, {QString("decimal"),QString("numeric")}, {QString("character varying"),QString("varchar")}, {QString("character"), QString("char")}, {QString("bool"), QString("boolean")}, {QString("bit varying"),QString("varbit")}, {QString("oid"),QString("regproc"),QString("regprocedure"), QString("regoper"),QString("regoperator"),QString("regclass"), QString("regtype"),QString("regconfig"),QString("regdictionary")}, {QString("timestamptz"),QString("timestamp with time zone")}}; //If the types are equal there is no need to perform further operations if(*this==type) return(true); //Getting the index which the this type is in for(QStringList list : types) { if(list.contains(~(*this))) break; this_idx++; } //Getting the index which 'type' is in for(QStringList list : types) { if(list.contains(~type)) break; type_idx++; } return(this_idx < types.size() && type_idx < types.size() && this_idx==type_idx && this->isArrayType()==type.isArrayType()); } bool PgSqlType::isExactTo(PgSqlType type) { return(this->type_idx == type.type_idx && this->dimension == type.dimension && this->length == type.length && this->precision == type.precision && this->with_timezone == type.with_timezone && this->interval_type == type.interval_type && this->spatial_type == type.spatial_type); } PgSqlType PgSqlType::getAliasType(void) { if(!isUserType()) { if(type_list[this->type_idx]==QString("serial")) return(PgSqlType(QString("integer"))); else if(type_list[this->type_idx]==QString("smallserial")) return(PgSqlType(QString("smallint"))); else if(type_list[this->type_idx]==QString("bigserial")) return(PgSqlType(QString("bigint"))); else return(PgSqlType(type_list[this->type_idx])); } else return(*this); } void PgSqlType::setDimension(unsigned dim) { if(dim > 0 && this->isUserType()) { int idx=getUserTypeIndex(~(*this), nullptr) - (PseudoEnd + 1); if(static_cast(idx) < user_types.size() && user_types[idx].type_conf==UserTypeConfig::SequenceType) throw Exception(ErrorCode::AsgInvalidSequenceTypeArray,__PRETTY_FUNCTION__,__FILE__,__LINE__); } dimension=dim; } void PgSqlType::setLength(unsigned len) { this->length=len; } void PgSqlType::setPrecision(int prec) { if(!isUserType()) { //Raises an error if the user tries to specify a precision > length if(((BaseType::type_list[type_idx]==QString("numeric") || BaseType::type_list[type_idx]==QString("decimal")) && prec > static_cast(length))) throw Exception(ErrorCode::AsgInvalidPrecision,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the precision is greater thant 6 else if(((BaseType::type_list[type_idx]==QString("time") || BaseType::type_list[type_idx]==QString("timestamp") || BaseType::type_list[type_idx]==QString("interval")) && prec > 6)) throw Exception(ErrorCode::AsgInvalidPrecisionTimestamp,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->precision=prec; } } unsigned PgSqlType::getDimension(void) { return(dimension); } unsigned PgSqlType::getLength(void) { return(length); } int PgSqlType::getPrecision(void) { return(precision); } QString PgSqlType::getCodeDefinition(unsigned def_type,QString ref_type) { if(def_type==SchemaParser::SqlDefinition) return(*(*this)); else { attribs_map attribs; SchemaParser schparser; attribs[Attributes::Length]=QString(); attribs[Attributes::Dimension]=QString(); attribs[Attributes::Precision]=QString(); attribs[Attributes::WithTimezone]=QString(); attribs[Attributes::IntervalType]=QString(); attribs[Attributes::SpatialType]=QString(); attribs[Attributes::Variation]=QString(); attribs[Attributes::Srid]=QString(); attribs[Attributes::RefType]=ref_type; attribs[Attributes::Name]=(~(*this)); attribs[Attributes::Length]=QString("%1").arg(this->length); if(dimension > 0) attribs[Attributes::Dimension]=QString("%1").arg(this->dimension); if(precision >= 0) attribs[Attributes::Precision]=QString("%1").arg(this->precision); if(interval_type != BaseType::Null) attribs[Attributes::IntervalType]=(~interval_type); if(isGiSType()) { attribs[Attributes::SpatialType]=(~spatial_type); attribs[Attributes::Variation]=QString("%1").arg(spatial_type.getVariation()); attribs[Attributes::Srid]=QString("%1").arg(spatial_type.getSRID()); } if(with_timezone) attribs[Attributes::WithTimezone]=Attributes::True; return(schparser.getCodeDefinition(Attributes::PgSqlBaseType, attribs, def_type)); } } QString PgSqlType::operator * (void) { QString fmt_type, type, aux; unsigned idx; type=~(*this); //Generation the definition for the spatial types (PostGiS) if(type==QString("geometry") || type==QString("geography")) fmt_type=type + (*spatial_type); else if(hasVariableLength()) { //Configuring the precision if((type==QString("numeric") || type==QString("decimal")) && length >= 1 && precision>=0 && precision<=static_cast(length)) aux=QString("%1(%2,%3)").arg(BaseType::type_list[type_idx]).arg(length).arg(precision); //Configuring the length for the type else if(length >= 1) aux=QString("%1(%2)").arg(BaseType::type_list[type_idx]).arg(length); else aux=type; fmt_type=aux; } else if(type!=QString("numeric") && type!=QString("decimal") && acceptsPrecision()) { if(type!=QString("interval")) { aux=BaseType::type_list[type_idx]; if(precision >= 0) aux+=QString("(%1)").arg(precision); if(with_timezone) aux+=QString(" with time zone"); } else { aux=BaseType::type_list[type_idx]; if(interval_type!=BaseType::Null) aux+=QString(" %1 ").arg(~interval_type); if(precision >= 0) aux+=QString("(%1)").arg(precision); } fmt_type=aux; } else fmt_type=type; if(type!=QString("void") && dimension > 0) { for(idx=0; idx < dimension; idx++) fmt_type+=QString("[]"); } return(fmt_type); } /*********************** * CLASS: BehaviorType * ***********************/ BehaviorType::BehaviorType(unsigned type_id) { (*this)=type_id; } BehaviorType::BehaviorType(void) { type_idx=Offset; } BehaviorType::BehaviorType(const QString &type_name) { (*this)=type_name; } void BehaviorType::getTypes(QStringList &type_list) { BaseType::getTypes(type_list,Offset,TypesCount); } unsigned BehaviorType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned BehaviorType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*********************** * CLASS: SecurityType * ***********************/ SecurityType::SecurityType(void) { type_idx=Offset; } SecurityType::SecurityType(const QString &type_name) { (*this)=type_name; } SecurityType::SecurityType(unsigned type_id) { (*this)=type_id; } void SecurityType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned SecurityType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned SecurityType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*********************** * CLASS: LanguageType * ***********************/ LanguageType::LanguageType(void) { type_idx=Offset; } LanguageType::LanguageType(unsigned type_id) { (*this)=type_id; } LanguageType::LanguageType(const QString &type_name) { (*this)=type_name; } void LanguageType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned LanguageType::operator = (unsigned tipo_id) { BaseType::setType(tipo_id,Offset,TypesCount); return(type_idx); } unsigned LanguageType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*********************** * CLASS: EncodingType * ***********************/ EncodingType::EncodingType(void) { type_idx=Offset; } EncodingType::EncodingType(const QString &type) { (*this)=type; } EncodingType::EncodingType(const unsigned type_id) { (*this)=type_id; } void EncodingType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned EncodingType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned EncodingType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } bool EncodingType::operator == (const char *type_name) { return((*this)==QString(type_name)); } bool EncodingType::operator == (const QString &type_name) { unsigned idx,total; bool found=false; total=Offset + TypesCount; for(idx=Offset; idxtype_idx!=type.type_idx); } bool EncodingType::operator != (unsigned type_id) { return(this->type_idx!=type_id); } /********************** * CLASS: StorageType * **********************/ StorageType::StorageType(void) { type_idx=Offset; } StorageType::StorageType(const QString &type_name) { (*this)=type_name; } void StorageType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned StorageType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned StorageType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } bool StorageType::operator == (const char *type_name) { return((*this)==QString(type_name)); } bool StorageType::operator == (const QString &type_name) { unsigned idx,total; bool found=false; total=Offset + TypesCount; for(idx=Offset; idxtype_idx!=type.type_idx); } /******************** * CLASS: MatchType * ********************/ MatchType::MatchType(void) { type_idx=Offset; } MatchType::MatchType(const QString &type_name) { (*this)=type_name; } MatchType::MatchType(unsigned type_id) { (*this)=type_id; } void MatchType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned MatchType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned MatchType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*********************** * CLASS: DeferralType * ***********************/ DeferralType::DeferralType(void) { type_idx=Offset; } DeferralType::DeferralType(const QString &type_name) { (*this)=type_name; } DeferralType::DeferralType(unsigned type_id) { (*this)=type_id; } void DeferralType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned DeferralType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned DeferralType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*********************** * CLASS: CategoryType * ***********************/ CategoryType::CategoryType(void) { type_idx=Offset; } CategoryType::CategoryType(const QString &type_name) { (*this)=type_name; } CategoryType::CategoryType(unsigned type_id) { (*this)=type_id; } void CategoryType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned CategoryType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned CategoryType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /********************* * CLASS: FiringType * *********************/ FiringType::FiringType(void) { type_idx=Offset; } FiringType::FiringType(unsigned type_id) { (*this)=type_id; } FiringType::FiringType(const QString &type_name) { (*this)=type_name; } void FiringType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned FiringType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned FiringType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*************************** * CLASS: EventTriggerType * ***************************/ EventTriggerType::EventTriggerType(void) { type_idx=Offset; } EventTriggerType::EventTriggerType(unsigned type_id) { (*this)=type_id; } EventTriggerType::EventTriggerType(const QString &type_name) { (*this)=type_name; } void EventTriggerType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned EventTriggerType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned EventTriggerType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*************************** * CLASS: IdentityMode * ***************************/ IdentityType::IdentityType(void) { type_idx=Offset; } IdentityType::IdentityType(unsigned type_id) { (*this)=type_id; } IdentityType::IdentityType(const QString &type_name) { (*this)=type_name; } void IdentityType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned IdentityType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned IdentityType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*************************** * CLASS: PolicyCmdType * ***************************/ PolicyCmdType::PolicyCmdType(void) { type_idx=Offset; } PolicyCmdType::PolicyCmdType(unsigned type_id) { (*this)=type_id; } PolicyCmdType::PolicyCmdType(const QString &type_name) { (*this)=type_name; } void PolicyCmdType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned PolicyCmdType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned PolicyCmdType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } /*************************** * CLASS: PartitioningType * ***************************/ PartitioningType::PartitioningType(void) { type_idx=Offset; } PartitioningType::PartitioningType(unsigned type_id) { (*this)=type_id; } PartitioningType::PartitioningType(const QString &type_name) { (*this)=type_name; } void PartitioningType::getTypes(QStringList &tipos) { BaseType::getTypes(tipos,Offset,TypesCount); } unsigned PartitioningType::operator = (unsigned type_id) { BaseType::setType(type_id,Offset,TypesCount); return(type_idx); } unsigned PartitioningType::operator = (const QString &type_name) { unsigned type_id; type_id=BaseType::getType(type_name, Offset, TypesCount); BaseType::setType(type_id,Offset,TypesCount); return(type_id); } pgmodeler-0.9.2/libpgmodeler/src/pgsqltypes.h000066400000000000000000000642331360462764600213460ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Class definitions for the basic object/actions types on PostgreSQL \note Creation date: 31/08/2006 */ #ifndef PGSQL_TYPES_H #define PGSQL_TYPES_H #include "exception.h" #include "attributes.h" #include "schemaparser.h" #include #include class BaseType{ protected: static constexpr unsigned TypesCount=262; static QString type_list[TypesCount]; //! \brief Index of the type on the type_list vector unsigned type_idx; /*! \brief Sets an id to the type according to the limit stablished by the attribute offset and type_count from each class */ void setType(unsigned type_id, unsigned offset, unsigned count); //! \brief Checks if the type id is valid according to the offset/count for the class bool isTypeValid(unsigned type_id, unsigned offset, unsigned count); //! \brief Returns the string list for all types on the specified interval (offset-count) static void getTypes(QStringList &types, unsigned offset, unsigned count); //! \brief Returns the type id searching by its name. Returns BaseType::null when not found static unsigned getType(const QString &type_name, unsigned offset, unsigned count); public: static constexpr unsigned Null=0; BaseType(void); //! \brief Returns the name of the type QString operator ~ (void); //! \brief Returns the code (id) of the type unsigned operator ! (void); //! \brief Returns the code (id) of the type unsigned getTypeId(void); //! \brief Returns the name of the type QString getTypeName(void); bool operator == (BaseType &type); bool operator == (unsigned type_id); bool operator != (BaseType &type); bool operator != (unsigned type_id); static QString getTypeString(unsigned type_id); }; class ActionType: public BaseType{ private: //! \brief Initial position of the names related to the class on BaseType::type_list static constexpr unsigned Offset=1; //! \brief Type count for the class related to the list static constexpr unsigned TypesCount=5; public: static constexpr unsigned NoAction=Offset; static constexpr unsigned Restrict=Offset+1; static constexpr unsigned Cascade=Offset+2; static constexpr unsigned SetNull=Offset+3; static constexpr unsigned SetDefault=Offset+4; ActionType(const QString &type_name); ActionType(unsigned type_id); ActionType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class ConstraintType: public BaseType{ private: static constexpr unsigned Offset=6; static constexpr unsigned TypesCount=5; public: static constexpr unsigned PrimaryKey=Offset; static constexpr unsigned ForeignKey=Offset+1; static constexpr unsigned Check=Offset+2; static constexpr unsigned Unique=Offset+3; static constexpr unsigned Exclude=Offset+4; ConstraintType(const QString &type_name); ConstraintType(unsigned type_id); ConstraintType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class EventType: public BaseType{ private: static constexpr unsigned Offset=11; static constexpr unsigned TypesCount=5; public: static constexpr unsigned OnSelect=Offset; static constexpr unsigned OnInsert=Offset+1; static constexpr unsigned OnDelete=Offset+2; static constexpr unsigned OnUpdate=Offset+3; static constexpr unsigned OnTruncate=Offset+4; EventType(const QString &type_name); EventType(unsigned type_id); EventType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); /*! \brief These two operators where created to permit the use the class EventType on STL containers (specially maps) */ bool operator < (EventType type) const; bool operator < (unsigned type_id) const; }; class ExecutionType: public BaseType{ private: static constexpr unsigned Offset=16; static constexpr unsigned TypesCount=2; public: static constexpr unsigned Also=Offset; static constexpr unsigned Instead=Offset+1; ExecutionType(const QString &type_name); ExecutionType(unsigned type_id); ExecutionType(void); static void getTypes(QStringList&type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class FunctionType: public BaseType{ private: static constexpr unsigned Offset=18; static constexpr unsigned TypesCount=3; public: static constexpr unsigned Volatile=Offset; static constexpr unsigned Stable=Offset+1; static constexpr unsigned Immutable=Offset+2; FunctionType(const QString &type_name); FunctionType(unsigned type_id); FunctionType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class IndexingType: public BaseType{ private: static constexpr unsigned Offset=21; static constexpr unsigned TypesCount=6; public: static constexpr unsigned Btree=Offset; static constexpr unsigned Gist=Offset+1; static constexpr unsigned Hash=Offset+2; static constexpr unsigned Gin=Offset+3; static constexpr unsigned Spgist=Offset+4; static constexpr unsigned Brin=Offset+5; IndexingType(const QString &type_name); IndexingType(unsigned type_id); IndexingType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class IntervalType: public BaseType{ private: static constexpr unsigned Offset=139; static constexpr unsigned TypesCount=13; public: static constexpr unsigned Year=Offset; static constexpr unsigned Month=Offset+1; static constexpr unsigned Day=Offset+2; static constexpr unsigned Hour=Offset+3; static constexpr unsigned Minute=Offset+4; static constexpr unsigned Second=Offset+5; static constexpr unsigned YearToMonth=Offset+6; static constexpr unsigned DayToHour=Offset+7; static constexpr unsigned DayToMinute=Offset+8; static constexpr unsigned DayToSecond=Offset+9; static constexpr unsigned HourToMinute=Offset+10; static constexpr unsigned HourToSecond=Offset+11; static constexpr unsigned MinuteToSecond=Offset+12; IntervalType(const QString &type_name); IntervalType(unsigned type_id); IntervalType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; /*! \brief This class stores the user defined type configureation. When the user creates a Type, Sequence, Domain, even a Table, it can be used as a type on certain configurations so this class implements a basic structure to control these types */ class UserTypeConfig { protected: //! \brief Pointer to the instance of the user defined type void *ptype; //! \brief Pointer to the model that the type belongs to void *pmodel; //! \brief Name of the type QString name; //! \brief Type configuration id (refer to ???_TYPE constants) unsigned type_conf; /*! \brief Indicates that the type is invalidated after being removed from database model. This wll cause the type not to be listed or referenced. Actually the type is not removed from user type list but deactivated to avoid messing around with other user types */ bool invalidated; public: static constexpr unsigned BaseType=1, //! \brief The type refers to a user-defined base type (class Type) DomainType=2, //! \brief The type refers to a domain TableType=4, //! \brief The type refers to a table SequenceType=8, //! \brief The type refers to a sequence ViewType=16, //! \brief The type refers to a view ExtensionType=32, //! \brief The type refers to a extension used as datatype ForeignTableType=64, //! \brief The type refers to a extension used as datatype //! \brief This constant refers to all types above and must be used only on type searches AllUserTypes=127; UserTypeConfig(void) { name=QString(); ptype=nullptr; pmodel=nullptr; invalidated=false; type_conf=BaseType; } friend class PgSqlType; }; class SpatialType: public BaseType{ private: unsigned variation; static constexpr unsigned Offset=232; static constexpr unsigned TypesCount=16; /*! \brief Used in conjunction with spatial_type, and denotes the SRID value for the spatial type. This value goes from -1 to n. */ int srid; public: static constexpr unsigned NoVar=0; static constexpr unsigned VarZ=1; static constexpr unsigned VarM=2; static constexpr unsigned VarZm=3; static constexpr unsigned Point=Offset; static constexpr unsigned LineString=Offset+1; static constexpr unsigned Polygon=Offset+2; static constexpr unsigned MultiPoint=Offset+3; static constexpr unsigned MultiLineString=Offset+4; static constexpr unsigned MultiPolygon=Offset+5; static constexpr unsigned Geometry=Offset+6; static constexpr unsigned GeometryCollection=Offset+7; SpatialType(const QString &type_name, int srid, unsigned variation_id=SpatialType::NoVar); SpatialType(unsigned type_id, int srid, unsigned var_id=SpatialType::NoVar); SpatialType(void); void setVariation(unsigned var); unsigned getVariation(void); void setSRID(int srid); int getSRID(void); static void getTypes(QStringList &type_list); QString operator * (void); }; class PgSqlType: public BaseType{ private: static constexpr unsigned Offset=27; static constexpr unsigned TypesCount=112; //! \brief Offset for oid types static constexpr unsigned OidStart=109; static constexpr unsigned OidEnd=123; //! \brief Offset for pseudo types static constexpr unsigned PseudoStart=124; static constexpr unsigned PseudoEnd=138; //! \brief Configuration for user defined types static vector user_types; //! \brief Dimension of the type if it's configured as array unsigned dimension, //! \brief Type's length (used for types like varchar, date e bit) length; //! \brief Type's precison (used by numeric/decimal) int precision; /*! \brief Indicates that the type (when used as timestamp or time) must considers timezones */ bool with_timezone; //! \brief Time interval used by 'interval' type IntervalType interval_type; //! \brief Spatial type used by the PostGiS types SpatialType spatial_type; protected: //! \brief Adds a new reference to the user defined type static void addUserType(const QString &type_name, void *ptype, void *pmodel, unsigned type_conf); //! \brief Removes a reference to the user defined type static void removeUserType(const QString &type_name, void *ptype); //! \brief Renames a user defined type static void renameUserType(const QString &type_name, void *ptype, const QString &new_name); /*! \brief Removes all registered types for the specified database model. Caution: This method must be called only when destroying the model. Calling it in any other situation can cause unexpected results */ static void removeUserTypes(void *pmodel); //! \brief Returns the name of the type using its id static QString getUserTypeName(unsigned type_id); void setUserType(unsigned type_id); void setUserType(void *ptype); public: PgSqlType(void); /*! \brief Creates a type from a simple string containing the name of the type. \note This method works in different way than PgSQLType::parserString() */ PgSqlType(const QString &type_name); //! \brief Creates a type from a pointer that references an user defined type (Type class) PgSqlType(void *ptype); /*! \brief Creates a type from a type name and a series of data like * dimension, length, precision, timezone option, interval type and spatial type. * All parameters are optional except type_name and dimension which can be used to quicly create * array of a certain type. */ PgSqlType(const QString &type_name, unsigned dimension, unsigned length = 0, int precision = -1, bool with_timezone = false, IntervalType interv_type = IntervalType::Null, SpatialType spatial_type = SpatialType()); /*! \brief Creates a type from a pointer to a data type (generally a user defined type, see UserTypeConfig class) * and a series of data like dimension, length, precision, timezone option, interval type and spatial type. * All parameters are optional except ptype and dimension which can be used to quickly create * array of a certain type. */ PgSqlType(void *ptype, unsigned dimension, unsigned length = 0, int precision = -1, bool with_timezone = false, IntervalType interv_type = IntervalType::Null, SpatialType spatial_type = SpatialType()); /*! \brief Creates a type from a type id and a series of data like * dimension, length, precision, timezone option, interval type and spatial type. * All parameters are optional except type_id and dimension which can be used to quickly create * array of a certain type. */ PgSqlType(unsigned type_id, unsigned dimension, unsigned length = 0, int precision = -1, bool with_timezone = false, IntervalType interv_type = IntervalType::Null, SpatialType spatial_type = SpatialType()); /*! \brief Creates a configured instance of PgSQLType from a string in SQL canonical form, e.g, varchar(255), timestamp with timezone, smallint[] and so on. If the string specifies arrays and length descriptors in wrong positions the method will try to return the correct type. The method will raise errors if the type could not be configured */ static PgSqlType parseString(const QString &str); static unsigned getUserTypeIndex(const QString &type_name, void *ptype, void *pmodel=nullptr); static unsigned getBaseTypeIndex(const QString &type_name); /*! \brief Returns if the type is registered in the list of valid types (built-in one and user defined). The optional parameter 'pmodel' is used to filter user defined type of a specific database model */ static bool isRegistered(const QString &type, void *pmodel=nullptr); static void getUserTypes(QStringList &type_list, void *pmodel, unsigned inc_usr_types); static void getUserTypes(vector &ptypes, void *pmodel, unsigned inc_usr_types); static void getTypes(QStringList &type_list, bool oids=true, bool pseudos=true); void setDimension(unsigned dim); void setLength(unsigned len); void setPrecision(int prec); void setWithTimezone(bool with_tz); void setIntervalType(IntervalType interv_type); void setSpatialType(SpatialType spat_type); unsigned getDimension(void); unsigned getLength(void); int getPrecision(void); IntervalType getIntervalType(void); SpatialType getSpatialType(void); bool isWithTimezone(void); bool isPseudoType(void); bool isOIDType(void); bool isUserType(void); bool isArrayType(void); bool isGiSType(void); bool isRangeType(void); bool isSerialType(void); bool isDateTimeType(void); bool isNumericType(void); bool isIntegerType(void); bool isCharacterType(void); bool isNetworkType(void); bool isPolymorphicType(void); bool hasVariableLength(void); bool acceptsPrecision(void); //! \brief Indicates if the 'this' type can be casted to 'type' bool canCastTo(PgSqlType type); /*! \brief Returns if the "this" type is equivalent to the specified type. In order to be compatible the "this" and "type" must be an alias from each other, for instance, "varchar" is compatible with "character varying" and vice-versa, smallint is compatible with int2, and so on. */ bool isEquivalentTo(PgSqlType type); /*! \brief Returns true if the provided type is exactly the same as the "this". * This method compares ALL attributes of the type. Note that this method is * different from the operatores == (PgSqlType) because this latter compares only * the indexes of the types. This method is useful if one need to fully compare the types */ bool isExactTo(PgSqlType type); PgSqlType getAliasType(void); QString getCodeDefinition(unsigned def_type, QString ref_type=QString()); QString operator ~ (void); //! \brief Returns the SQL definition for the type QString operator * (void); unsigned operator << (void *ptype); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); //! \brief Compares the index of the "this" with the provided type index. If an exact match is needed use isExactTo() bool operator == (unsigned type_idx); //! \brief Compares the index of the "this" with the provided type. If an exact match is needed use isExactTo() bool operator == (PgSqlType type); //! \brief Compares the index of the "this" with the provided type name index. If an exact match is needed use isExactTo() bool operator == (const QString &type_name); //! \brief Compares the index of the "this" with the provided type reference. If an exact match is needed use isExactTo() bool operator == (void *ptype); // The methods below are just the oposite of the == versions bool operator != (const QString &type_name); bool operator != (PgSqlType type); bool operator != (unsigned type_idx); /*! \brief Returns the pointer to the user defined type which denotes the the pgsql type */ void *getUserTypeReference(void); //! \brief Returns the configuration id for the user defined type unsigned getUserTypeConfig(void); //! \brief Returns the code (id) of the type. This is equivalent to call !type unsigned getTypeId(void); /*! \brief Returns the name of the type. This is equivalent to call ~type. * If incl_dimension is true then returns only the type name appending the dimension descriptor [] if the type's dimension is > 0. * Other attributes of the type are discarded. */ QString getTypeName(bool incl_dimension); //! \brief Returns the name of the type in SQL form including length, precision and other parameters. This is equivalent to call *type QString getSQLTypeName(void); friend class Type; friend class Domain; friend class PhysicalTable; friend class Table; friend class Sequence; friend class View; friend class Extension; friend class DatabaseModel; }; class BehaviorType: public BaseType{ private: static constexpr unsigned Offset=152; static constexpr unsigned TypesCount=3; public: static constexpr unsigned CalledOnNullInput=Offset; static constexpr unsigned ReturnsNullOnNullInput=Offset+1; static constexpr unsigned Strict=Offset+2; BehaviorType(const QString &type_name); BehaviorType(unsigned type_id); BehaviorType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class SecurityType: public BaseType{ private: static constexpr unsigned Offset=155; static constexpr unsigned TypesCount=2; public: static constexpr unsigned Invoker=Offset; static constexpr unsigned Definer=Offset+1; SecurityType(unsigned type_id); SecurityType(const QString &type_name); SecurityType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class LanguageType: public BaseType{ private: static constexpr unsigned Offset=157; static constexpr unsigned TypesCount=7; public: static constexpr unsigned Sql=Offset; static constexpr unsigned C=Offset+1; static constexpr unsigned PlPgsql=Offset+2; static constexpr unsigned PlTcl=Offset+3; static constexpr unsigned PlPerl=Offset+4; static constexpr unsigned PlPython=Offset+5; static constexpr unsigned Internal=Offset+6; LanguageType(const QString &type_name); LanguageType(unsigned type_id); LanguageType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned tipo_id); unsigned operator = (const QString &type_name); }; class EncodingType: public BaseType{ private: static constexpr unsigned Offset=164; static constexpr unsigned TypesCount=42; public: EncodingType(void); EncodingType(const QString &type); EncodingType(const unsigned type_id); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); bool operator == (const QString &type_name); bool operator == (const char *type_name); bool operator != (const QString &type_name); bool operator != (EncodingType type); bool operator != (unsigned tipo_id); }; class StorageType: public BaseType{ private: static constexpr unsigned Offset=206; static constexpr unsigned TypesCount=4; public: static constexpr unsigned Plain=Offset; static constexpr unsigned External=Offset+1; static constexpr unsigned Extended=Offset+2; static constexpr unsigned Main=Offset+3; StorageType(void); StorageType(const QString &type_name); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); bool operator == (const QString &type_name); bool operator == (const char *type_name); bool operator != (const QString &type_name); bool operator != (StorageType type); }; class MatchType: public BaseType{ private: static constexpr unsigned Offset=210; static constexpr unsigned TypesCount=3; public: static constexpr unsigned Full=Offset; static constexpr unsigned Partial=Offset+1; static constexpr unsigned Simple=Offset+2; MatchType(unsigned type_id); MatchType(const QString &type_name); MatchType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class DeferralType: public BaseType{ private: static constexpr unsigned Offset=213; static constexpr unsigned TypesCount=2; public: static constexpr unsigned Immediate=Offset; static constexpr unsigned Deferred=Offset+1; DeferralType(unsigned type_id); DeferralType(const QString &type_name); DeferralType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class CategoryType: public BaseType{ private: static constexpr unsigned Offset=215; static constexpr unsigned TypesCount=14; public: static constexpr unsigned UserDefined=Offset; static constexpr unsigned Array=Offset+1; static constexpr unsigned Boolean=Offset+2; static constexpr unsigned Composite=Offset+3; static constexpr unsigned DateTime=Offset+4; static constexpr unsigned Enumeration=Offset+5; static constexpr unsigned Geometric=Offset+6; static constexpr unsigned NetworkAddr=Offset+7; static constexpr unsigned Numeric=Offset+8; static constexpr unsigned PseudoTypes=Offset+9; static constexpr unsigned Stringt=Offset+10; static constexpr unsigned Timespan=Offset+11; static constexpr unsigned BitString=Offset+12; static constexpr unsigned Unknown=Offset+13; CategoryType(unsigned type_id); CategoryType(const QString &type_name); CategoryType(void); static void getTypes(QStringList &type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class FiringType: public BaseType{ private: static constexpr unsigned Offset=229; static constexpr unsigned TypesCount=3; public: static constexpr unsigned Before=Offset; static constexpr unsigned After=Offset+1; static constexpr unsigned InsteadOf=Offset+2; FiringType(const QString &type_name); FiringType(unsigned type_id); FiringType(void); static void getTypes(QStringList&type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class EventTriggerType: public BaseType{ private: static constexpr unsigned Offset=248; static constexpr unsigned TypesCount=4; public: static constexpr unsigned DdlCommandStart=Offset; static constexpr unsigned DdlCommandEnd=Offset+1; static constexpr unsigned SqlDrop=Offset+2; static constexpr unsigned TableRewrite=Offset+3; EventTriggerType(const QString &type_name); EventTriggerType(unsigned type_id); EventTriggerType(void); static void getTypes(QStringList&type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class IdentityType: public BaseType{ private: static constexpr unsigned Offset=252; static constexpr unsigned TypesCount=2; public: static constexpr unsigned Always=Offset; static constexpr unsigned ByDefault=Offset+1; IdentityType(const QString &type_name); IdentityType(unsigned type_id); IdentityType(void); static void getTypes(QStringList&type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class PolicyCmdType: public BaseType { private: static constexpr unsigned Offset=254; static constexpr unsigned TypesCount=5; public: static constexpr unsigned All=Offset; static constexpr unsigned Select=Offset+1; static constexpr unsigned Insert=Offset+2; static constexpr unsigned Update=Offset+3; static constexpr unsigned Delete=Offset+4; PolicyCmdType(const QString &type_name); PolicyCmdType(unsigned type_id); PolicyCmdType(void); static void getTypes(QStringList&type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; class PartitioningType: public BaseType { private: static constexpr unsigned Offset=259; static constexpr unsigned TypesCount=3; public: static constexpr unsigned Range=Offset; static constexpr unsigned List=Offset+1; static constexpr unsigned Hash=Offset+2; PartitioningType(const QString &type_name); PartitioningType(unsigned type_id); PartitioningType(void); static void getTypes(QStringList&type_list); unsigned operator = (unsigned type_id); unsigned operator = (const QString &type_name); }; #endif pgmodeler-0.9.2/libpgmodeler/src/physicaltable.cpp000066400000000000000000001430521360462764600223070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "physicaltable.h" #include "pgmodelerns.h" const QString PhysicalTable::DataSeparator = QString("•"); const QString PhysicalTable::DataLineBreak = QString("%1%2").arg("⸣").arg('\n'); PhysicalTable::PhysicalTable(void) : BaseTable() { gen_alter_cmds=false; attributes[Attributes::Columns]=QString(); attributes[Attributes::InhColumns]=QString(); attributes[Attributes::Constraints]=QString(); attributes[Attributes::ColsComment]=QString(); attributes[Attributes::AncestorTable]=QString(); attributes[Attributes::GenAlterCmds]=QString(); attributes[Attributes::ConstrSqlDisabled]=QString(); attributes[Attributes::ColIndexes]=QString(); attributes[Attributes::ConstrIndexes]=QString(); attributes[Attributes::InitialData]=QString(); attributes[Attributes::Partitioning]=QString(); attributes[Attributes::PartitionKey]=QString(); attributes[Attributes::PartitionedTable]=QString(); attributes[Attributes::PartitionBoundExpr]=QString(); attributes[Attributes::CopyTable]=QString(); copy_table=partitioned_table=nullptr; partitioning_type=BaseType::Null; } void PhysicalTable::destroyObjects(void) { vector list=getObjects(); while(!list.empty()) { delete(list.back()); list.pop_back(); } ancestor_tables.clear(); partition_tables.clear(); } void PhysicalTable::setName(const QString &name) { QString prev_name=this->getName(true); BaseObject::setName(name); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void PhysicalTable::setSchema(BaseObject *schema) { QString prev_name=this->getName(true); BaseObject::setSchema(schema); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void PhysicalTable::setCopyTable(PhysicalTable *tab) { setCodeInvalidated(copy_table != tab); copy_table=tab; if(!copy_table) copy_op=CopyOptions(0,0); } void PhysicalTable::setCopyTableOptions(CopyOptions like_op) { if(copy_table) { setCodeInvalidated(copy_op != like_op); this->copy_op=like_op; } } PhysicalTable *PhysicalTable::getCopyTable(void) { return(copy_table); } CopyOptions PhysicalTable::getCopyTableOptions(void) { return(copy_op); } void PhysicalTable::setPartitioningType(PartitioningType part_type) { setCodeInvalidated(partitioning_type != part_type); partitioning_type = part_type; if(part_type == PartitioningType::Null) partition_keys.clear(); else // If changing the partitioning type of the table the ALTER commands for columns and constraints is disabled setGenerateAlterCmds(false); } PartitioningType PhysicalTable::getPartitioningType(void) { return(partitioning_type); } PhysicalTable *PhysicalTable::getPartitionedTable(void) { return(partitioned_table); } void PhysicalTable::setProtected(bool value) { vector obj_types = getChildObjectTypes(obj_type); vector *list=nullptr; //Protected the table child objects for(auto &type : obj_types) { list=getObjectList(type); for(auto &tab_obj : *list) { /* Relationship included object are always protected, so the protection state of this objects is not altered */ if(!tab_obj->isAddedByRelationship()) tab_obj->setProtected(value); } } //Protectes the table itself BaseGraphicObject::setProtected(value); } void PhysicalTable::setCommentAttribute(TableObject *tab_obj) { if(tab_obj && !tab_obj->getComment().isEmpty() && tab_obj->isDeclaredInTable()) { attribs_map attribs; attribs[Attributes::Signature]=tab_obj->getSignature(); attribs[Attributes::SqlObject]=tab_obj->getSQLName(); attribs[Attributes::Column]=(tab_obj->getObjectType()==ObjectType::Column ? Attributes::True : QString()); attribs[Attributes::Constraint]=(tab_obj->getObjectType()==ObjectType::Constraint ? Attributes::True : QString()); attribs[Attributes::Table]=this->getName(true); attribs[Attributes::Name]=tab_obj->getName(true); QString comment = tab_obj->getEscapedComment(BaseObject::isEscapeComments()); attribs[Attributes::EscapeComment]=BaseObject::isEscapeComments() ? Attributes::True : QString(); attribs[Attributes::Comment]=comment; schparser.ignoreUnkownAttributes(true); if(tab_obj->isSQLDisabled()) attributes[Attributes::ColsComment]+=QString("-- "); attributes[Attributes::ColsComment]+=schparser.getCodeDefinition(Attributes::Comment, attribs, SchemaParser::SqlDefinition); schparser.ignoreUnkownAttributes(false); } } void PhysicalTable::setAncestorTableAttribute(void) { unsigned i, count=ancestor_tables.size(); QStringList list; for(i=0; i < count; i++) list.push_back(ancestor_tables[i]->getName(true)); attributes[Attributes::AncestorTable]=list.join(','); } void PhysicalTable::setRelObjectsIndexesAttribute(void) { attribs_map aux_attribs; vector *> obj_indexes={ &col_indexes, &constr_indexes }; QString attribs[]={ Attributes::ColIndexes, Attributes::ConstrIndexes }; ObjectType obj_types[]={ ObjectType::Column, ObjectType::Constraint }; unsigned idx=0, size=obj_indexes.size(); for(idx=0; idx < size; idx++) { attributes[attribs[idx]]=QString(); if(!obj_indexes[idx]->empty()) { for(auto &obj_idx : (*obj_indexes[idx])) { aux_attribs[Attributes::Name]=obj_idx.first; aux_attribs[Attributes::Index]=QString::number(obj_idx.second); schparser.ignoreUnkownAttributes(true); aux_attribs[Attributes::Objects]+=schparser.getCodeDefinition(Attributes::Object, aux_attribs, SchemaParser::XmlDefinition); } aux_attribs[Attributes::ObjectType]=BaseObject::getSchemaName(obj_types[idx]); attributes[attribs[idx]]=schparser.getCodeDefinition(Attributes::CustomIdxs, aux_attribs, SchemaParser::XmlDefinition); aux_attribs.clear(); } } } void PhysicalTable::setColumnsAttribute(unsigned def_type, bool incl_rel_added_cols) { QString str_cols, inh_cols; unsigned i, count; count=columns.size(); for(i=0; i < count; i++) { /* Do not generates the column code definition when it is not included by relatoinship, in case of XML definition. */ if((def_type==SchemaParser::SqlDefinition && !columns[i]->isAddedByCopy() && !columns[i]->isAddedByGeneralization()) || /* (def_type==SchemaParser::SqlDefinition && columns[i]->isAddedByCopy() && this->isPartition()) || */ (def_type==SchemaParser::XmlDefinition && (!columns[i]->isAddedByRelationship() || (incl_rel_added_cols && columns[i]->isAddedByRelationship())))) { str_cols+=columns[i]->getCodeDefinition(def_type); if(def_type==SchemaParser::SqlDefinition) setCommentAttribute(columns[i]); } else if(def_type==SchemaParser::SqlDefinition && columns[i]->isAddedByGeneralization() && !gen_alter_cmds) { inh_cols+=QString("-- ") + columns[i]->getCodeDefinition(def_type); } } if(def_type==SchemaParser::SqlDefinition) { if(!str_cols.isEmpty() && !gen_alter_cmds) { count = str_cols.size(); // Removing the last comma from the columns SQL in order to avoid syntax errors if(str_cols[count-2] == ',' || str_cols[count-2] == '\n') str_cols.remove(count - 2, 2); /* Special case: if we have the last column's SQL disabled we need to remove * the comma from the last line (the enabled one) in order to avoid syntax error */ int disabled_col_idx = str_cols.lastIndexOf(QString("-- ")), last_comma_idx = str_cols.lastIndexOf(',', disabled_col_idx); if(last_comma_idx >= 0 && last_comma_idx < disabled_col_idx) str_cols.remove(last_comma_idx, 1); } attributes[Attributes::InhColumns]=inh_cols; } attributes[Attributes::Columns]=str_cols; } void PhysicalTable::setConstraintsAttribute(unsigned def_type) { QString str_constr; unsigned i, count; bool inc_added_by_rel; Constraint *constr=nullptr; vector lines; count=constraints.size(); for(i=0; i < count; i++) { constr=dynamic_cast(constraints[i]); if(constr->getConstraintType()!=ConstraintType::ForeignKey && ((def_type==SchemaParser::SqlDefinition && ((!constr->isReferRelationshipAddedColumn() && constr->getConstraintType()!=ConstraintType::Check) || (constr->getConstraintType()==ConstraintType::Check && !constr->isAddedByGeneralization()) || constr->getConstraintType()==ConstraintType::PrimaryKey)) || (def_type==SchemaParser::XmlDefinition && !constr->isAddedByRelationship() && ((constr->getConstraintType()!=ConstraintType::PrimaryKey && !constr->isReferRelationshipAddedColumn()) || (constr->getConstraintType()==ConstraintType::PrimaryKey))))) { inc_added_by_rel=(def_type==SchemaParser::SqlDefinition); if(def_type==SchemaParser::XmlDefinition) str_constr+=constr->getCodeDefinition(def_type,inc_added_by_rel); else //For sql definition the generated constraints are stored in a vector to be treated below lines.push_back(constr->getCodeDefinition(def_type,inc_added_by_rel)); if(def_type==SchemaParser::SqlDefinition) setCommentAttribute(constr); } } if(def_type==SchemaParser::SqlDefinition && !lines.empty()) { /* When the coistraints are being generated in form of ALTER commands simply concatenates all the lines */ if(gen_alter_cmds) { for(i=0; i < lines.size(); i++) str_constr+=lines[i]; } else { /* Check if some constraint has its sql disabled. If so, it necessary to make some tweaks in order to not generate bad sql code */ i=lines.size()-1; unsigned dis_sql_cnt=0; //If the last line starts with -- indicates that sql code for the constraint is disable if(lines[i].startsWith(QLatin1String("--")) && i > 0) //Removes the comma from the above line in order to avoid bad sql lines[i-1].remove(lines[i-1].lastIndexOf(','),1); else //Otherwise removes the comma from the last line lines[i].remove(lines[i].lastIndexOf(','),1); for(i=0; i < lines.size(); i++) { if(lines[i].startsWith(QLatin1String("--"))) dis_sql_cnt++; str_constr+=lines[i]; } attributes[Attributes::ConstrSqlDisabled]=(dis_sql_cnt==lines.size() ? Attributes::True : QString()); } } attributes[Attributes::Constraints]=str_constr; } vector *PhysicalTable::getObjectList(ObjectType obj_type) { if(obj_type==ObjectType::Column) return(&columns); if(obj_type==ObjectType::Constraint) return(&constraints); if(obj_type==ObjectType::Trigger) return(&triggers); return(nullptr); } void PhysicalTable::addObject(BaseObject *obj, int obj_idx) { ObjectType obj_type; if(!obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { int idx; obj_type=obj->getObjectType(); #ifdef DEMO_VERSION #warning "DEMO VERSION: table children objects creation limit." vector *obj_list=(obj_type!=ObjectType::Table ? getObjectList(obj_type) : nullptr); if((obj_list && obj_list->size() >= GlobalAttributes::MaxObjectCount) || (obj_type==ObjectType::Table && ancestor_tables.size() >= GlobalAttributes::MaxObjectCount)) throw Exception(trUtf8("In demonstration version tables can have only `%1' instances of each child object type or ancestor tables! You've reach this limit for the type: `%2'") .arg(GlobalAttributes::MaxObjectCount) .arg(BaseObject::getTypeName(obj_type)), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); #endif try { //Raises an error if already exists a object with the same name and type if(getObject(obj->getName(),obj_type,idx)) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(obj->getName(true)) .arg(obj->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the user try to set the table as ancestor/copy of itself else if((isPhysicalTable(obj_type) || obj_type==ObjectType::BaseTable) && obj==this) throw Exception(ErrorCode::InvInheritCopyPartRelationship,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!isPhysicalTable(obj_type)) { TableObject *tab_obj; vector *obj_list; Column *col; tab_obj=dynamic_cast(obj); col=dynamic_cast(tab_obj); //Sets the object parent table if there isn't one if(!tab_obj->getParentTable()) tab_obj->setParentTable(this); //Raises an error if the parent table of the table object is different from table 'this' else if(tab_obj->getParentTable()!=this) throw Exception(ErrorCode::AsgObjectBelongsAnotherTable,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Validates the object SQL code befor insert on table obj->getCodeDefinition(SchemaParser::SqlDefinition); if(col && col->getType()==this) { throw Exception(Exception::getErrorMessage(ErrorCode::InvColumnTableType) .arg(col->getName()) .arg(this->getName()), ErrorCode::InvColumnTableType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(obj_type==ObjectType::Constraint) { //Raises a error if the user try to add a second primary key on the table if(dynamic_cast(tab_obj)->getConstraintType()==ConstraintType::PrimaryKey && this->getPrimaryKey()) throw Exception(ErrorCode::AsgExistingPrimaryKeyTable,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(obj_type==ObjectType::Trigger) dynamic_cast(tab_obj)->validateTrigger(); obj_list=getObjectList(obj_type); //Adds the object to the table if(obj_idx < 0 || obj_idx >= static_cast(obj_list->size())) obj_list->push_back(tab_obj); else { //If there is a object index specified inserts the object at the position if(obj_list->size() > 0) obj_list->insert((obj_list->begin() + obj_idx), tab_obj); else obj_list->push_back(tab_obj); } if(obj_type==ObjectType::Column || obj_type==ObjectType::Constraint) { updateAlterCmdsStatus(); if(obj_type==ObjectType::Constraint) dynamic_cast(tab_obj)->setColumnsNotNull(true); } } else if(isPhysicalTable(obj_type)) { PhysicalTable *tab = nullptr; tab = dynamic_cast(obj); if(obj_idx < 0 || obj_idx >= static_cast(ancestor_tables.size())) ancestor_tables.push_back(tab); else ancestor_tables.insert((ancestor_tables.begin() + obj_idx), tab); } else throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(true); } catch(Exception &e) { if(e.getErrorCode()==ErrorCode::UndefinedAttributeValue) throw Exception(Exception::getErrorMessage(ErrorCode::AsgObjectInvalidDefinition) .arg(obj->getName()) .arg(obj->getTypeName()), ErrorCode::AsgObjectInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void PhysicalTable::addColumn(Column *col, int idx) { try { addObject(col, idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::addTrigger(Trigger *trig, int idx) { try { addObject(trig, idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::setPartionedTable(PhysicalTable *table) { setCodeInvalidated(partitioned_table != table); if(table != partitioned_table && partitioned_table) partitioned_table->removePartitionTable(this); partitioned_table = table; if(partitioned_table) { partitioned_table->addPartitionTable(this); /* If the partitioned table is defined we need to disable the ALTER commands for columns and constraints * in order to avoid SQL syntax errors */ setGenerateAlterCmds(false); } } void PhysicalTable::setPartitionBoundingExpr(const QString part_bound_expr) { setCodeInvalidated(part_bounding_expr != part_bound_expr); part_bounding_expr = part_bound_expr; } QString PhysicalTable::getPartitionBoundingExpr(void) { return(part_bounding_expr); } vector PhysicalTable::getPartionTables(void) { return(partition_tables); } bool PhysicalTable::isPartitionTableExists(PhysicalTable *table, bool compare_names) { return(getPartitionTableIndex(table, compare_names) >= 0); } void PhysicalTable::addConstraint(Constraint *constr, int idx) { try { addObject(constr, idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::addAncestorTable(PhysicalTable *tab, int idx) { try { addObject(tab, idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::addPartitionTable(PhysicalTable *tab) { if(tab && std::find(partition_tables.begin(), partition_tables.end(), tab) == partition_tables.end()) partition_tables.push_back(tab); } void PhysicalTable::removePartitionTable(PhysicalTable *tab) { int idx = getPartitionTableIndex(tab, false); if(idx >= 0) partition_tables.erase(partition_tables.begin() + idx); } int PhysicalTable::getPartitionTableIndex(PhysicalTable *tab, bool compare_names) { if(!tab) return(-1); vector::iterator itr = partition_tables.begin(); while(itr != partition_tables.end()) { if(*itr == tab || (compare_names && tab->getName(true) == (*itr)->getName(true))) break; itr++; } if(itr == partition_tables.end()) return(-1); return(itr - partition_tables.begin()); } void PhysicalTable::addPartitionKeys(vector &part_keys) { vector part_keys_bkp = partition_keys; if(partitioning_type == BaseType::Null) return; if(partitioning_type == PartitioningType::List && part_keys.size() > 1) throw Exception(Exception::getErrorMessage(ErrorCode::InvPartitionKeyCount).arg(this->getSignature()), ErrorCode::InvPartitionKeyCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); partition_keys.clear(); for(auto &part_key : part_keys) { if(std::find(partition_keys.begin(), partition_keys.end(), part_key) != partition_keys.end()) { partition_keys = part_keys_bkp; throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); } if(part_key.getColumn() && part_key.getColumn()->isAddedByRelationship()) { partition_keys = part_keys_bkp; throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidColumnPartitionKey) .arg(part_key.getColumn()->getSignature(true)), ErrorCode::AsgInvalidColumnPartitionKey,__PRETTY_FUNCTION__,__FILE__,__LINE__); } partition_keys.push_back(part_key); } setCodeInvalidated(true); } void PhysicalTable::removePartitionKeys(void) { partition_keys.clear(); setCodeInvalidated(true); } void PhysicalTable::removeObject(BaseObject *obj) { try { if(obj) { TableObject *tab_obj=dynamic_cast(obj); if(tab_obj) removeObject(getObjectIndex(tab_obj), obj->getObjectType()); else removeObject(obj->getName(true), ObjectType::Table); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeObject(const QString &name, ObjectType obj_type) { int idx; //Gets the object index getObject(name,obj_type,idx); //Removes the object If it was found (idx >= 0) if(idx>=0) removeObject(static_cast(idx),obj_type); } void PhysicalTable::removeObject(unsigned obj_idx, ObjectType obj_type) { //Raises an error if the user try to remove a object with invalid type if(!TableObject::isTableObject(obj_type) && obj_type!=ObjectType::Table) throw Exception(ErrorCode::RemObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(PhysicalTable::isPhysicalTable(obj_type) && obj_idx < ancestor_tables.size()) { vector::iterator itr; itr=ancestor_tables.begin() + obj_idx; ancestor_tables.erase(itr); } else if(!PhysicalTable::isPhysicalTable(obj_type)) { vector *obj_list=getObjectList(obj_type); vector::iterator itr; if(!obj_list) return; //Raises an error if the object index is out of bound if(obj_idx >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(obj_type!=ObjectType::Column) { itr=obj_list->begin() + obj_idx; TableObject *tab_obj=(*itr); Constraint *constr=dynamic_cast(tab_obj); tab_obj->setParentTable(nullptr); obj_list->erase(itr); if(constr && constr->getConstraintType()==ConstraintType::PrimaryKey) dynamic_cast(tab_obj)->setColumnsNotNull(false); } else { vector refs; Column *column=nullptr; itr=obj_list->begin() + obj_idx; column=dynamic_cast(*itr); //Gets the references to the column before the exclusion getColumnReferences(column, refs, true); //Case some trigger, constraint, index is referencing the column raises an error if(!refs.empty()) { throw Exception(Exception::getErrorMessage(ErrorCode::RemInderectReference) .arg(column->getName()) .arg(column->getTypeName()) .arg(refs[0]->getName()) .arg(refs[0]->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::RemInderectReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the column is being referenced by any partition key if(isPartitionKeyRefColumn(column)) { throw Exception(Exception::getErrorMessage(ErrorCode::RemColumnRefByPartitionKey) .arg(column->getName()).arg(this->getName(true)), ErrorCode::RemColumnRefByPartitionKey,__PRETTY_FUNCTION__,__FILE__,__LINE__); } column->setParentTable(nullptr); columns.erase(itr); } } setCodeInvalidated(true); } void PhysicalTable::removeColumn(const QString &name) { try { removeObject(name,ObjectType::Column); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeColumn(unsigned idx) { try { removeObject(idx,ObjectType::Column); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeTrigger(const QString &name) { try { removeObject(name,ObjectType::Trigger); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeTrigger(unsigned idx) { try { removeObject(idx,ObjectType::Trigger); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeConstraint(const QString &name) { try { removeObject(name,ObjectType::Constraint); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeConstraint(unsigned idx) { try { removeObject(idx,ObjectType::Constraint); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeAncestorTable(const QString &name) { try { removeObject(name,ObjectType::Table); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PhysicalTable::removeAncestorTable(unsigned idx) { try { removeObject(idx,ObjectType::Table); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } int PhysicalTable::getObjectIndex(const QString &name, ObjectType obj_type) { int idx; getObject(name, obj_type, idx); return(idx); } int PhysicalTable::getObjectIndex(BaseObject *obj) { TableObject *tab_obj=dynamic_cast(obj); vector *obj_list = nullptr; vector::iterator itr, itr_end; bool found=false; if(!obj) return(-1); obj_list = getObjectList(obj->getObjectType()); if(!obj_list) return(-1); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && !found) { found=((tab_obj->getParentTable()==this && (*itr)==tab_obj) || (tab_obj->getName()==(*itr)->getName())); if(!found) itr++; } if(found) return(itr-obj_list->begin()); else return(-1); } BaseObject *PhysicalTable::getObject(const QString &name, ObjectType obj_type) { int idx; return(getObject(name, obj_type, idx)); } BaseObject *PhysicalTable::getObject(const QString &name, ObjectType obj_type, int &obj_idx) { BaseObject *object=nullptr; bool found=false, format=false; vector *obj_list=getObjectList(obj_type); //Checks if the name contains ", if so, the search will consider formatted names format=name.contains('"'); if(TableObject::isTableObject(obj_type) && obj_list) { vector::iterator itr, itr_end; QString aux_name=name; itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end) { found=((*itr)->getName(format)==aux_name); if(!found) itr++; else break; } if(found) { obj_idx=(itr-obj_list->begin()); object=(*itr); } else obj_idx=-1; } else if(isPhysicalTable(obj_type)) { vector::iterator itr_tab, itr_end_tab; QString tab_name, aux_name=name; aux_name.remove('"'); itr_tab=ancestor_tables.begin(); itr_end_tab=ancestor_tables.end(); while(itr_tab!=itr_end_tab) { /* Unlike other object types, tables are always compared with the FORMATTED NAME because they must be 'schema-qualified' preventing a table of the same name but different schemas are confused */ tab_name=(*itr_tab)->getName(true).remove('"'); found=(tab_name==aux_name); if(!found) itr_tab++; else break; } if(found) { obj_idx=(itr_tab-ancestor_tables.begin()); object=(*itr_tab); } else obj_idx=-1; } else throw Exception(ErrorCode::ObtObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(object); } BaseObject *PhysicalTable::getObject(unsigned obj_idx, ObjectType obj_type) { vector *obj_list=nullptr; if(isPhysicalTable(obj_type)) { //Raises an error if the object index is out of bound if(obj_idx >= ancestor_tables.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(ancestor_tables[obj_idx]); } else { obj_list = getObjectList(obj_type); if(!obj_list) return(nullptr); if(obj_idx < obj_list->size()) return(obj_list->at(obj_idx)); //Raises an error if the object index is out of bound throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } PhysicalTable *PhysicalTable::getAncestorTable(const QString &name) { int idx; return(dynamic_cast(getObject(name, ObjectType::Table, idx))); } PhysicalTable *PhysicalTable::getAncestorTable(unsigned idx) { return(dynamic_cast(getObject(idx, ObjectType::Table))); } Constraint *PhysicalTable::getPrimaryKey(void) { unsigned count,i; Constraint *pk=nullptr, *constr=nullptr; count=constraints.size(); for(i=0; i < count && !pk; i++) { constr=dynamic_cast(constraints[i]); pk=(constr->getConstraintType()==ConstraintType::PrimaryKey ? constr : nullptr); } return(pk); } Column *PhysicalTable::getColumn(const QString &name, bool ref_old_name) { if(!ref_old_name) { int idx; return(dynamic_cast(getObject(name, ObjectType::Column, idx))); } else { Column *column=nullptr; vector::iterator itr, itr_end; bool found=false, format=false; format=name.contains('"'); itr=columns.begin(); itr_end=columns.end(); //Search the column referencing the old name while(itr!=itr_end && !found) { column=dynamic_cast(*itr); itr++; found=(!name.isEmpty() && column->getOldName(format)==name); } if(!found) column=nullptr; return(column); } } Column *PhysicalTable::getColumn(unsigned idx) { return(dynamic_cast(getObject(idx,ObjectType::Column))); } Trigger *PhysicalTable::getTrigger(const QString &name) { int idx; return(dynamic_cast(getObject(name,ObjectType::Trigger,idx))); } Trigger *PhysicalTable::getTrigger(unsigned idx) { return(dynamic_cast(getObject(idx,ObjectType::Trigger))); } Constraint *PhysicalTable::getConstraint(const QString &name) { int idx; return(dynamic_cast(getObject(name,ObjectType::Constraint,idx))); } Constraint *PhysicalTable::getConstraint(unsigned idx) { return(dynamic_cast(getObject(idx,ObjectType::Constraint))); } unsigned PhysicalTable::getColumnCount(void) { return(columns.size()); } unsigned PhysicalTable::getTriggerCount(void) { return(triggers.size()); } unsigned PhysicalTable::getConstraintCount(void) { return(constraints.size()); } unsigned PhysicalTable::getAncestorTableCount(void) { return(ancestor_tables.size()); } unsigned PhysicalTable::getObjectCount(ObjectType obj_type, bool inc_added_by_rel) { if(!TableObject::isTableObject(obj_type) && !isPhysicalTable(obj_type)) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(isPhysicalTable(obj_type)) return(ancestor_tables.size()); else { vector *list=nullptr; list = getObjectList(obj_type); if(!list) return(0); if(!inc_added_by_rel) { vector::iterator itr, itr_end; unsigned count=0; itr=list->begin(); itr_end=list->end(); while(itr!=itr_end) { if(!(*itr)->isAddedByRelationship()) count++; itr++; } return(count); } else return(list->size()); } } void PhysicalTable::setRelObjectsIndexes(const vector &obj_names, const vector &idxs, ObjectType obj_type) { if(!obj_names.empty() && obj_names.size()==idxs.size()) { map *obj_idxs_map=nullptr; unsigned idx=0, size=obj_names.size(); if(obj_type==ObjectType::Column) obj_idxs_map=&col_indexes; else if(obj_type==ObjectType::Constraint) obj_idxs_map=&constr_indexes; else throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); for(idx=0; idx < size; idx++) (*obj_idxs_map)[obj_names[idx]]=idxs[idx]; } } void PhysicalTable::saveRelObjectsIndexes(ObjectType obj_type) { map *obj_idxs_map=nullptr; vector *list=nullptr; if(obj_type==ObjectType::Column) { obj_idxs_map=&col_indexes; list=&columns; } else if(obj_type==ObjectType::Constraint) { obj_idxs_map=&constr_indexes; list=&constraints; } obj_idxs_map->clear(); setCodeInvalidated(true); if(isReferRelationshipAddedObject()) { unsigned idx=0; for(auto &obj : (*list)) { if(obj->isAddedByLinking()) (*obj_idxs_map)[obj->getName()]=idx; idx++; } } } void PhysicalTable::saveRelObjectsIndexes(void) { saveRelObjectsIndexes(ObjectType::Column); saveRelObjectsIndexes(ObjectType::Constraint); } void PhysicalTable::restoreRelObjectsIndexes(void) { restoreRelObjectsIndexes(ObjectType::Column); restoreRelObjectsIndexes(ObjectType::Constraint); if(!col_indexes.empty() || !constr_indexes.empty()) { setCodeInvalidated(true); this->setModified(true); } } void PhysicalTable::restoreRelObjectsIndexes(ObjectType obj_type) { map *obj_idxs=nullptr; if(obj_type==ObjectType::Column) obj_idxs=&col_indexes; else obj_idxs=&constr_indexes; if(!obj_idxs->empty()) { vector *list=getObjectList(obj_type); vector new_list; QString name; TableObject *tab_obj=nullptr; unsigned i=0, pos=0, size=0, obj_idx, names_used=0, aux_size=0; size=list->size(); /* Indentify the maximum index on the existing rel objects. This is done to correctly resize the new list in order to avoid exceed the list bounds and consequently crashing the app */ for(auto &itr : *obj_idxs) { if(aux_size < (itr.second + 1)) aux_size=itr.second + 1; } /* If the auxiliary size is lesser than the current object list size the new list is resized with same capacity of the "list" vector */ if(aux_size < size) aux_size=size; new_list.resize(aux_size); for(auto &obj : *list) { name=obj->getName(); //Check if the current object is a relationship created one and its name is on the custom index map if(obj->isAddedByLinking() && obj_idxs->count(name)) { //Allocate the object on its original position obj_idx=obj_idxs->at(name); new_list[obj_idx]=obj; names_used++; } } /* Allocating the other objects, the ones that aren't created by relationship or the one which were created by relationship but weren't positioned yet */ pos=i=0; while(pos < size && i < size) { tab_obj=list->at(pos); name=tab_obj->getName(); if(!new_list[i] && obj_idxs->count(name)==0) { new_list[i]=tab_obj; pos++; i++; } else if(obj_idxs->count(name)!=0) pos++; else if(new_list[i]) i++; } //Removing unused items (nullptr ones) from the list using remove_if and lambdas (for predicate) new_list.erase(remove_if(new_list.begin(), new_list.end(), [](TableObject *obj){ return(obj==nullptr); }), new_list.end()); (*list)=new_list; /* Checking if the object names used are equal to the map size. If not, indicates that one o more objects on the map doesn't exists anymore on the table thus there is the need to updated the object index map */ if(names_used!=obj_idxs->size()) saveRelObjectsIndexes(obj_type); } } bool PhysicalTable::isConstraintRefColumn(Column *column, ConstraintType constr_type) { bool found=false; vector::iterator itr, itr_end; Constraint *constr=nullptr; if(column) { itr=constraints.begin(); itr_end=constraints.end(); while(itr!=itr_end && !found) { constr=dynamic_cast(*itr); itr++; found=(constr->getConstraintType()==constr_type && constr->isColumnReferenced(column)); } } return(found); } bool PhysicalTable::isPartitionKeyRefColumn(Column *column) { bool found=false; if(column) { for(auto &part_key : partition_keys) { if(part_key.getColumn() == column) { found = true; break; } } } return(found); } void PhysicalTable::setGenerateAlterCmds(bool value) { if(value && (isPartition() || isPartitioned())) { /* Forcing the disabling of ALTER commands for columns and constraints * if the table is a partition or partitioned table in order to avoid * SQL syntax errors */ setCodeInvalidated(true); gen_alter_cmds = false; } else { setCodeInvalidated(gen_alter_cmds != value); gen_alter_cmds = value; } updateAlterCmdsStatus(); } bool PhysicalTable::isGenerateAlterCmds(void) { return(gen_alter_cmds); } void PhysicalTable::updateAlterCmdsStatus(void) { unsigned i; for(i=0; i < columns.size(); i++) columns[i]->setDeclaredInTable(!gen_alter_cmds); //Foreign keys are aways created as ALTER form for(i=0; i < constraints.size(); i++) constraints[i]->setDeclaredInTable(!gen_alter_cmds && dynamic_cast(constraints[i])->getConstraintType()!=ConstraintType::ForeignKey); } void PhysicalTable::setTableAttributes(unsigned def_type, bool incl_rel_added_objs) { QStringList part_keys_code; attributes[Attributes::GenAlterCmds]=(gen_alter_cmds ? Attributes::True : QString()); attributes[Attributes::AncestorTable]=QString(); attributes[Attributes::PartitionedTable]=QString(); attributes[Attributes::Tag]=QString(); attributes[Attributes::Partitioning]=~partitioning_type; attributes[Attributes::PartitionKey]=QString(); attributes[Attributes::PartitionBoundExpr]=part_bounding_expr; attributes[Attributes::Layer]=QString::number(layer); attributes[Attributes::Pagination]=(pagination_enabled ? Attributes::True : QString()); attributes[Attributes::CollapseMode]=QString::number(enum_cast(collapse_mode)); attributes[Attributes::AttribsPage]=(pagination_enabled ? QString::number(curr_page[AttribsSection]) : QString()); attributes[Attributes::ExtAttribsPage]=(pagination_enabled ? QString::number(curr_page[ExtAttribsSection]) : QString()); for(auto part_key : partition_keys) part_keys_code+=part_key.getCodeDefinition(def_type); if(def_type == SchemaParser::SqlDefinition) attributes[Attributes::PartitionKey]=part_keys_code.join(','); else attributes[Attributes::PartitionKey]=part_keys_code.join(' '); if(def_type==SchemaParser::SqlDefinition && partitioned_table) attributes[Attributes::PartitionedTable]=partitioned_table->getName(true); if(tag && def_type==SchemaParser::XmlDefinition) attributes[Attributes::Tag]=tag->getCodeDefinition(def_type, true); setColumnsAttribute(def_type, incl_rel_added_objs); setConstraintsAttribute(def_type); setAncestorTableAttribute(); if(def_type==SchemaParser::XmlDefinition) { setRelObjectsIndexesAttribute(); setPositionAttribute(); setFadedOutAttribute(); attributes[Attributes::InitialData]=initial_data; attributes[Attributes::MaxObjCount]=QString::number(static_cast(getMaxObjectCount() * 1.20)); } else attributes[Attributes::InitialData]=getInitialDataCommands(); } void PhysicalTable::operator = (PhysicalTable &table) { QString prev_name = this->getName(true); (*dynamic_cast(this))=dynamic_cast(table); this->layer = table.layer; this->col_indexes=table.col_indexes; this->constr_indexes=table.constr_indexes; this->partitioning_type=table.partitioning_type; this->initial_data=table.initial_data; this->partition_keys=table.partition_keys; PgSqlType::renameUserType(prev_name, this, this->getName(true)); } bool PhysicalTable::isReferRelationshipAddedObject(void) { vector::iterator itr, itr_end; ObjectType types[]={ ObjectType::Column, ObjectType::Constraint }; bool found=false; for(unsigned i=0; i < 2 && !found; i++) { itr=getObjectList(types[i])->begin(); itr_end=getObjectList(types[i])->end(); while(itr!=itr_end && !found) { found=(*itr)->isAddedByRelationship(); itr++; } } return(found); } bool PhysicalTable::isPartition(void) { return(partitioned_table != nullptr); } bool PhysicalTable::isPartitioned(void) { return(partitioning_type != BaseType::Null); } bool PhysicalTable::isPhysicalTable(ObjectType obj_type) { return(BaseTable::isBaseTable(obj_type) && obj_type != ObjectType::View); } void PhysicalTable::swapObjectsIndexes(ObjectType obj_type, unsigned idx1, unsigned idx2) { vector *obj_list=nullptr; vector::iterator itr1, itr2; TableObject *aux_obj=nullptr, *aux_obj1=nullptr; try { if(idx1!=idx2) { obj_list=getObjectList(obj_type); //Raises an error if both index is out of list bounds if(idx1 >= obj_list->size() && idx2 >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //If the idx1 is out of bound inserts the element idx2 at the list's begin else if(idx1 >= obj_list->size()) { aux_obj1=obj_list->front(); itr2=obj_list->begin() + idx2; aux_obj=(*itr2); obj_list->erase(itr2); obj_list->insert(obj_list->begin(), aux_obj); } //If the idx2 is out of bound inserts the element idx1 on the list's end else if(idx2 >= obj_list->size()) { itr1=obj_list->begin() + idx1; aux_obj=(*itr1); aux_obj1=obj_list->back(); obj_list->erase(itr1); obj_list->push_back(aux_obj); } else { aux_obj=obj_list->at(idx1); itr1=obj_list->begin() + idx1; itr2=obj_list->begin() + idx2; (*itr1)=aux_obj1=(*itr2); (*itr2)=aux_obj; } if(obj_type!=ObjectType::Column && obj_type!=ObjectType::Constraint) BaseObject::swapObjectsIds(aux_obj, aux_obj1, false); setCodeInvalidated(true); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void PhysicalTable::getColumnReferences(Column *column, vector &refs, bool exclusion_mode) { if(column && !column->isAddedByRelationship()) { unsigned count, i; Column *col=nullptr, *col1=nullptr; vector::iterator itr, itr_end; bool found=false; Constraint *constr=nullptr; Trigger *trig=nullptr; itr=constraints.begin(); itr_end=constraints.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !found))) { constr=dynamic_cast(*itr); itr++; col=constr->getColumn(column->getName(),true); col1=constr->getColumn(column->getName(),false); if((col && col==column) || (col1 && col1==column)) { found=true; refs.push_back(constr); } } itr=triggers.begin(); itr_end=triggers.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !found))) { trig=dynamic_cast(*itr); itr++; count=trig->getColumnCount(); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !found)); i++) { if(trig->getColumn(i)==column) { found=true; refs.push_back(trig); } } } } } vector PhysicalTable::getObjects(const vector &excl_types) { vector list; vector types=getChildObjectTypes(obj_type); for(auto type : types) { if(std::find(excl_types.begin(), excl_types.end(), type) != excl_types.end()) continue; list.insert(list.end(), getObjectList(type)->begin(), getObjectList(type)->end()) ; } return(list); } vector PhysicalTable::getPartitionKeys(void) { return(partition_keys); } void PhysicalTable::setCodeInvalidated(bool value) { vector types = getChildObjectTypes(obj_type); for(auto type : types) { for(auto &obj : *getObjectList(type)) obj->setCodeInvalidated(value); } BaseObject::setCodeInvalidated(value); } void PhysicalTable::setInitialData(const QString &value) { setCodeInvalidated(initial_data != value); initial_data = value; } QString PhysicalTable::getInitialData(void) { return(initial_data); } QString PhysicalTable::getInitialDataCommands(void) { QStringList buffer=initial_data.split(DataLineBreak); if(!buffer.isEmpty() && !buffer.at(0).isEmpty()) { QStringList col_names, col_values, commands, selected_cols; int curr_col=0; QList ignored_cols; col_names=(buffer.at(0)).split(DataSeparator); col_names.removeDuplicates(); buffer.removeFirst(); //Separating valid columns (selected) from the invalids (ignored) for(QString col_name : col_names) { if(getObjectIndex(col_name, ObjectType::Column) >= 0) selected_cols.append(col_name); else ignored_cols.append(curr_col); curr_col++; } for(QString buf_row : buffer) { curr_col=0; //Filtering the invalid columns' values for(QString value : buf_row.split(DataSeparator)) { if(ignored_cols.contains(curr_col)) continue; col_values.append(value); } commands.append(createInsertCommand(selected_cols, col_values)); col_values.clear(); } return(commands.join('\n')); } return(QString()); } QString PhysicalTable::createInsertCommand(const QStringList &col_names, const QStringList &values) { QString fmt_cmd, insert_cmd = QString("INSERT INTO %1 (%2) VALUES (%3);\n%4"); QStringList val_list, col_list; int curr_col=0; for(QString col_name : col_names) col_list.push_back(BaseObject::formatName(col_name)); for(QString value : values) { //Empty values as considered as DEFAULT if(value.isEmpty()) { value=QString("DEFAULT"); } //Unescaped values will not be enclosed in quotes else if(value.startsWith(PgModelerNs::UnescValueStart) && value.endsWith(PgModelerNs::UnescValueEnd)) { value.remove(0,1); value.remove(value.length()-1, 1); } //Quoting value else { value.replace(QString("\\") + PgModelerNs::UnescValueStart, PgModelerNs::UnescValueStart); value.replace(QString("\\") + PgModelerNs::UnescValueEnd, PgModelerNs::UnescValueEnd); value.replace(QString("\'"), QString("''")); value.replace(QChar(QChar::LineFeed), QString("\\n")); value=QString("E'") + value + QString("'"); } val_list.push_back(value); } if(!col_list.isEmpty() && !val_list.isEmpty()) { //If the set of values is greater than the set of columns it will be truncated if(val_list.size() > col_list.size()) val_list.erase(val_list.begin() + col_list.size(), val_list.end()); //If the set of columns is greater than the set of values than DEFAULT values will be provided else if(col_list.size() > val_list.size()) { for(curr_col = val_list.size(); curr_col < col_list.size(); curr_col++) val_list.append(QString("DEFAULT")); } fmt_cmd=insert_cmd.arg(getSignature()).arg(col_list.join(", ")) .arg(val_list.join(", ")).arg(Attributes::DdlEndToken); } return(fmt_cmd); } void PhysicalTable::setObjectListsCapacity(unsigned capacity) { if(capacity < DefMaxObjectCount || capacity > DefMaxObjectCount * 10) capacity = DefMaxObjectCount; for(auto &type : getChildObjectTypes(obj_type)) getObjectList(type)->reserve(type != ObjectType::Column ? capacity/2 : capacity); } unsigned PhysicalTable::getMaxObjectCount(void) { unsigned count = 0, max = 0; for(auto &type : getChildObjectTypes(obj_type)) { count = getObjectList(type)->size(); if(count > max) max = count; } return(max); } QString PhysicalTable::getDataDictionary(bool splitted, attribs_map extra_attribs) { Column *column = nullptr; Constraint *constr = nullptr; attribs_map attribs, aux_attrs; QStringList tab_names, col_names; QString dict_files_root = GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::DataDictSchemaDir + GlobalAttributes::DirSeparator, tab_dict_file = dict_files_root + Attributes::Table + GlobalAttributes::SchemaExt, col_dict_file = dict_files_root + Attributes::Column + GlobalAttributes::SchemaExt, constr_dict_file = dict_files_root + Attributes::Constraint + GlobalAttributes::SchemaExt, link_dict_file = dict_files_root + Attributes::Link + GlobalAttributes::SchemaExt, check_mark = QString("✓"); attribs.insert(extra_attribs.begin(), extra_attribs.end()); attribs[Attributes::Type] = getTypeName(); attribs[Attributes::TypeClass] = getSchemaName(); attribs[Attributes::Splitted] = splitted ? Attributes::True : QString(); attribs[Attributes::Name] = obj_name; attribs[Attributes::Schema] = schema ? schema->getName() : QString(); attribs[Attributes::Comment] = comment; attribs[Attributes::Columns] = QString(); attribs[Attributes::Constraints] = QString(); aux_attrs[Attributes::Splitted] = attribs[Attributes::Splitted]; // Gathering the acestor table names for(auto &tab : ancestor_tables) { aux_attrs[Attributes::Name] = tab->getSignature().remove(QChar('"')); tab_names.push_back(schparser.getCodeDefinition(link_dict_file, aux_attrs)); } attribs[Attributes::Inherit] = tab_names.join(", "); tab_names.clear(); attribs[Attributes::PartitionedTable] = QString(); if(partitioned_table) { aux_attrs[Attributes::Name] = partitioned_table->getSignature().remove(QChar('"')); attribs[Attributes::PartitionedTable] = schparser.getCodeDefinition(link_dict_file, aux_attrs); } // Gathering the patition table names for(auto &tab : partition_tables) { aux_attrs[Attributes::Name] = tab->getSignature().remove(QChar('"')); tab_names.push_back(schparser.getCodeDefinition(link_dict_file, aux_attrs)); } attribs[Attributes::PartitionTables] = tab_names.join(", "); for(auto &obj : columns) { column = dynamic_cast(obj); aux_attrs[Attributes::Parent] = getSchemaName(); aux_attrs[Attributes::Name] = column->getName(); aux_attrs[Attributes::Type] = *column->getType(); aux_attrs[Attributes::DefaultValue] = column->getDefaultValue(); aux_attrs[Attributes::Comment] = column->getComment(); aux_attrs[Attributes::NotNull] = column->isNotNull() ? check_mark : QString(); aux_attrs[Attributes::PkConstr] = isConstraintRefColumn(column, ConstraintType::PrimaryKey) ? check_mark : QString(); aux_attrs[Attributes::UqConstr] = isConstraintRefColumn(column, ConstraintType::Unique) ? check_mark : QString(); aux_attrs[Attributes::FkConstr] = isConstraintRefColumn(column, ConstraintType::ForeignKey) ? check_mark : QString(); schparser.ignoreEmptyAttributes(true); attribs[Attributes::Columns] += schparser.getCodeDefinition(col_dict_file, aux_attrs); aux_attrs.clear(); } for(auto &obj : constraints) { constr = dynamic_cast(obj); aux_attrs[Attributes::Splitted] = attribs[Attributes::Splitted]; aux_attrs[Attributes::Name] = constr->getName(); aux_attrs[Attributes::Type] = ~constr->getConstraintType(); aux_attrs[Attributes::Comment] = constr->getComment(); aux_attrs[Attributes::RefTable] = constr->getReferencedTable() ? constr->getReferencedTable()->getSignature().remove(QChar('"')) : QString(); // Retrieving the columns that composes the constraint for(auto &col : constr->getColumns(Constraint::SourceCols)) col_names.push_back(col->getName()); aux_attrs[Attributes::Columns] = col_names.join(", "); col_names.clear(); schparser.ignoreEmptyAttributes(true); attribs[Attributes::Constraints] += schparser.getCodeDefinition(constr_dict_file, aux_attrs); aux_attrs.clear(); } schparser.ignoreEmptyAttributes(true); return(schparser.getCodeDefinition(tab_dict_file, attribs)); } pgmodeler-0.9.2/libpgmodeler/src/physicaltable.h000066400000000000000000000355041360462764600217560ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the basic attributes and operations shared by tables and foreign tables. */ #ifndef PHYSICAL_TABLE_H #define PHYSICAL_TABLE_H #include "basegraphicobject.h" #include "basetable.h" #include "column.h" #include "constraint.h" #include "trigger.h" #include "function.h" #include "role.h" #include "partitionkey.h" #include "copyoptions.h" #include class PhysicalTable: public BaseTable { protected: //! \brief Specifies the table from which columns are copied PhysicalTable *copy_table; //! \brief Specifies the copy table options CopyOptions copy_op; /*! \brief Stores the initial data of the table in CSV like form. This will produce a set of INSERT commands that is appended to the table's SQL definition */ QString initial_data; //! \brief The partition bounding expression QString part_bounding_expr; //! \brief Vectors that store basic table attributes vector columns; vector constraints; vector triggers; //! \brief Stores the tables that 'this' object inherits attributes vector ancestor_tables; //! \brief Stores the tables that 'this' object has as its partitions vector partition_tables; //! \brief Stores the partition keys of the table partitioning being used vector partition_keys; //! \brief Stores the table which this one is partition of PhysicalTable *partitioned_table; /*! \brief Indicates that constraints and columns are generated in for of ALTER commands. When true this will cause constraints and columsn to be created in a separated command outside tha table's declaration */ bool gen_alter_cmds; //! \brief Stores the relationship added column / constraints indexes map col_indexes, constr_indexes; //! \brief The partitioning mode/type used by the table PartitioningType partitioning_type; /*! \brief Gets one table ancestor (ObjectType::Table) or copy (ObjectType::ObjBaseTable) using its name and stores the index of the found object on parameter 'obj_idx' */ BaseObject *getObject(const QString &name, ObjectType obj_type, int &obj_idx); //! \brief The methods below generates the table attributes used by the SchemaParser void setColumnsAttribute(unsigned def_type, bool incl_rel_added_cols); void setConstraintsAttribute(unsigned def_type); void setCommentAttribute(TableObject *tab_obj); void setAncestorTableAttribute(void); void setRelObjectsIndexesAttribute(void); //! \brief Adds an ancestor table void addAncestorTable(PhysicalTable *tab, int idx=-1); //! \brief Adds a partition table void addPartitionTable(PhysicalTable *tab); //! \brief Removes a partition table void removePartitionTable(PhysicalTable *tab); /*! \brief Returns the index of the partition table. If the * compare_names is true then the search will compare the names if * the object itself is not present in the list of partitions */ int getPartitionTableIndex(PhysicalTable *tab, bool compare_names); //! \brief Removes an acestor table using its name void removeAncestorTable(const QString &name); //! \brief Removes an acestor table using its index void removeAncestorTable(unsigned idx); /*! \brief Updates the "decl_in_table" status for columns/constraints indicating if ALTER commands must be generated or not */ void updateAlterCmdsStatus(void); void saveRelObjectsIndexes(ObjectType obj_type); void restoreRelObjectsIndexes(ObjectType obj_type); //! \brief Create an insert command from a list of columns and the values. QString createInsertCommand(const QStringList &col_names, const QStringList &values); //! \brief Performs the destruction of all children objects and internal lists clearing void destroyObjects(void); public: //! \brief Default char for data separator in initial-data tag static const QString DataSeparator, //! \brief Default char for data line break in initial-data tag DataLineBreak; PhysicalTable(void); ~PhysicalTable(void){} //! \brief Returns true if the provided table is considered a physical table (Table, ForeignTable, PhysicalTable) static bool isPhysicalTable(ObjectType obj_type); //! \brief Defines the table's name. This method updates the type named after the table void setName(const QString &name); //! \brief Defines the table's schema. This method updates the type named after the table void setSchema(BaseObject *schema); //! \brief Configures the copy table void setCopyTable(PhysicalTable *tab); //! \brief Configures the copy table options void setCopyTableOptions(CopyOptions copy_op); //! \brief Returns the copy table PhysicalTable *getCopyTable(void); //! \brief Get the copy table options CopyOptions getCopyTableOptions(void); //! \brief Defines if the partitioning type of the table virtual void setPartitioningType(PartitioningType part_type); //! \brief Returns the current partitioning type defined for the table PartitioningType getPartitioningType(void); //! \brief Returns the partitioned table which this table is a partition of PhysicalTable *getPartitionedTable(void); //! \brief Adds an object to the table. It can be inserted at a specified index 'obj_idx'. void addObject(BaseObject *obj, int obj_idx=-1); //! \brief Gets a object from table through its index and type BaseObject *getObject(unsigned obj_idx, ObjectType obj_type); //! \brief Gets a object from table through its name and type BaseObject *getObject(const QString &name, ObjectType obj_type); //! \brief Removes a object from table through its index and type void removeObject(unsigned obj_idx, ObjectType obj_type); //! \brief Removes a object from table through its name and type void removeObject(const QString &name, ObjectType obj_type); //! \brief Removes the specified object from table void removeObject(BaseObject *obj); //! \brief Adds a column to table (optionally the user can add the object at the specified index 'idx') void addColumn(Column *col, int idx=-1); //! \brief Adds a constraint to table (optionally the user can add the object at the specified index 'idx') void addConstraint(Constraint *constr, int idx=-1); //! \brief Adds a trigger to table (optionally the user can add the object at the specified index 'idx') void addTrigger(Trigger *trig, int idx=-1); //! \brief Adds a partition table void setPartionedTable(PhysicalTable *table); //! \brief Defines the partition bounding expression void setPartitionBoundingExpr(const QString part_bound_expr); //! \brief Returns the partition bounding expression QString getPartitionBoundingExpr(void); //! \brief Returns the partition tables vector getPartionTables(void); //! \brief Returs if the provided table is amongst the partitions bool isPartitionTableExists(PhysicalTable *table, bool compare_names); //! \brief Adds partition keys to the table. This method overrides the currently configure partition keys. void addPartitionKeys(vector &part_keys); //! \brief Remove all partition keys configured for the table void removePartitionKeys(void); /*! \brief Gets a column through its name. The boolean parameter is used to search columns referencing their old names */ Column *getColumn(const QString &name, bool ref_old_name=false); //! \brief Gets a column through its index Column *getColumn(unsigned idx); //! \brief Gets a constraint through its name. Constraint *getConstraint(const QString &name); //! \brief Gets a constraint through its index Constraint *getConstraint(unsigned idx); //! \brief Gets a trigger through its name. Trigger *getTrigger(const QString &name); //! \brief Gets a trigger through its index Trigger *getTrigger(unsigned idx); //! \brief Gets a ancestor table through its name PhysicalTable *getAncestorTable(const QString &name); //! \brief Gets a ancestor table through its index PhysicalTable *getAncestorTable(unsigned idx); //! \brief Returns the primary key of the table. Returns nullptr when it doesn't exists Constraint *getPrimaryKey(void); //! \brief Gets the column count unsigned getColumnCount(void); //! \brief Gets the constraint count unsigned getConstraintCount(void); //! \brief Gets the trigger count unsigned getTriggerCount(void); //! \brief Gets the ancestor table count unsigned getAncestorTableCount(void); /*! \brief Gets the the count for the specified object type. The boolean parameter indicates that objects added by relationship must be counted */ unsigned getObjectCount(ObjectType obj_type, bool inc_added_by_rel=true); //! \brief Removes a column through its name void removeColumn(const QString &name); //! \brief Removes a column through its index void removeColumn(unsigned idx); //! \brief Removes a constraint through its name void removeConstraint(const QString &name); //! \brief Removes a constraint through its index void removeConstraint(unsigned idx); //! \brief Removes a trigger through its name void removeTrigger(const QString &name); //! \brief Removes a trigger through its index void removeTrigger(unsigned idx); //! \brief Returns the SQL / XML definition for table virtual QString getCodeDefinition(unsigned def_type) = 0; //! \brief Gets the object index using its name and type int getObjectIndex(const QString &name, ObjectType obj_type); /*! \brief Returns the index for the specified table object. If the object specified on the parameter owns to another table other than 'this' then the name of the objects are compared instead of the memory address */ int getObjectIndex(BaseObject *obj); //! \brief Returns the children objects of the table excluding the provided children types vector getObjects(const vector &excl_types = {}); //! \brief Returns all the partition keys used by the table vector getPartitionKeys(void); //! \brief Protects the table and its aggregated objects against modification void setProtected(bool value); //! \brief Toggles the generation of columns and constraints in form of ALTER commands void setGenerateAlterCmds(bool value); //! \brief Returns the current status of generation of ALTER commands for columns and constraints bool isGenerateAlterCmds(void); /*! \brief Returns if the specified column is referenced by one of the constraints on table. The user must specify the constraint type */ bool isConstraintRefColumn(Column *column, ConstraintType constr_type); /*! \brief Returns if the specified column is referenced by one of the constraints on table. The user must specify the constraint type */ bool isPartitionKeyRefColumn(Column *column); //! \brief Swaps two objects position void swapObjectsIndexes(ObjectType obj_type, unsigned idx1, unsigned idx2); //! \brief Returns if the table references objects added by relationship bool isReferRelationshipAddedObject(void); //! \brief Returns if the table is a partition of another table bool isPartition(void); //! \brief Returns if the table is a partitioned. This is the same as getPartitioningType() != BaseType::null bool isPartitioned(void); //! \brief Copy the attributes between two tables void operator = (PhysicalTable &table); //! \brief Returns the specified object type list. Returns null if an invalid object type is provided virtual vector *getObjectList(ObjectType obj_type); /*! \brief Gets objects which refer to object of the parameter (directly or indirectly) and stores them in a vector. The 'exclusion_mode' is used to speed up the execution of the method when it is used to validate the deletion of the object, getting only the first reference to the object candidate for deletion. To get ALL references to the object must be specified as 'false' the parameter 'exclusion_mode'. */ void getColumnReferences(Column *column, vector &refs, bool exclusion_mode=false); //! \brief Save the current index of the objects created by relationship void saveRelObjectsIndexes(void); /*! \brief Restore the position of the objects created by relationships. This method must be used with caution since it generate a new list of object replacing the original inside the table. Also this method can be slow in huge tables */ void restoreRelObjectsIndexes(void); //! \brief Creates custom index from rel. created object using a name and index vectors as input. void setRelObjectsIndexes(const vector &obj_names, const vector &idxs, ObjectType obj_type); //! \brief Invalidates the cached code forcing the generation of both SQL and XML void setCodeInvalidated(bool value); /*! \brief Returns the alter definition by comparing the this table against the one provided via parameter * This is a pure virtual method and must be implemented by children classes */ virtual QString getAlterDefinition(BaseObject *object) = 0; /*! \brief Defines an initial set of data for the table in a CSV-like buffer. In order to separate columns and values use the DATA_SEPARATOR char and to separate rows use the DATA_LINE_BREAK */ void setInitialData(const QString &value); //! \brief Returns the table's initial data in raw format QString getInitialData(void); /*! \brief Translate the CSV-like initial data to a set of INSERT commands. In invalid columns exist in the buffer they will be rejected when generating the commands */ QString getInitialDataCommands(void); /*! \brief Generates the table's SQL code considering adding the relationship added object or not. * Note if the method is called with incl_rel_added_objs = true it can produce an SQL/XML code * that does not reflect the real semantics of the table. So take care to use this method and always * invalidate the tables code (see setCodeInvalidated()) after retrieving the resulting code */ void setTableAttributes(unsigned def_type, bool incl_rel_added_objs); virtual void setObjectListsCapacity(unsigned capacity); virtual unsigned getMaxObjectCount(void); virtual QString getDataDictionary(bool splitted, attribs_map extra_attribs = {}); friend class Relationship; friend class OperationList; }; #endif pgmodeler-0.9.2/libpgmodeler/src/policy.cpp000066400000000000000000000115411360462764600207570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "policy.h" Policy::Policy(void) : TableObject() { obj_type=ObjectType::Policy; permissive = false; policy_cmd = PolicyCmdType::All; attributes[Attributes::Permissive] = QString(); attributes[Attributes::Command] = QString(); attributes[Attributes::UsingExp] = QString(); attributes[Attributes::CheckExp] = QString(); attributes[Attributes::Roles] = QString(); } void Policy::setParentTable(BaseTable *table) { if(table && table->getObjectType() != ObjectType::Table) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidObjectType) .arg(this->obj_name) .arg(this->getTypeName()) .arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::AsgInvalidObjectType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } TableObject::setParentTable(table); } void Policy::setPermissive(bool value) { setCodeInvalidated(permissive != value); permissive = value; } bool Policy::isPermissive(void) { return(permissive); } void Policy::setPolicyCommand(PolicyCmdType cmd) { setCodeInvalidated(policy_cmd != cmd); policy_cmd = cmd; } PolicyCmdType Policy::getPolicyCommand(void) { return(policy_cmd); } void Policy::setUsingExpression(const QString &expr) { setCodeInvalidated(using_expr != expr); using_expr = expr; } QString Policy::getUsingExpression(void) { return(using_expr); } void Policy::setCheckExpression(const QString &expr) { setCodeInvalidated(check_expr != expr); check_expr = expr; } QString Policy::getCheckExpression(void) { return(check_expr); } void Policy::addRole(Role *role) { if(!role) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(std::find(roles.begin(), roles.end(), role) == roles.end()) roles.push_back(role); } void Policy::removeRoles(void) { roles.clear(); setCodeInvalidated(true); } vector Policy::getRoles(void) { return(roles); } QString Policy::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); QStringList rol_names; if(getParentTable()) attributes[Attributes::Table]=getParentTable()->getName(true); attributes[Attributes::Command] = ~policy_cmd; for(auto role : roles) rol_names.append(role->getName(true)); attributes[Attributes::Permissive] = (permissive ? Attributes::True : QString()); attributes[Attributes::UsingExp] = using_expr; attributes[Attributes::CheckExp] = check_expr; attributes[Attributes::Roles] = rol_names.join(QString(", ")); return(BaseObject::__getCodeDefinition(def_type)); } QString Policy::getSignature(bool format) { if(!getParentTable()) return(BaseObject::getSignature(format)); return(QString("%1 ON %2").arg(this->getName(format)).arg(getParentTable()->getSignature(true))); } QString Policy::getAlterDefinition(BaseObject *object) { Policy *policy=dynamic_cast(object); if(!policy) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { QStringList rol_names, aux_rol_names; attribs_map attribs; attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); if(this->using_expr.simplified() != policy->using_expr.simplified()) attribs[Attributes::UsingExp] = policy->using_expr; if(this->check_expr.simplified() != policy->check_expr.simplified()) attribs[Attributes::CheckExp] = policy->check_expr; for(auto role : this->roles) rol_names.append(role->getName(true)); for(auto role : policy->roles) aux_rol_names.append(role->getName(true)); rol_names.sort(); aux_rol_names.sort(); if(!rol_names.isEmpty() && aux_rol_names.isEmpty()) attribs[Attributes::Roles] = Attributes::Unset; else if(rol_names.join(QString(", ")) != aux_rol_names.join(QString(", "))) attribs[Attributes::Roles] = aux_rol_names.join(QString(", ")); copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } bool Policy::isRoleExists(Role *role) { if(!role) return(false); return(std::find(roles.begin(), roles.end(), role) != roles.end()); } pgmodeler-0.9.2/libpgmodeler/src/policy.h000066400000000000000000000060661360462764600204320ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Policy \brief Implements the operations to manipulate row level security (RLS). */ #ifndef POLICY_H #define POLICY_H #include "tableobject.h" #include "role.h" class Policy : public TableObject { private: /*! \brief Roles that has permissions over the object. This vector can be empty indicating that all roles on the cluster has permission over the object. */ vector roles; //! \brief Defines the USING expression applied to queries referencing the table which policy is applied QString using_expr, //! \brief Defines the CHECK expression applied to INSERT/UPDATE queries check_expr; /*! \brief Indicates if the policy is permissive. Permissive policies are combined using OR operator by PostgreSQL and reducing the set of records accessed by a query. When the policy is restrictive the policies are combined using AND. By default, a policy is permissive. */ bool permissive; PolicyCmdType policy_cmd; public: Policy(void); virtual void setParentTable(BaseTable *table) final; //! \brief Defines if the the policy is permissive or restrictive void setPermissive(bool value); //! \brief Returns if the policy is permissive or restrictive bool isPermissive(void); //! \brief Defines the command affected by the policy. void setPolicyCommand(PolicyCmdType cmd); //! \brief Returns the policy affected command PolicyCmdType getPolicyCommand(void); //! \brief Defines the USING expresion of the policy void setUsingExpression(const QString &expr); //! \brief Returns the USING expresion of the policy QString getUsingExpression(void); //! \brief Defines the CHECK expresion of the policy void setCheckExpression(const QString &expr); //! \brief Returns the CHECK expresion of the policy QString getCheckExpression(void); //! \brief Adds a role that will have privileges over the object void addRole(Role *role); //! \brief Remove all roles from the policy void removeRoles(void); //! \brief Returns all the roles that is used by the policy vector getRoles(void); //! \brief Returns the SQL / XML definition for the policy virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool format=false) final; virtual QString getAlterDefinition(BaseObject *object) final; bool isRoleExists(Role *role); }; #endif pgmodeler-0.9.2/libpgmodeler/src/reference.cpp000066400000000000000000000221241360462764600214150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "reference.h" Reference::Reference(void) { this->table=nullptr; this->column=nullptr; this->is_def_expr=false; } Reference::Reference(PhysicalTable *table, Column *column, const QString &tab_alias, const QString &col_alias) { //Raises an error if the table is not allocated if(!table) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the table/column alias has an invalid name else if((!tab_alias.isEmpty() && !BaseObject::isValidName(tab_alias)) || (!col_alias.isEmpty() && !BaseObject::isValidName(col_alias))) throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the column parent table differs from the passed table else if(column && column->getParentTable()!=table) throw Exception(ErrorCode::AsgObjectBelongsAnotherTable ,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->table=table; this->column=column; this->alias=tab_alias; this->column_alias=col_alias; this->is_def_expr=false; } Reference::Reference(const QString &expression, const QString &expr_alias) { //Raises an error if the user try to create an reference using an empty expression if(expression.isEmpty()) throw Exception(ErrorCode::AsgInvalidExpressionObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the expression alias has an invalid name else if(!expr_alias.isEmpty() && !BaseObject::isValidName(expr_alias)) throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); table=nullptr; column=nullptr; alias=expr_alias; this->expression=expression; this->is_def_expr=false; } void Reference::setDefinitionExpression(bool value) { is_def_expr = value; if(!value) clearReferencedTables(); } void Reference::addReferencedTable(PhysicalTable *ref_table) { if(!ref_table) return; if(std::find(ref_tables.begin(), ref_tables.end(), ref_table) == ref_tables.end()) ref_tables.push_back(ref_table); } int Reference::getReferencedTableIndex(PhysicalTable *ref_table) { int idx = -1; vector::iterator itr = std::find(ref_tables.begin(), ref_tables.end(), ref_table); if(itr != ref_tables.end()) idx = itr - ref_tables.begin(); return(idx); } void Reference::clearReferencedTables(void) { ref_tables.clear(); } vector Reference::getReferencedTables(void) { return(ref_tables); } bool Reference::isDefinitionExpression(void) { return(is_def_expr); } void Reference::addColumn(const QString &name, PgSqlType type, const QString &alias) { QString aux_name = name; if(aux_name.startsWith(QChar('\"')) && aux_name.endsWith(QChar('\"'))) { aux_name.remove(0, 1); aux_name.remove(aux_name.length(), 1); } // Validating the column name if(!BaseObject::isValidName(name)) { if(aux_name.isEmpty()) throw Exception(ErrorCode::AsgEmptyNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(aux_name.size() > BaseObject::ObjectNameMaxLength) throw Exception(ErrorCode::AsgLongNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else throw Exception(ErrorCode::AsgInvalidNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } // Checking if the column already exists for(auto &col : columns) { if(col.name == name) throw Exception(ErrorCode::InsDuplicatedElement,__PRETTY_FUNCTION__,__FILE__,__LINE__); } columns.push_back(SimpleColumn(name, *type, alias)); } void Reference::addColumn(Column *col) { if(!col) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); addColumn(col->getName(), col->getType(), col->getAlias()); } void Reference::removeColumns(void) { columns.clear(); } vector Reference::getColumns(void) { return(columns); } PhysicalTable *Reference::getTable(void) { return(table); } Column *Reference::getColumn(void) { return(column); } QString Reference::getColumnAlias(void) { return(column_alias); } QString Reference::getAlias(void) { return(alias); } QString Reference::getExpression(void) { return(expression); } unsigned Reference::getReferenceType(void) { if(expression.isEmpty()) return(ReferColumn); else return(ReferExpression); } void Reference::setReferenceAlias(const QString &alias) { if(alias.size() > BaseObject::ObjectNameMaxLength) throw Exception(ErrorCode::AsgLongNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); ref_alias = alias; } QString Reference::getReferenceAlias(void) { return(ref_alias); } QString Reference::getSQLDefinition(unsigned sql_type) { QString sql_def, tab_name; unsigned refer_type; refer_type=getReferenceType(); //Case the reference is between the SELECT-FROM keywords if(sql_type==SqlReferSelect) { //Case the reference is linked to a column if(refer_type==ReferColumn) { /* Generated SQL definition: [TABLE_ALIAS.]{COLUMN_NAME | *} [AS COLUMN_ALIAS] */ if(!alias.isEmpty()) tab_name=BaseObject::formatName(alias) + QString("."); else tab_name=table->getSignature() + QString("."); /* Case there is no column definede the default behavior is consider all the table columns (e.g. table.*) */ if(!column) sql_def=tab_name + QString("*"); else { //Case there is an column concatenates its name to the code definition sql_def=tab_name + column->getName(true); //Case there is a column alias concatenate it to the definition if(!column_alias.isEmpty()) sql_def+=QString(" AS ") + BaseObject::formatName(column_alias); } } //Case the reference is linked to an expression else { /* Generated SQL definition: {expression} [AS ALIAS] */ sql_def=expression; if(!alias.isEmpty()) sql_def+=QString(" AS ") + BaseObject::formatName(alias); } sql_def+=QString(",\n"); } //Case the reference is between the FROM-[JOIN | WHERE] keywords else if(sql_type==SqlReferFrom) { /* Case the reference is linked to a column only the table name is used. For expression the complete code is used thus the generated code is: ... FROM {TABLE_NAME} [AS ALIAS] or ... FROM {EXPRESSION} */ if(refer_type==ReferColumn) { sql_def+=table->getName(true); if(!alias.isEmpty()) sql_def+=QString(" AS ") + BaseObject::formatName(alias); } else sql_def=expression; sql_def+=QString(",\n"); } //Case the reference is after [JOIN | WHERE] keywords else { //Case the column is allocated if(refer_type==ReferColumn && column) { /* Generated SQL definition: ... WHERE {TABLE_NAME | ALIAS}.{COLUMN_NAME} */ if(alias.isEmpty()) sql_def=table->getName(true); else sql_def=BaseObject::formatName(alias); sql_def+=QString("."); if(column) sql_def+=column->getName(true); } else if(refer_type==ReferExpression) sql_def=expression; } sql_def=QString(" ") + sql_def; return(sql_def); } QString Reference::getXMLDefinition(void) { attribs_map attribs, aux_attribs; SchemaParser schparser; Column col_aux; QStringList ref_tab_names; attribs[Attributes::Table]=QString(); attribs[Attributes::Column]=QString(); if(table) attribs[Attributes::Table]=table->getName(true); if(column) attribs[Attributes::Column]=column->getName(); attribs[Attributes::RefAlias]=ref_alias; attribs[Attributes::Expression]=expression; attribs[Attributes::Alias]=alias; attribs[Attributes::ColumnAlias]=column_alias; attribs[Attributes::Columns]=QString(); attribs[Attributes::RefTables]=QString(); for(auto &col : columns) { col_aux.setName(col.name); col_aux.setType(PgSqlType::parseString(col.type)); col_aux.setAlias(col.alias); attribs[Attributes::Columns]+=col_aux.getCodeDefinition(SchemaParser::XmlDefinition); } if(is_def_expr) { for(auto &tab : ref_tables) { aux_attribs[Attributes::Name] = tab->getSignature(); attribs[Attributes::RefTables] += schparser.getCodeDefinition(Attributes::RefTableTag, aux_attribs, SchemaParser::XmlDefinition); } } return(schparser.getCodeDefinition(Attributes::Reference, attribs, SchemaParser::XmlDefinition)); } bool Reference::operator == (Reference &refer) { unsigned ref_type; ref_type=this->getReferenceType(); if(ref_type==refer.getReferenceType()) { if(ref_type==ReferColumn) { return(this->table==refer.table && this->column==refer.column && this->alias==refer.alias && this->column_alias==refer.column_alias); } else { return(this->expression==refer.expression && this->alias==refer.alias && this->is_def_expr==refer.is_def_expr); } } else return(false); } pgmodeler-0.9.2/libpgmodeler/src/reference.h000066400000000000000000000121021360462764600210550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Reference \brief This auxiliary class is used to define SQL/XML for views \note Creation date: 05/09/2008 */ #ifndef REFERENCE_H #define REFERENCE_H #include "table.h" #include "schema.h" /*! \brief This simple struct acts like a rudimentary column used by Reference and Views to represent columns * Note that, as intended, the struct expects that all received values are validated since they are immutable */ struct SimpleColumn { QString name, type, alias; SimpleColumn(const QString &_name, const QString &_type, const QString &_alias) : name(_name), type(_type), alias(_alias) {} }; class Reference { private: //! \brief Stores the table used by the reference PhysicalTable *table; //! \brief Stores the column used by the reference Column *column; //! \brief Stores the expression that defines one reference QString expression, //! \brief Stores the alias to the expression or table alias, //! \brief Stores only the alias for the column column_alias, //! \brief Stores the alias for the reference. This text will be displayed when the view is being show in compact mode ref_alias; //! \brief Indicates if the expression is used as entire view definition bool is_def_expr; /*! \brief Stores the columns that the reference (when being an expression [is_def_expr]) generates. * These columns are used when drawing a view and that has only on definition expression. * By having columns, instead of drawing the expression as a column of the view, the ones in * this vector are displayed */ vector columns; /*! \brief Stores the tables that the reference object is using within the expression which defines the view * when is_def_expr is set. These tables are used to hint the user which tables the view is using. */ vector ref_tables; public: //! \brief Constants used to define the reference type static constexpr unsigned ReferColumn=0, //! \brief The reference is based on a table column ReferExpression=1; //! \brief The reference is based on an expression //! \brief Constants used on the view code generation static constexpr unsigned SqlReferWhere=1, SqlReferSelect=2, SqlReferFrom=4, SqlReferEndExpr=8, SqlViewDefinition=16; Reference(void); //! \brief Creates a reference based on a table column Reference(PhysicalTable *table, Column *column, const QString &tab_alias, const QString &col_alias); //! \brief Creates a reference based on a expression Reference(const QString &expression, const QString &expr_alias); /*! \brief Changes the behavior of the expression. Calling this method will cause the reference to be used as the entire view SQL definition */ void setDefinitionExpression(bool value); void addReferencedTable(PhysicalTable *ref_table); int getReferencedTableIndex(PhysicalTable *ref_table); void clearReferencedTables(void); vector getReferencedTables(void); //! \brief Gets the referenced table PhysicalTable *getTable(void); //! \brief Gets the referenced column Column *getColumn(void); //! \brief Returns the alias for the referenced column QString getColumnAlias(void); //! \brief Returs the reference for the table or expression QString getAlias(void); //! \brief Returns the expression for the reference QString getExpression(void); //! \brief Returns the reference typ (see REFER_??? constants) unsigned getReferenceType(void); void setReferenceAlias(const QString &alias); QString getReferenceAlias(void); //! \brief Returns the SQL code definition QString getSQLDefinition(unsigned sql_type); //! \brief Returns the XML code definition QString getXMLDefinition(void); //! \brief Indicates if the reference when used as expression defines the entire view (raw sql definition) bool isDefinitionExpression(void); //! \brief Adds a column as being generated by the reference (if it is an expression) void addColumn(const QString &name, PgSqlType type, const QString &alias); void addColumn(Column *col); //! \brief Clears the columns generated by the expression void removeColumns(void); //! \brief Returns the columns which the reference generates vector getColumns(void); /*! \brief Compare the attributes of two references returning true when they have the same values */ bool operator == (Reference &refer); }; #endif pgmodeler-0.9.2/libpgmodeler/src/relationship.cpp000066400000000000000000002552601360462764600221710ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "relationship.h" #include "pgmodelerns.h" #include const QString Relationship::SuffixSeparator=QString("_"); const QString Relationship::SrcTabToken=QString("{st}"); const QString Relationship::DstTabToken=QString("{dt}"); const QString Relationship::GenTabToken=QString("{gt}"); const QString Relationship::SrcColToken=QString("{sc}"); constexpr unsigned Relationship::SrcColPattern; constexpr unsigned Relationship::DstColPattern; constexpr unsigned Relationship::PkPattern; constexpr unsigned Relationship::UqPattern; constexpr unsigned Relationship::SrcFkPattern; constexpr unsigned Relationship::DstFkPattern; constexpr unsigned Relationship::PkColPattern; Relationship::Relationship(Relationship *rel) : BaseRelationship(rel) { if(!rel) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); (*(this))=(*rel); } Relationship::Relationship(unsigned rel_type, PhysicalTable *src_tab, PhysicalTable *dst_tab, bool src_mdtry, bool dst_mdtry, bool identifier, bool deferrable, DeferralType deferral_type, ActionType fk_del_act, ActionType fk_upd_act, CopyOptions copy_op) : BaseRelationship(rel_type, src_tab, dst_tab, src_mdtry, dst_mdtry) { try { obj_type=ObjectType::Relationship; QString str_aux; /* Raises an error if the user tries to create a relationship (1-1, 1-n, n-n or copy) * if any involved table is a foreign table. Foreign tables can participate only * inheritance and partitioning relationships */ if((rel_type!=RelationshipGen && rel_type!=RelationshipPart && rel_type!=RelationshipDep) && (src_tab->getObjectType() == ObjectType::ForeignTable || dst_tab->getObjectType() == ObjectType::ForeignTable)) throw Exception(Exception::getErrorMessage(ErrorCode::InvRelTypeForeignTable) .arg(obj_name) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)), ErrorCode::InvRelTypeForeignTable,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the user tries to create a copy relation in which the receiver table * is a foreign table. In case of creating a copy relationship between a table and a foreign table * the receiver must be a table and the reference a foreign table */ if(rel_type == RelationshipDep && src_tab->getObjectType() == ObjectType::ForeignTable) throw Exception(Exception::getErrorMessage(ErrorCode::InvCopyRelForeignTable) .arg(obj_name) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)), ErrorCode::InvCopyRelForeignTable,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the user tries to create a relationship which some table doesn't has a primary key */ if(((rel_type==Relationship11 || rel_type==Relationship1n) && !this->getReferenceTable()->getPrimaryKey()) || (rel_type==RelationshipNn && (!src_tab->getPrimaryKey() || !dst_tab->getPrimaryKey()))) throw Exception(Exception::getErrorMessage(ErrorCode::InvLinkTablesNoPrimaryKey) .arg(obj_name) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)), ErrorCode::InvLinkTablesNoPrimaryKey,__PRETTY_FUNCTION__,__FILE__,__LINE__); // Raises an error if the user tries to create another copy relationship if the table already copies another table if(rel_type==RelationshipDep && src_tab->getCopyTable()) throw Exception(Exception::getErrorMessage(ErrorCode::InvCopyRelTableDefined) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)) .arg(dynamic_cast(src_tab)->getCopyTable()->getName(true)), ErrorCode::InvCopyRelTableDefined,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* If the relationship is partitioning the destination table (partitioned) shoud have * a partitioning type defined otherwise and error is raised */ if(rel_type == RelationshipPart && !dst_tab->isPartitioned()) throw Exception(Exception::getErrorMessage(ErrorCode::InvPartitioningTypePartRel) .arg(src_tab->getSignature()).arg(dst_tab->getSignature()), ErrorCode::InvPartitioningTypePartRel, __PRETTY_FUNCTION__,__FILE__,__LINE__); // Raises an error if the user tries to create a partitioning relationship where one of the tables are already a partition table if(rel_type==RelationshipPart && src_tab->getPartitionedTable()) throw Exception(Exception::getErrorMessage(ErrorCode::InvPartRelPartitionedDefined) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)) .arg(src_tab->getPartitionedTable()->getName(true)), ErrorCode::InvPartRelPartitionedDefined,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the user tries to create a generalization or copy relationship in * which one of the tables is part of a partitioning hierarchy, or if the relationship is 1-1, 1-n, n-n and * one of the tables is a partition. */ if(((rel_type == RelationshipGen || rel_type == RelationshipDep) && (src_tab->isPartition() || src_tab->isPartitioned() || dst_tab->isPartition() || dst_tab->isPartitioned())) || ((rel_type == Relationship11 || rel_type == Relationship1n || rel_type == RelationshipNn) && (src_tab->isPartition() || dst_tab->isPartition()))) throw Exception(Exception::getErrorMessage(ErrorCode::InvRelTypeForPatitionTables) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)) .arg(src_tab->isPartitioned() || src_tab->isPartition() ? src_tab->getName(true) : dst_tab->getName(true)), ErrorCode::InvRelTypeForPatitionTables,__PRETTY_FUNCTION__,__FILE__,__LINE__); copy_options=copy_op; table_relnn=nullptr; fk_rel1n=pk_relident=pk_special=uq_rel11=pk_original=nullptr; this->deferrable=deferrable; this->deferral_type=deferral_type; this->del_action=fk_del_act; this->upd_action=fk_upd_act; this->invalidated=true; this->single_pk_column=false; if(rel_type==Relationship11) str_aux=QApplication::translate("Relationship","%1_has_one_%2",""); else if(rel_type==Relationship1n) str_aux=QApplication::translate("Relationship","%1_has_many_%2",""); else if(rel_type==RelationshipNn) str_aux=QApplication::translate("Relationship","many_%1_has_many_%2",""); else if(rel_type==RelationshipGen) str_aux=QApplication::translate("Relationship","%1_inherits_%2",""); else if(rel_type==RelationshipPart) str_aux=QApplication::translate("Relationship","%1_is_partition_of_%2",""); else str_aux=QApplication::translate("Relationship","%1_copies_%2",""); if(rel_type==RelationshipNn) str_aux=str_aux.arg(this->src_table->getName()) .arg(this->dst_table->getName()); else if(rel_type==Relationship1n) str_aux=str_aux.arg(this->getReferenceTable()->getName()) .arg(this->getReceiverTable()->getName()); else str_aux=str_aux.arg(this->getReceiverTable()->getName()) .arg(this->getReferenceTable()->getName()); if(str_aux.size() > BaseObject::ObjectNameMaxLength) str_aux.resize(BaseObject::ObjectNameMaxLength); setName(str_aux); if(rel_type==RelationshipNn) { tab_name_relnn=this->obj_name; if(tab_name_relnn.size() > BaseObject::ObjectNameMaxLength) tab_name_relnn.resize(BaseObject::ObjectNameMaxLength); setNamePattern(PkPattern, GenTabToken + SuffixSeparator + QString("pk")); setNamePattern(SrcFkPattern, SrcTabToken + SuffixSeparator + QString("fk")); setNamePattern(DstFkPattern, DstTabToken + SuffixSeparator + QString("fk")); setNamePattern(UqPattern, GenTabToken + SuffixSeparator + QString("uq")); setNamePattern(SrcColPattern, SrcColToken + SuffixSeparator + SrcTabToken); setNamePattern(DstColPattern, SrcColToken + SuffixSeparator + DstTabToken); setNamePattern(PkColPattern, QString("id")); } else if(rel_type==RelationshipDep || rel_type==RelationshipGen) setNamePattern(PkPattern, DstTabToken + SuffixSeparator + QString("pk")); else { setNamePattern(PkPattern, DstTabToken + SuffixSeparator + QString("pk")); setNamePattern(SrcFkPattern, SrcTabToken + SuffixSeparator + QString("fk")); setNamePattern(UqPattern, DstTabToken + SuffixSeparator + QString("uq")); setNamePattern(SrcColPattern, SrcColToken + SuffixSeparator + SrcTabToken); } rejected_col_count=0; setIdentifier(identifier); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Relationship::setNamePattern(unsigned pat_id, const QString &pattern) { if(!pattern.isEmpty()) { QString aux_name=pattern, pat_tokens[]={ SrcTabToken, DstTabToken, GenTabToken, SrcColToken }; unsigned i, count=sizeof(pat_tokens)/sizeof(QString); for(i=0; i < count; i++) aux_name.replace(pat_tokens[i], QString("%1").arg(static_cast('a' + i))); if(pat_id > PkColPattern) throw Exception(Exception::getErrorMessage(ErrorCode::RefInvalidNamePatternId) .arg(this->getName()),__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!BaseObject::isValidName(aux_name)) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidNamePattern) .arg(this->getName()),__PRETTY_FUNCTION__,__FILE__,__LINE__); name_patterns[pat_id]=pattern; this->invalidated=true; } } QString Relationship::getNamePattern(unsigned pat_id) { if(pat_id > PkColPattern) throw Exception(ErrorCode::RefInvalidNamePatternId,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(name_patterns[pat_id]); } QString Relationship::generateObjectName(unsigned pat_id, Column *id_col, bool use_alias) { QString name, aux_name; name=name_patterns[pat_id]; name.replace(GenTabToken, (rel_type==RelationshipNn ? tab_name_relnn : QString())); if(rel_type==RelationshipNn) { aux_name = use_alias && !src_table->getAlias().isEmpty() ? src_table->getAlias() : src_table->getName(); name.replace(SrcTabToken, aux_name); aux_name = use_alias && !dst_table->getAlias().isEmpty() ? dst_table->getAlias() : dst_table->getName(); name.replace(DstTabToken, aux_name); } else { aux_name = use_alias && !getReferenceTable()->getAlias().isEmpty() ? getReferenceTable()->getAlias() : getReferenceTable()->getName(); name.replace(SrcTabToken, aux_name); aux_name = use_alias && !getReceiverTable()->getAlias().isEmpty() ? getReceiverTable()->getAlias() : getReceiverTable()->getName(); name.replace(DstTabToken, aux_name); } aux_name.clear(); if(id_col) aux_name = use_alias && !id_col->getAlias().isEmpty() ? id_col->getAlias() : id_col->getName(); name.replace(SrcColToken, aux_name); if(name.size() > BaseObject::ObjectNameMaxLength) name.remove(BaseObject::ObjectNameMaxLength, name.size()); return(name); } void Relationship::setOriginalPrimaryKey(Constraint *pk) { pk_original = pk; } void Relationship::setMandatoryTable(unsigned table_id, bool value) { BaseRelationship::setMandatoryTable(table_id, value); this->invalidated=true; } void Relationship::setDeferrable(bool value) { deferrable=value; this->invalidated=true; } void Relationship::setIdentifier(bool value) { /* Raises an error if the user try to set an self relationship, n-n relationship, generalization or copy as identifier. Only 1-1, 1-n relationships can be set as identifier. */ if(value && (src_table==dst_table || (rel_type==RelationshipNn || rel_type==RelationshipGen || rel_type==RelationshipDep))) throw Exception(ErrorCode::InvIdentifierRelationship,__PRETTY_FUNCTION__,__FILE__,__LINE__); identifier=value; this->invalidated=true; } void Relationship::setSpecialPrimaryKeyCols(vector &cols) { /* Raises an error if the user try to set columns for special primary key when the relationship type is identifier or self relationship */ if(!cols.empty() && (isSelfRelationship() || isIdentifier())) throw Exception(Exception::getErrorMessage(ErrorCode::InvUseSpecialPrimaryKey) .arg(this->getName()), ErrorCode::InvUseSpecialPrimaryKey,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->column_ids_pk_rel=cols; } vector Relationship::getSpecialPrimaryKeyCols(void) { return(this->column_ids_pk_rel); } void Relationship::createSpecialPrimaryKey(void) { if(!column_ids_pk_rel.empty()) { unsigned i, count; vector gen_cols; PhysicalTable *table = getReceiverTable(); // First we need to remove the original primary key in order to use the special pk if(table->getPrimaryKey()) { pk_original = table->getPrimaryKey(); table->removeObject(pk_original); } /* Allocates the primary key with the following feature: 1) Protected and included by linking in order to be easily identified on internal operations of the relationship 2) Use the same tablespace as the receiver table */ pk_special=new Constraint; pk_special->setName(generateObjectName(PkPattern)); pk_special->setAlias(generateObjectName(PkPattern, nullptr, true)); pk_special->setConstraintType(ConstraintType::PrimaryKey); pk_special->setAddedByLinking(true); pk_special->setProtected(true); pk_special->setTablespace(dynamic_cast(getReceiverTable()->getTablespace())); //For generalization relationships generates the primary key in form of ALTER command pk_special->setDeclaredInTable(this->getRelationshipType()!=RelationshipGen); // Adding the collumns of the original primary key to the special one for(i=0; pk_original && i < pk_original->getColumnCount(Constraint::SourceCols); i++) pk_special->addColumn(pk_original->getColumn(i, Constraint::SourceCols), Constraint::SourceCols); gen_cols=gen_columns; for(auto &attrib : rel_attributes) gen_cols.push_back(dynamic_cast(attrib)); //Adds the columns to the primary key count=column_ids_pk_rel.size(); for(i=0; i < count; i++) { if(column_ids_pk_rel[i] < gen_cols.size() && !pk_special->isColumnExists(gen_cols[column_ids_pk_rel[i]], Constraint::SourceCols)) pk_special->addColumn(gen_cols[column_ids_pk_rel[i]], Constraint::SourceCols); } try { this->addObject(pk_special); } catch(Exception &) { //Case some error is raised deletes the special primary key delete(pk_special); pk_special=nullptr; } } } void Relationship::setTableNameRelNN(const QString &name) { if(rel_type==RelationshipNn) { if(!BaseObject::isValidName(name)) throw Exception(ErrorCode::AsgInvalidNameTableRelNN, __PRETTY_FUNCTION__,__FILE__,__LINE__); tab_name_relnn=name; tab_name_relnn.remove('"'); this->invalidated=true; } } QString Relationship::getTableNameRelNN(void) { return(tab_name_relnn); } void Relationship::setPartitionBoundingExpr(const QString &part_bound_expr) { part_bounding_expr = (part_bound_expr.toLower() == Attributes::Default.toLower() ? QString() : part_bound_expr); this->invalidated = true; } QString Relationship::getPartitionBoundingExpr(void) { return(part_bounding_expr); } bool Relationship::isDeferrable(void) { return(deferrable); } void Relationship::setDeferralType(DeferralType defer_type) { deferral_type=defer_type; this->invalidated=true; } DeferralType Relationship::getDeferralType(void) { return(deferral_type); } void Relationship::setActionType(ActionType act_type, unsigned act_id) { if(act_id==Constraint::DeleteAction) this->del_action=act_type; else this->upd_action=act_type; this->invalidated=true; } ActionType Relationship::getActionType(unsigned act_id) { if(act_id==Constraint::DeleteAction) return(del_action); else return(upd_action); } int Relationship::getObjectIndex(TableObject *object) { vector::iterator itr, itr_end; vector *list=nullptr; TableObject *obj_aux=nullptr; ObjectType obj_type; bool found=false; //Raises an error if the object is not allocated if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Selecting the correct list using the object type obj_type=object->getObjectType(); if(obj_type==ObjectType::Column) list=&rel_attributes; else if(obj_type==ObjectType::Constraint) list=&rel_constraints; else //Raises an error if the object type isn't valid (not a column or constraint) throw Exception(ErrorCode::RefObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); itr=list->begin(); itr_end=list->end(); while(itr!=itr_end && !found) { obj_aux=(*itr); found=(obj_aux==object || obj_aux->getName()==object->getName()); itr++; } if(found) return((itr-list->begin())-1); else return(-1); } bool Relationship::isColumnExists(Column *column) { vector::iterator itr, itr_end; Column *col_aux=nullptr; bool found=false; //Raises an error if the column is not allocated if(!column) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=gen_columns.begin(); itr_end=gen_columns.end(); while(itr!=itr_end && !found) { col_aux=(*itr); found=(col_aux==column || col_aux->getName()==column->getName()); itr++; } return(found); } void Relationship::addObject(TableObject *tab_obj, int obj_idx) { ObjectType obj_type; vector *obj_list=nullptr; /* Raises an error if the user try to add manually a special primary key on the relationship and the relationship type is not generalization or copy */ if((rel_type==RelationshipGen || rel_type==RelationshipDep || rel_type==RelationshipPart) && !(tab_obj->isAddedByRelationship() && tab_obj->isProtected() && tab_obj->getObjectType()==ObjectType::Constraint)) throw Exception(ErrorCode::AsgObjectInvalidRelationshipType,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { //Checks if the object isn't exists on the relationshi and doesn't belongs to a table if(!tab_obj->getParentTable() && getObjectIndex(tab_obj) < 0) { //Gets the object list according the object type obj_type=tab_obj->getObjectType(); if(obj_type==ObjectType::Column) obj_list=&rel_attributes; else if(obj_type==ObjectType::Constraint) obj_list=&rel_constraints; else //Raises an error if the object type isn't valid (not a column or constraint) throw Exception(ErrorCode::AsgObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); //Defines the parent table for the object only for validation tab_obj->setParentTable(src_table); //Generates the code for the object only for validation if(obj_type==ObjectType::Column) dynamic_cast(tab_obj)->getCodeDefinition(SchemaParser::SqlDefinition); else { Constraint *rest=nullptr; rest=dynamic_cast(tab_obj); //Raises an error if the user try to add as foreign key to relationship if(rest->getConstraintType()==ConstraintType::ForeignKey) throw Exception(ErrorCode::AsgForeignKeyRelationship,__PRETTY_FUNCTION__,__FILE__,__LINE__); rest->getCodeDefinition(SchemaParser::SqlDefinition); } //Switch back to null the object parent tab_obj->setParentTable(nullptr); if(obj_idx < 0 || obj_idx >= static_cast(obj_list->size())) obj_list->push_back(tab_obj); else { if(obj_list->size() > 0) obj_list->insert((obj_list->begin() + obj_idx), tab_obj); else obj_list->push_back(tab_obj); } tab_obj->setAddedByLinking(true); this->invalidated=true; } else throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(tab_obj->getName(true)) .arg(tab_obj->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgDuplicatedObject, __PRETTY_FUNCTION__,__FILE__,__LINE__); } catch(Exception &e) { if(e.getErrorCode()==ErrorCode::UndefinedAttributeValue) throw Exception(Exception::getErrorMessage(ErrorCode::AsgObjectInvalidDefinition) .arg(tab_obj->getName()) .arg(tab_obj->getTypeName()), ErrorCode::AsgObjectInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Relationship::destroyObjects(void) { while(!rel_constraints.empty()) { delete(rel_constraints.back()); rel_constraints.pop_back(); } while(!rel_attributes.empty()) { delete(rel_attributes.back()); rel_attributes.pop_back(); } } void Relationship::removeObject(unsigned obj_id, ObjectType obj_type) { vector *obj_list=nullptr; TableObject *tab_obj=nullptr; PhysicalTable *recv_table=nullptr; if(obj_type==ObjectType::Column) obj_list=&rel_attributes; else if(obj_type==ObjectType::Constraint) obj_list=&rel_constraints; else throw Exception(ErrorCode::RefObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the object index is out of bound if(obj_id >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); tab_obj=obj_list->at(obj_id); recv_table=this->getReceiverTable(); if(obj_type==ObjectType::Column) { Column *col=nullptr; Constraint *constr=nullptr; vector::iterator itr, itr_end; vector::iterator sp_pk_itr; bool refer=false; int col_idx=0; itr=rel_constraints.begin(); itr_end=rel_constraints.end(); col=dynamic_cast(tab_obj); while(itr!=itr_end && !refer) { constr=dynamic_cast(*itr); //Check is the column is referenced by one relationship constraints refer=(constr->getColumn(col->getName(), Constraint::SourceCols) || constr->getColumn(col->getName(), Constraint::ReferencedCols)); itr++; } //Raises an error if the column to be removed is referenced by a relationship constraint if(refer) throw Exception(Exception::getErrorMessage(ErrorCode::RemInderectReference) .arg(col->getName()) .arg(col->getTypeName()) .arg(constr->getName()) .arg(constr->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::RemInderectReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Generating the column index inside the special pk column list col_idx=getObjectIndex(col) + gen_columns.size(); sp_pk_itr=find(column_ids_pk_rel.begin(), column_ids_pk_rel.end(), col_idx); //Remove the attribute from the special pk column id list if(sp_pk_itr!=column_ids_pk_rel.end()) column_ids_pk_rel.erase(sp_pk_itr); removeColumnFromTablePK(dynamic_cast(col->getParentTable()), col); } //Removing the object from the receiver table if(recv_table && tab_obj->getParentTable()==recv_table) { recv_table->removeObject(tab_obj); tab_obj->setParentTable(nullptr); } //Removes the column obj_list->erase(obj_list->begin() + obj_id); this->invalidated=true; } void Relationship::removeObject(TableObject *object) { if(!object) throw Exception(ErrorCode::RemNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); removeObject(getObjectIndex(object),object->getObjectType()); } void Relationship::removeAttribute(unsigned attrib_idx) { removeObject(attrib_idx, ObjectType::Column); } void Relationship::removeConstraint(unsigned constr_idx) { removeObject(constr_idx, ObjectType::Constraint); } vector Relationship::getGeneratedColumns(void) { return(gen_columns); } Table *Relationship::getGeneratedTable(void) { return(table_relnn); } vector Relationship::getGeneratedConstraints(void) { vector vect; if(fk_rel1n) vect.push_back(fk_rel1n); if(uq_rel11) vect.push_back(uq_rel11); if(pk_relident) vect.push_back(pk_relident); return(vect); } TableObject *Relationship::getObject(unsigned obj_idx, ObjectType obj_type) { vector *list=nullptr; if(obj_type==ObjectType::Column) list=&rel_attributes; else if(obj_type==ObjectType::Constraint) list=&rel_constraints; else throw Exception(ErrorCode::RefObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); if(obj_idx >= list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex, __PRETTY_FUNCTION__,__FILE__,__LINE__); return(list->at(obj_idx)); } TableObject *Relationship::getObject(const QString &name, ObjectType obj_type) { vector::iterator itr, itr_end; vector *list=nullptr; TableObject *obj_aux=nullptr; bool found=false; if(obj_type==ObjectType::Column) list=&rel_attributes; else if(obj_type==ObjectType::Constraint) list=&rel_constraints; else throw Exception(ErrorCode::RefObjectInvalidType, __PRETTY_FUNCTION__,__FILE__,__LINE__); itr=list->begin(); itr_end=list->end(); while(itr!=itr_end && !found) { obj_aux=(*itr); found=(obj_aux->getName()==name); itr++; } if(found) return(obj_aux); else return(nullptr); } Column *Relationship::getAttribute(unsigned attrib_idx) { //Raises an error if the attribute index is out of bound if(attrib_idx >= rel_attributes.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(dynamic_cast(rel_attributes[attrib_idx])); } Column *Relationship::getAttribute(const QString &name) { return(dynamic_cast(getObject(name,ObjectType::Column))); } vector Relationship::getAttributes(void) { return(rel_attributes); } Constraint *Relationship::getConstraint(unsigned constr_idx) { //Raises an error if the constraint index is out of bound if(constr_idx >= rel_constraints.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(dynamic_cast(rel_constraints[constr_idx])); } Constraint *Relationship::getConstraint(const QString &name) { return(dynamic_cast(getObject(name,ObjectType::Constraint))); } vector Relationship::getConstraints(void) { return(rel_constraints); } unsigned Relationship::getAttributeCount(void) { return(rel_attributes.size()); } unsigned Relationship::getConstraintCount(void) { return(rel_constraints.size()); } unsigned Relationship::getObjectCount(ObjectType obj_type) { if(obj_type==ObjectType::Column) return(rel_attributes.size()); else if(obj_type==ObjectType::Constraint) return(rel_constraints.size()); else throw Exception(ErrorCode::RefObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } void Relationship::addConstraints(PhysicalTable *recv_tab) { Constraint *constr=nullptr, *pk=nullptr; unsigned constr_id, constr_cnt, i, count; try { constr_cnt=rel_constraints.size(); for(constr_id=0; constr_id < constr_cnt; constr_id++) { constr=dynamic_cast(rel_constraints[constr_id]); constr->setAddedByLinking(true); //Breaks the iteration if the constraist has a parent if(constr->getParentTable()) break; if(constr->getConstraintType()!=ConstraintType::PrimaryKey) { constr->setName(PgModelerNs::generateUniqueName(constr, (*recv_tab->getObjectList(ObjectType::Constraint)))); recv_tab->addConstraint(constr); } else { /* Case the constraint is a primary key it will be merged with the table's primary key */ //Gets the table primary key pk=recv_tab->getPrimaryKey(); if(pk) { count=constr->getColumnCount(Constraint::SourceCols); for(i=0; i < count; i++) //Adds the colums from the constraint into the table's primary key pk->addColumn(constr->getColumn(i, Constraint::SourceCols), Constraint::SourceCols); } else //Case the table doens't has a primary key the constraint will the be it recv_tab->addConstraint(constr); if(constr==pk_special) { rel_constraints.erase(rel_constraints.begin()+constr_id); constr_cnt=rel_constraints.size(); } } } } catch(Exception &e) { vector::iterator itr=rel_constraints.begin(); while(itr!=rel_constraints.end()) { recv_tab->removeObject(*itr); itr++; } throw Exception(e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addColumnsRelGenPart(void) { PhysicalTable *src_tab=nullptr, *dst_tab=nullptr, *parent_tab=nullptr, *aux_tab=nullptr; Column *src_col=nullptr, *dst_col=nullptr, *column=nullptr, *aux_col=nullptr; unsigned src_count, dst_count, i, i1, i2, id_tab, idx, tab_count; vector columns; ObjectType types[2]={ ObjectType::Table, ObjectType::BaseTable }; ErrorCode err_code=ErrorCode::Custom; bool duplic=false, cond=false, /* 0 -> Column created by inheritance relationship * 1 -> Column created by copy relationship */ src_flags[2]={false,false}, dst_flags[2]={false,false}; QString str_aux, msg; PgSqlType src_type, dst_type; try { src_tab=dynamic_cast(src_table); dst_tab=dynamic_cast(dst_table); //Gets the column count from participant tables src_count=src_tab->getColumnCount(); dst_count=dst_tab->getColumnCount(); rejected_col_count=0; /* If the relationship is partitioning the destination table (partitioned) shoud have * a partitioning type defined otherwise and error is raised */ if(rel_type == RelationshipPart && !dst_tab->isPartitioned()) throw Exception(Exception::getErrorMessage(ErrorCode::InvPartitioningTypePartRel) .arg(src_tab->getSignature()).arg(dst_tab->getSignature()), ErrorCode::InvPartitioningTypePartRel, __PRETTY_FUNCTION__,__FILE__,__LINE__); /* This for compares the columns of the receiver table with the columns of the reference table in order to resolve the conflicting names */ for(i=0; i < dst_count && err_code==ErrorCode::Custom; i++) { //Gets the column from the receiver (destination) table dst_col=dst_tab->getColumn(i); /* The copied column have the 'serial' like types converted to integer like types in order to avoid error when configuring the relationship foreign key */ dst_type=dst_col->getType(); if(dst_type==QString("serial")) dst_type=QString("integer"); else if(dst_type==QString("bigserial")) dst_type=QString("bigint"); else if(dst_type==QString("smallserial")) dst_type=QString("smallint"); /* This flag indicates that the column name is registered in the other table column (duplication). This situation need to be resolved in order to evict the creation of duplicated column on the receiver table */ duplic=false; for(i1=0; i1 < src_count && !duplic; i1++) { //Gets the reference (source) column converting its type src_col=src_tab->getColumn(i1); src_type=src_col->getType(); if(src_type==QString("serial")) src_type=QString("integer"); else if(src_type==QString("bigserial")) src_type=QString("bigint"); else if(dst_type==QString("smallserial")) dst_type=QString("smallint"); //Check the duplication on the column names duplic=(src_col->getName()==dst_col->getName()); //In case of duplication if(duplic) { /* It is necessary to check if the source column (reference) is of the table itself, if it came from a parent table or a table copy. The same verification is the destination column. The duplicity of columns only generates error when the source column is of the table itself and the target column was not from a parent table of the receiver table in the case of a copy relationship. If the source column is of the reference table or coming from a copy relationship and the type of the current relationship is inheritance, the only case in which the duplicity generates error is the type incompatibility of the columns involved, otherwise they are merged. */ for(id_tab=0; id_tab < 2; id_tab++) { if(id_tab==0) { aux_col=src_col; aux_tab=src_tab; } else { aux_col=dst_col; aux_tab=dst_tab; } for(i2=0; i2 < 2; i2++) { //Checking if the column came from a generalization relationship if(PhysicalTable::isPhysicalTable(types[i2])) { tab_count=aux_tab->getObjectCount(ObjectType::Table); for(idx=0; idx < tab_count; idx++) { parent_tab=dynamic_cast(aux_tab->getObject(idx, ObjectType::Table)); cond=(aux_col->getParentTable()==parent_tab && aux_col->isAddedByGeneralization()); } } //Checking if the column came from a copy relationship else { parent_tab=aux_tab->getCopyTable(); cond=(parent_tab && rel_type == RelationshipDep && aux_col->getParentTable()==parent_tab && aux_col->isAddedByCopy()); } if(id_tab==0) src_flags[i2]=cond; else dst_flags[i2]=cond; } } /* Error condition 1: The relationship type is dependency and the source column is from the table itself or it came from a copy table and the destination column is from the destination table or came from a copy table of the destination table itself */ if((rel_type==RelationshipDep) && ((!src_flags[0] && !src_flags[1]) || (!src_flags[0] && src_flags[1])) && ((!dst_flags[0] && !dst_flags[1]) || (!dst_flags[0] && dst_flags[1]))) { err_code=ErrorCode::InvCopyRelationshipDuplicCols; } /* Error condition 2: The relationship type is generalization and the column * types is incompatible */ else if((rel_type == RelationshipGen || rel_type==RelationshipPart) && src_type != dst_type) err_code=ErrorCode::InvInheritRelationshipIncompCols; } } //In case that no error was detected (ERR_CUSTOM) if(err_code==ErrorCode::Custom) { //In case there is no column duplicity if(!duplic) { //Creates a new column making the initial configurations column=new Column; (*column)=(*dst_col); if(rel_type==RelationshipGen) column->setAddedByGeneralization(true); else column->setAddedByCopy(true); column->setParentTable(nullptr); column->setParentRelationship(this); //Converts the type if(column->getType()==QString("serial")) column->setType(PgSqlType(QString("integer"))); else if(column->getType()==QString("bigserial")) column->setType(PgSqlType(QString("bigint"))); else if(column->getType()==QString("smallserial")) column->setType(PgSqlType(QString("smallint"))); //Adds the new column to the temporary column list columns.push_back(column); } else /* If there is duplicity, the column is discarded and not included in the list, instead, increases the attribute which counts the amount duplicate columns of which were rejected by already exist in the target (receiver) table */ rejected_col_count++; } } if((src_tab->getColumnCount() + columns.size()) != dst_tab->getColumnCount() && rel_type == RelationshipPart) err_code = ErrorCode::InvColumnCountPartRel; //In case that no duplicity error is detected if(err_code==ErrorCode::Custom) { vector::iterator itr, itr_end; /* The columns of the temporary list will be inserted in the list of referencing columns, and additionally the relationship columns will also be inserted directly in the source table, which inherits or copy table columns from target table */ gen_columns=columns; itr=gen_columns.begin(); itr_end=gen_columns.end(); while(itr!=itr_end) { src_tab->addColumn((*itr)); itr++; } } else { //In case of duplicity error the temporary columns are destroyed while(!columns.empty()) { delete(columns.back()); columns.pop_back(); } str_aux=Exception::getErrorMessage(err_code); if(err_code==ErrorCode::InvCopyRelationshipDuplicCols) { msg=QString(str_aux) .arg(dst_col->getName(true)) .arg(dst_tab->getName(true)) .arg(src_tab->getName(true)); } else if(err_code==ErrorCode::InvColumnCountPartRel) { msg=QString(str_aux) .arg(src_tab->getName(true)) .arg(dst_tab->getName(true)); } else { msg=QString(str_aux) .arg(dst_col->getName(true)) .arg(dst_tab->getName(true)) .arg(src_col->getName(true)) .arg(src_tab->getName(true)); } throw Exception(msg, err_code,__PRETTY_FUNCTION__,__FILE__,__LINE__); } /* Creates the special primary key if exists and if the receiver table is not a foreign table . * This kind of table still don't support pks and fks */ if(getReceiverTable()->getObjectType() != ObjectType::ForeignTable) this->createSpecialPrimaryKey(); //Adds the constraint on the receiver table this->addConstraints(getReceiverTable()); } catch(Exception &e) { //Forcing the relationship as connected to perform the disconnection operations this->connected=true; this->disconnectRelationship(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addConstraintsRelGenPart(void) { PhysicalTable *parent_tab=getReferenceTable(), *child_tab=getReceiverTable(); vector *constrs=parent_tab->getObjectList(ObjectType::Constraint); Constraint *ck_constr=nullptr, *constr=nullptr, *aux_constr=nullptr; try { for(auto &obj : *constrs) { constr=dynamic_cast(obj); if(constr->getConstraintType()==ConstraintType::Check && !constr->isNoInherit()) { aux_constr=dynamic_cast(child_tab->getObject(constr->getName(), ObjectType::Constraint)); if(!aux_constr) { ck_constr=new Constraint; (*ck_constr)=(*constr); ck_constr->setParentTable(nullptr); ck_constr->setAddedByGeneralization(true); child_tab->addConstraint(ck_constr); ck_constraints.push_back(ck_constr); } else if(aux_constr->getConstraintType()!=ConstraintType::Check || aux_constr->getExpression().simplified()!=constr->getExpression().simplified()) throw Exception(Exception::getErrorMessage(ErrorCode::InvInheritRelationshipIncompConstrs) .arg(constr->getName()).arg(parent_tab->getName(false, true)) .arg(aux_constr->getName()).arg(child_tab->getName(false, true)), ErrorCode::InvInheritRelationshipIncompConstrs,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::connectRelationship(void) { try { if(!connected) { if(rel_type==RelationshipGen) { //Copying the CHECK constraints before adding custom constraints like special pk addConstraintsRelGenPart(); //Creates the columns on the receiver table following the rules for generalization rules addColumnsRelGenPart(); //The reference table is added as parent table on the receiver getReceiverTable()->addAncestorTable(getReferenceTable()); } else if(rel_type==RelationshipDep) { //Creates the columns on the receiver table following the rules for copy rules addColumnsRelGenPart(); //The reference table is added as copy table on the receiver getReceiverTable()->setCopyTable(getReferenceTable()); getReceiverTable()->setCopyTableOptions(this->copy_options); } else if(rel_type == RelationshipPart) { //Copying the CHECK constraints before adding custom constraints like special pk addConstraintsRelGenPart(); //Creates the columns on the receiver table following the rules for copy rules addColumnsRelGenPart(); getReceiverTable()->setPartionedTable(getReferenceTable()); getReceiverTable()->setPartitionBoundingExpr(part_bounding_expr); } else if(rel_type==Relationship11 || rel_type==Relationship1n) { if(rel_type==Relationship11) addColumnsRel11(); else addColumnsRel1n(); } else if(rel_type==RelationshipNn) { if(!table_relnn) //Allocates the table that represents the Many-to-Many relationship table_relnn=new Table; /* By default the schema and tablespace for the new table is the same as the relationship source table */ table_relnn->setName(tab_name_relnn); table_relnn->setSchema(src_table->getSchema()); table_relnn->setTablespace(src_table->getTablespace()); addColumnsRelNn(); } BaseRelationship::connectRelationship(); /* Storing the names of tables in order to check if they were renamed in any moment. When a table is renamed the relationship will be invalidated because most of objects generated by the relationship uses the tables names */ src_tab_prev_name=src_table->getName(); dst_tab_prev_name=dst_table->getName(); this->invalidated=false; } } catch(Exception &e) { if(table_relnn) { delete(table_relnn); table_relnn=nullptr; } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::configureIndentifierRel(PhysicalTable *recv_tab) { Constraint *pk=nullptr; unsigned i, count; bool new_pk=false; try { /* In the identifier relationship, the primary key of the receiver table (weak entity) will be merged with the primary key of the reference table (strong entity) */ //Gets the primary key from the receiver table pk=recv_tab->getPrimaryKey(); //Case the primary key doesn't exists it'll be created if(!pk) { //Creates the primary key for the weak entity if(!pk_relident) { pk=new Constraint; pk->setConstraintType(ConstraintType::PrimaryKey); pk->setAddedByLinking(true); pk->setDeferrable(this->deferrable); pk->setDeferralType(this->deferral_type); this->pk_relident=pk; } else pk=this->pk_relident; new_pk=true; pk->setName(generateObjectName(PkPattern)); pk->setAlias(generateObjectName(PkPattern, nullptr, true)); } //Adds the columns from the strong entity primary key on the weak entity primary key count=gen_columns.size(); for(i=0; i < count; i++) pk->addColumn(gen_columns[i], Constraint::SourceCols); //Inserts the configured primary key on the receiver table (if there is no pk on it) if(new_pk) recv_tab->addConstraint(pk); } catch(Exception &e) { if(pk_relident) { if(new_pk) { recv_tab->removeObject(pk_relident); delete(pk_relident); } else { pk=recv_tab->getPrimaryKey(); count=gen_columns.size(); for(i=0; i < count; i++) pk->removeColumn(gen_columns[i]->getName(), Constraint::SourceCols); } pk_relident=nullptr; } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addUniqueKey(PhysicalTable *recv_tab) { Constraint *uq=nullptr; unsigned i, count; try { //Alocates the unique key if(!uq_rel11) { uq=new Constraint; uq->setDeferrable(this->deferrable); uq->setDeferralType(this->deferral_type); uq->setConstraintType(ConstraintType::Unique); uq->setAddedByLinking(true); uq_rel11=uq; } //Adds the referenced columns as the unique key columns count=gen_columns.size(); i=0; while(i < count) uq->addColumn(gen_columns[i++], Constraint::SourceCols); /* Special case when the receiver table of the one-to-one unique key * is a partitioned table. If any of the partition keys of that table * refer to a column, the column itself must be included into the generated * unique key according to PostgreSQL rules (12+) */ if(recv_tab->isPartitioned()) { for(auto &part_key : recv_tab->getPartitionKeys()) { if(part_key.getColumn()) uq->addColumn(part_key.getColumn(), Constraint::SourceCols); } } uq->setName(generateObjectName(UqPattern)); uq->setAlias(generateObjectName(UqPattern, nullptr, true)); uq->setName(PgModelerNs::generateUniqueName(uq, (*recv_tab->getObjectList(ObjectType::Constraint)))); recv_tab->addConstraint(uq); } catch(Exception &e) { if(uq_rel11) { recv_tab->removeObject(uq_rel11); delete(uq_rel11); uq_rel11=nullptr; } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addForeignKey(PhysicalTable *ref_tab, PhysicalTable *recv_tab, ActionType del_act, ActionType upd_act) { Constraint *pk=nullptr, *pk_aux=nullptr, *fk=nullptr; unsigned i, i1, qty; Column *column=nullptr, *column_aux=nullptr; QString name, aux, fk_alias; try { //Alocates the foreign key if((rel_type==RelationshipNn) || (!fk_rel1n && (rel_type==Relationship11 || rel_type==Relationship1n))) { fk=new Constraint; fk->setDeferrable(this->deferrable); fk->setDeferralType(this->deferral_type); fk->setConstraintType(ConstraintType::ForeignKey); fk->setAddedByLinking(true); //The reference table is the table referenced by the foreign key fk->setReferencedTable(ref_tab); /* The configured fk is assigned to the relatioship attibute in order to be manipulated more easily */ if(rel_type==Relationship11 || rel_type==Relationship1n) fk_rel1n=fk; } //Sets the ON DELETE and ON UPDATE actions for the foreign key fk->setActionType(del_act, Constraint::DeleteAction); fk->setActionType(upd_act, Constraint::UpdateAction); /* Gets the primary key from the reference table in order to reference its columns on the primary key */ pk=ref_tab->getPrimaryKey(); qty=gen_columns.size(); i=i1=0; /* Special condition for n-n relationships. Because the columns copied from participants tables are stored in a single list, its needed to make a shift the scan them so that the columns are not related in a incorrect way in the foreign key. Case 1: The number of columns (qty) must be decremented from quantity of columns present in the primary key of the target table. This is done when the pointer 'ref_tab' points to the own source table of the relationship. Thus, it is avoided that columns beyond the end of columns list in the source primary key be accessed. Case 2: The initial scan index (i) points to the first column of the columns list which corresponds to the set of columns of the target table. The first column related to the destination table column list always has its index starting at the existant columns count on the primary key on the source table because they is always inserted after this position. */ if(rel_type==RelationshipNn) { vector fks; /* Get the created foreign keys created on the self relationship in order to create them properly */ if(isSelfRelationship()) table_relnn->getForeignKeys(fks, true, dynamic_cast
(ref_tab)); //Case 1: decrementing the quantity of columns to be scanned if((!isSelfRelationship() && ref_tab==src_table) || //Condition to create the first fk on the self relationship (isSelfRelationship() && fks.size()==0)) qty-=dynamic_cast
(dst_table)->getPrimaryKey()->getColumnCount(Constraint::SourceCols); //Case 2: shifiting the scan index else if(ref_tab==dst_table) { pk_aux=dynamic_cast
(src_table)->getPrimaryKey(); i=pk_aux->getColumnCount(Constraint::SourceCols); } } while(i < qty) { column=gen_columns[i]; column_aux=pk->getColumn(i1, Constraint::SourceCols); //Link the two columns on the foreign key fk->addColumn(column, Constraint::SourceCols); fk->addColumn(column_aux, Constraint::ReferencedCols); i++; i1++; } //Configures the foreign key name aux.clear(); if(rel_type!=RelationshipNn) { name=generateObjectName(SrcFkPattern); fk_alias=generateObjectName(SrcFkPattern, nullptr, true); } else { if(ref_tab==src_table) { name=generateObjectName(SrcFkPattern); fk_alias=generateObjectName(SrcFkPattern, nullptr, true); } else { name=generateObjectName(DstFkPattern); fk_alias=generateObjectName(DstFkPattern, nullptr, true); } } fk->setName(name); fk->setAlias(fk_alias); fk->setName(PgModelerNs::generateUniqueName(fk, (*recv_tab->getObjectList(ObjectType::Constraint)))); recv_tab->addConstraint(fk); } catch(Exception &e) { if(fk_rel1n) { recv_tab->removeObject(fk_rel1n); delete(fk_rel1n); fk_rel1n=nullptr; } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addAttributes(PhysicalTable *recv_tab) { unsigned i, count; Column *column=nullptr; try { count=rel_attributes.size(); for(i=0; i < count; i++) { column=dynamic_cast(rel_attributes[i]); /* Case the attribute has a parent table interrupts the process and the remaining attributes aren't inserted on the table */ if(column->getParentTable()) break; column->setName(PgModelerNs::generateUniqueName(column, (*recv_tab->getObjectList(ObjectType::Column)))); column->setAddedByLinking(true); column->setParentRelationship(this); recv_tab->addColumn(column); } } catch(Exception &e) { vector::iterator itr=rel_attributes.begin(); while(itr!=rel_attributes.end()) { recv_tab->removeObject(*itr); itr++; } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::copyColumns(PhysicalTable *ref_tab, PhysicalTable *recv_tab, bool not_null, bool is_dst_table) { Constraint *dst_pk=nullptr, *src_pk=nullptr, *pk=nullptr; unsigned i, count; Column *column=nullptr, *column_aux=nullptr; QString name, prev_name, col_alias; try { dst_pk=recv_tab->getPrimaryKey(); pk=src_pk=ref_tab->getPrimaryKey(); /* Raises an error if some table doesn't has a primary key if the relationship is 1-1, 1-n or n-n */ if((!src_pk && (rel_type==Relationship1n || rel_type==Relationship11)) || (!src_pk && !dst_pk && rel_type==RelationshipNn)) throw Exception(Exception::getErrorMessage(ErrorCode::InvLinkTablesNoPrimaryKey) .arg(this->obj_name) .arg(ref_tab->getName(true)) .arg(recv_tab->getName(true)), ErrorCode::InvLinkTablesNoPrimaryKey,__PRETTY_FUNCTION__,__FILE__,__LINE__); count=pk->getColumnCount(Constraint::SourceCols); /* Scans the primary key columns adding them to the referenced column list of the relationship */ for(i=0; i < count; i++) { column=new Column; gen_columns.push_back(column); //Add the current primary key source column on the list column_aux=pk->getColumn(i, Constraint::SourceCols); pk_columns.push_back(column_aux); (*column)=(*column_aux); column->setNotNull(not_null); column->setDefaultValue(""); column->setComment(""); prev_name=prev_ref_col_names[column_aux->getObjectId()]; if(rel_type!=RelationshipNn) { name=generateObjectName(SrcColPattern, column_aux); col_alias=generateObjectName(SrcColPattern, column_aux, true); } else { if(ref_tab==src_table && (!isSelfRelationship() || (isSelfRelationship() && !is_dst_table))) { name=generateObjectName(SrcColPattern, column_aux); col_alias=generateObjectName(SrcColPattern, column_aux, true); } else { name=generateObjectName(DstColPattern, column_aux); col_alias=generateObjectName(DstColPattern, column_aux, true); } } column->setAlias(col_alias); //Protects the column evicting that the user modifies it column->setAddedByLinking(true); //Set the parent table as null permiting the column to be added on the receiver table column->setParentTable(nullptr); column->setParentRelationship(this); //Converting the serial like types if(column->getType()==QString("serial")) column->setType(PgSqlType(QString("integer"))); else if(column->getType()==QString("bigserial")) column->setType(PgSqlType(QString("bigint"))); else if(column->getType()==QString("smallserial")) column->setType(PgSqlType(QString("smallint"))); column->setName(name); name=PgModelerNs::generateUniqueName(column, (*recv_tab->getObjectList(ObjectType::Column))); column->setName(name); if(!prev_name.isEmpty()) { column->setName(prev_name); column->setName(name); } /* If the old name given to the column is different from the current name, the current name of the column will be the old name when the relationship is disconnected and reconnected again, so the column name history is not lost even when the columns of the relationship is deallocated, this prevents the breakdown of the references to columns created by the relationship. This operation is only performed for relationships 1-1, 1-n relationships to the n-n relationships columns are always recreated without the need to keep the history because the user can not reference the columns created by n-n relationships. */ if(prev_name!=name && (rel_type==Relationship11 || rel_type==Relationship1n)) prev_ref_col_names[column_aux->getObjectId()]=column->getName(); recv_tab->addColumn(column); } } catch(Exception &e) { while(!gen_columns.empty()) { recv_tab->removeObject(gen_columns.back()); gen_columns.pop_back(); } prev_ref_col_names.clear(); pk_columns.clear(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addColumnsRel11(void) { Table *ref_tab=nullptr, *recv_tab=nullptr; try { ActionType del_action, upd_action; ref_tab=dynamic_cast
(this->getReferenceTable()); recv_tab=dynamic_cast
(this->getReceiverTable()); if(this->upd_action!=ActionType::Null) upd_action=this->upd_action; else upd_action=ActionType::Cascade; if(this->del_action!=ActionType::Null) del_action=this->del_action; else { if(identifier) del_action=ActionType::Cascade; else { //Case the reference table is mandatory participation set as RESTRICT the delete action on the foreign key if((ref_tab==this->src_table && this->isTableMandatory(SrcTable)) || (ref_tab==this->dst_table && this->isTableMandatory(DstTable))) del_action=ActionType::Restrict; else del_action=ActionType::SetNull; } } if(isSelfRelationship()) { addAttributes(recv_tab); addConstraints(recv_tab); copyColumns(ref_tab, recv_tab, false); addForeignKey(ref_tab, recv_tab, del_action, upd_action); addUniqueKey(recv_tab); } else { copyColumns(ref_tab, recv_tab, (!identifier && (this->isTableMandatory(SrcTable) || this->isTableMandatory(DstTable)))); if(identifier) { /* When the relationship is identifier, the cardinalities are ignored because the strong entity always is of mandatory participation. */ this->setMandatoryTable(DstTable, false); this->setMandatoryTable(SrcTable, false); if(ref_tab==this->src_table) this->setMandatoryTable(SrcTable, true); else this->setMandatoryTable(DstTable, true); configureIndentifierRel(recv_tab); } else createSpecialPrimaryKey(); addAttributes(recv_tab); addConstraints(recv_tab); addForeignKey(ref_tab, recv_tab, del_action, upd_action); if(!identifier) addUniqueKey(recv_tab); } } catch(Exception &e) { //Forcing the relationship as connected to perform the disconnection operations this->connected=true; this->disconnectRelationship(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addColumnsRel1n(void) { Table *ref_tab=nullptr, *recv_tab=nullptr; bool not_null=false; ActionType del_action=ActionType::SetNull, upd_action; try { recv_tab=dynamic_cast
(this->getReceiverTable()); ref_tab=dynamic_cast
(this->getReferenceTable()); if(this->upd_action!=ActionType::Null) upd_action=this->upd_action; else upd_action=ActionType::Cascade; if(this->del_action!=ActionType::Null) del_action=this->del_action; else { /* Case the relationship isn't identifier and the source table is mandatory participation the columns of the foreign key must not accept null values and the ON DELETE and ON UPDATE action will be RESTRICT */ if(!identifier && src_mandatory) { if(!deferrable) del_action=ActionType::Restrict; else del_action=ActionType::NoAction; } /* Case the relationship is identifier configures the ON DELETE anda ON UPDATE action on the foreign key as CASCADE because the weak entity exists only if the strong entity also exists, this means if the strong entity tuple is removed the weak entity tuple is also removed */ else if(identifier) del_action=ActionType::Cascade; } if(!identifier && src_mandatory) not_null=true; if(isSelfRelationship()) { addAttributes(recv_tab); addConstraints(recv_tab); copyColumns(ref_tab, recv_tab, not_null); addForeignKey(ref_tab, recv_tab, del_action, upd_action); } else { copyColumns(ref_tab, recv_tab, not_null); if(identifier) { this->setMandatoryTable(SrcTable, true); this->setMandatoryTable(DstTable, false); configureIndentifierRel(recv_tab); } else createSpecialPrimaryKey(); addAttributes(recv_tab); addConstraints(recv_tab); addForeignKey(ref_tab, recv_tab, del_action, upd_action); } } catch(Exception &e) { //Forcing the relationship as connected to perform the disconnection operations this->connected=true; this->disconnectRelationship(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Relationship::addColumnsRelNn(void) { Column *pk_col=nullptr; Table *tab=nullptr, *tab1=nullptr; Constraint *pk_tabnn=nullptr; bool src_not_null=false, dst_not_null=false; ActionType src_del_act=ActionType::Restrict, dst_del_act=ActionType::Restrict, src_upd_act=ActionType::Cascade, dst_upd_act=ActionType::Cascade; try { tab=dynamic_cast
(src_table); tab1=dynamic_cast
(dst_table); if(this->upd_action!=ActionType::Null) src_upd_act=dst_upd_act=this->upd_action; else src_upd_act=dst_upd_act=ActionType::Cascade; if(this->del_action!=ActionType::Null) src_del_act=dst_del_act=this->del_action; else src_del_act=dst_del_act=ActionType::Restrict; /* Copy the columns from the primary keys of the source and destination tables to the table that represents the n-n relationship */ copyColumns(tab, table_relnn, src_not_null); copyColumns(tab1, table_relnn, dst_not_null, true); if(single_pk_column) { pk_col=new Column; pk_col->setName(generateObjectName(PkColPattern)); pk_col->setAlias(generateObjectName(PkColPattern, nullptr, true)); pk_col->setType(PgSqlType(QString("serial"))); pk_col->setAddedByLinking(true); table_relnn->addColumn(pk_col); } //Creates the primary key for the n-n relationship table pk_tabnn=new Constraint; pk_tabnn->setName(generateObjectName(PkPattern)); pk_tabnn->setAlias(generateObjectName(PkPattern, nullptr, true)); pk_tabnn->setConstraintType(ConstraintType::PrimaryKey); pk_tabnn->setAddedByLinking(true); if(!single_pk_column) { for(auto &col : gen_columns) { col->setNotNull(true); pk_tabnn->addColumn(col, Constraint::SourceCols); } } else { pk_tabnn->addColumn(pk_col, Constraint::SourceCols); for(auto &col : gen_columns) col->setNotNull(true); } for(unsigned i : column_ids_pk_rel) { if(i < rel_attributes.size()) pk_tabnn->addColumn(dynamic_cast(rel_attributes[i]), Constraint::SourceCols); } table_relnn->addConstraint(pk_tabnn); addAttributes(table_relnn); addConstraints(table_relnn); addForeignKey(tab, table_relnn, src_del_act, src_upd_act); addForeignKey(tab1, table_relnn, dst_del_act, dst_upd_act); //For single pk column mode the generated column is added at the end of gen_columns vector if(pk_col) gen_columns.push_back(pk_col); } catch(Exception &e) { //Forcing the relationship as connected to perform the disconnection operations this->connected=true; this->disconnectRelationship(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } PhysicalTable *Relationship::getReferenceTable(void) { /* Many to Many relationships doesn't has only one reference table so is returned nullptr */ if(rel_type==RelationshipNn) return(nullptr); else { if(src_table==getReceiverTable()) return(dynamic_cast(dst_table)); else return(dynamic_cast(src_table)); } } void Relationship::setSiglePKColumn(bool value) { if(rel_type==RelationshipNn) { single_pk_column=value; this->invalidated=(single_pk_column!=value); } } bool Relationship::isSiglePKColumn(void) { return(single_pk_column); } PhysicalTable *Relationship::getReceiverTable(void) { if(rel_type==Relationship11) { /* Case 1: (0,1) ---<>--- (0,1) Case 2: (1,1) ---<>--- (0,1) */ if((!src_mandatory && !dst_mandatory) || (src_mandatory && !dst_mandatory)) return(dynamic_cast(dst_table)); /* Case 3: (0,1) ---<>--- (1,1) */ else if(!src_mandatory && dst_mandatory) return(dynamic_cast(src_table)); // Case 4: (1,1) ---<>--- (1,1) else /* Returns nullptr since this type of relationship isn't implemented. Refer to header file top comment for details */ return(nullptr); } /* For 1-n relationships, the table order is unchagned this means that the columns are always included in the destination table */ else if(rel_type==Relationship1n) return(dynamic_cast(dst_table)); /* For generalization / copy relationships the columns are always added in the source table */ else if(rel_type==RelationshipGen || rel_type==RelationshipDep || rel_type==RelationshipPart) return(dynamic_cast(src_table)); //For n-n relationships, the columns are added in the table that represents the relationship (table_relnn) else return(dynamic_cast(table_relnn)); } void Relationship::removeTableObjectsRefCols(PhysicalTable *table) { Table *aux_table = dynamic_cast
(table); Trigger *trigger=nullptr; Index *index=nullptr; Constraint *constr=nullptr; int i, count; //Remove all triggers that reference columns added by relationship count=table->getTriggerCount(); for(i=0; i < count; i++) { trigger=table->getTrigger(i); if(trigger->isReferRelationshipAddedColumn()) { table->removeObject(trigger); delete(trigger); count--; i--; if(i < 0) i=0; } } if(aux_table) { //Remove all indexes that reference columns added by relationship count=aux_table->getIndexCount(); for(i=0; i < count; i++) { index=aux_table->getIndex(i); if(index->isReferRelationshipAddedColumn()) { aux_table->removeObject(index); delete(index); count--; i--; if(i < 0) i=0; } } } //Remove all constraints that reference columns added by relationship count=table->getConstraintCount(); for(i=0; i < count; i++) { constr=table->getConstraint(i); if(!constr->isAddedByRelationship() && constr->getConstraintType()!=ConstraintType::PrimaryKey && constr->isReferRelationshipAddedColumn()) { table->removeObject(constr); delete(constr); count--; i--; if(i < 0) i=0; } } } void Relationship::removeColumnsFromTablePK(PhysicalTable *table) { if(table) { Constraint *pk=nullptr; Column *column=nullptr; unsigned i, count; /* Gets the table primary key and removes the columns created by the relationship from it */ pk=table->getPrimaryKey(); if(pk) { count=pk->getColumnCount(Constraint::SourceCols); for(i=0; i < count; i++) { column=pk->getColumn(i, Constraint::SourceCols); //Case the column was added by relationship and it belongs to the relationship if(column->isAddedByRelationship() && (isColumnExists(column) || getObjectIndex(column) >= 0)) { //Removes the column from primary key pk->removeColumn(column->getName(), Constraint::SourceCols); i--; count--; } } } } } void Relationship::removeColumnFromTablePK(PhysicalTable *table, Column *column) { if(table && column) { Constraint *pk=nullptr; unsigned i, count; pk=table->getPrimaryKey(); if(pk) { count=pk->getColumnCount(Constraint::SourceCols); for(i=0; i < count; i++) { if(column==pk->getColumn(i, Constraint::SourceCols)) { pk->removeColumn(column->getName(), Constraint::SourceCols); break; } } } } } void Relationship::disconnectRelationship(bool rem_tab_objs) { try { if(connected || /* WORKAROUND: in a very specific case (under investigation) the relationship is marked as disconnected but the internal objects aren't destroyed. To avoid memory leaks we are forcing the disconnection and destroying any allocated object. It seems this issues happens only during loading process but is related to relationship disconnection, mixing fk rels and 1:n rels, and validation. */ (!connected && (fk_rel1n || pk_relident || uq_rel11 || table_relnn || pk_special))) { vector::iterator itr, itr_end; Column *column=nullptr; PhysicalTable *table=nullptr; unsigned list_idx=0; vector *attr_list=nullptr; vector::iterator itr_atrib, itr_atrib_end; TableObject *tab_obj=nullptr; if(rel_type==RelationshipGen || rel_type==RelationshipDep || rel_type== RelationshipPart) { table=getReceiverTable(); if(rem_tab_objs) removeTableObjectsRefCols(table); removeColumnsFromTablePK(table); //Removes the special primary key if(table->getObjectIndex(pk_special) >= 0) { table->removeObject(pk_special); // Restoring the original primary key of the table if(pk_original) table->addObject(pk_original); } if(rel_type==RelationshipGen || rel_type==RelationshipPart) { while(!ck_constraints.empty()) { table->removeObject(ck_constraints.back()); delete(ck_constraints.back()); ck_constraints.pop_back(); } } if(rel_type==RelationshipGen) table->removeObject(getReferenceTable()); else if(rel_type == RelationshipPart) table->setPartionedTable(nullptr); else table->setCopyTable(nullptr); } else { Constraint *pk=nullptr, *constr=nullptr; unsigned i, count; /* In case of relationship 1-1 and 1-n is necessary remove the foreign key that represents the relationship furthermore columns added to primary key (in case of a identifier relationship) must be removed */ if(fk_rel1n && (rel_type==Relationship11 || rel_type==Relationship1n)) { table=getReceiverTable(); /* Gets the table which has a foreign key that represents the relationship (the table where the foreign key was inserted upon connection of the relationship) */ if(fk_rel1n) //Removes the foreign key from table table->removeConstraint(fk_rel1n->getName()); /* Gets the table primary key to check if it is the same as the primary key that defines the identifier relationship */ pk=table->getPrimaryKey(); //Removes the relationship created columns from table primary key removeColumnsFromTablePK(table); if(rem_tab_objs) removeTableObjectsRefCols(table); if(fk_rel1n) { //Destroy the foreign key fk_rel1n->removeColumns(); delete(fk_rel1n); fk_rel1n=nullptr; } //Destroy the auto created unique key if it exists if(uq_rel11) { table->removeConstraint(uq_rel11->getName()); uq_rel11->removeColumns(); delete(uq_rel11); uq_rel11=nullptr; } /* Removes the primary key from the table in case of identifier relationship where the primary key is created on the weak entity */ if(pk && pk==this->pk_relident) { //Gets the table that own the identifier relationship primary key table=dynamic_cast
(pk_relident->getParentTable()); //Removes the primary key from table if(table) table->removeConstraint(pk_relident->getName()); //Destroy the primary key delete(pk); pk_relident=nullptr; } else if(pk_special && table->getObjectIndex(pk_special) >= 0) { table->removeObject(pk_special); // Restoring the original primary key of the table if(pk_original) table->addObject(pk_original); } } else if(rel_type==RelationshipNn) { //In case of n-n relationship destroy the added constraints count=table_relnn->getConstraintCount(); for(i=0; i < count ; i++) { constr=table_relnn->getConstraint(i); //Destroy the constraint only if it was created by the relationship if(constr->isAddedByRelationship() && getObjectIndex(constr) < 0) { table_relnn->removeConstraint(constr->getName()); i--; count--; delete(constr); } } } } table=getReceiverTable(); //Removing relationship attributes and constraints from the receiver table while(list_idx <= 1) { attr_list=(list_idx==0 ? &rel_constraints : &rel_attributes); itr_atrib=attr_list->begin(); itr_atrib_end=attr_list->end(); while(itr_atrib!=itr_atrib_end) { tab_obj=(*itr_atrib); //Removes the attribute from the table only it were created by this relationship ( getObjectIndex >= 0) if(table && getObjectIndex(tab_obj) >= 0 && tab_obj->getParentTable()) { table->removeObject(tab_obj); tab_obj->setParentTable(nullptr); } itr_atrib++; } list_idx++; } //Destroy the special pk before the generated columns to avoid crashes if(pk_special) { delete(pk_special); pk_special=nullptr; } itr=gen_columns.begin(); itr_end=gen_columns.end(); //Destroy the columns created by the relationship while(itr!=itr_end) { column=(*itr); //Before the destruction the column is removed from table table->removeColumn(column->getName()); itr++; delete(column); } gen_columns.clear(); pk_columns.clear(); if(table_relnn) { delete(table_relnn); table_relnn=nullptr; } pk_original = nullptr; BaseRelationship::disconnectRelationship(); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } bool Relationship::isIdentifier(void) { return(identifier); } void Relationship::setCopyOptions(CopyOptions copy_op) { copy_options=copy_op; if(connected) getReceiverTable()->setCopyTableOptions(copy_op); } CopyOptions Relationship::getCopyOptions(void) { return(copy_options); } bool Relationship::hasIndentifierAttribute(void) { vector::iterator itr, itr_end; Constraint *constr=nullptr; bool found=false; itr=rel_constraints.begin(); itr_end=rel_constraints.end(); while(itr!=itr_end && !found) { constr=dynamic_cast(*itr); /* A relationship is considered to own a identifier attribute when a primary key is found among the constraints */ found=(constr->getConstraintType()==ConstraintType::PrimaryKey); itr++; } return(found); } void Relationship::forceInvalidate(void) { this->invalidated=true; } bool Relationship::isInvalidated(void) { unsigned rel_cols_count=0, tab_cols_count=0, i=0, count=0; PhysicalTable *table=nullptr, *table1=nullptr; Constraint *fk=nullptr, *fk1=nullptr, *constr=nullptr, *pk=nullptr; bool valid=false; Column *rel_pk_col=nullptr, *gen_col=nullptr, *col_aux=nullptr, *col_aux1 = nullptr, *pk_col=nullptr; QString col_name; if(invalidated) { /* If the relationship is identifier, removes the primary key automatically created when the same is connected to force the receiver table be without a primary key as a result any relationship 1-1, 1-n or n-n connected to it should be revalidated */ if(pk_relident && pk_relident->isAddedByLinking()) { dynamic_cast(pk_relident->getParentTable())->removeObject(pk_relident); pk_relident=nullptr; } return(true); } else if(connected) { /* Checking if the tables were renamed. For 1:1, 1:n and n:n this situation may cause the renaming of all generated objects */ if((rel_type==Relationship11 || rel_type==Relationship1n || rel_type==RelationshipNn) && (src_tab_prev_name!=src_table->getName() || dst_tab_prev_name!=dst_table->getName())) return(true); /* For relationships 1-1 and 1-n the verification for invalidation of the relationship is based on the comparison of amount of foreign key columns and the number of columns of primary key from the source table */ if(rel_type==Relationship11 || rel_type==Relationship1n) { table=getReferenceTable(); //Gets the source columns from the foreign key that represents the relationship rel_cols_count=fk_rel1n->getColumnCount(Constraint::SourceCols); //The relationship is invalidated if the reference table doesn't has a primary key pk=table->getPrimaryKey(); if(pk) { //Gets the amount of columns from the primary key tab_cols_count=pk->getColumnCount(Constraint::SourceCols); //Compares the column quantity valid=(rel_cols_count==tab_cols_count); //The next validation is on the name and type of columns for(i=0; i < rel_cols_count && valid; i++) { //Gets one column from the foreign key gen_col=gen_columns[i]; //Gets one column from the primary key rel_pk_col=pk_columns[i]; /* This third columns is get from the table primary key and will be checked if the columns addresses is the same. If not the relationship is invalidated */ pk_col=pk->getColumn(i, Constraint::SourceCols); /* To validate the columns with each other the following rules are followed: 1) Check if the there was some name modification. If the generated name does is not compatible with the current generated column name, then the relationship is invalidated. 2) Check if the types of the columns are compatible. The only accepted exception is if the type of the source column is 'serial' or 'bigserial' and the target column is 'integer' or 'bigint'. 3) Check if the column (address) from the vector pk_columns is equal to the column obtained directly from the primary key */ col_name=generateObjectName(SrcColPattern, rel_pk_col); valid=(rel_pk_col==pk_col && (gen_col->getName()==col_name ||gen_col->getName().contains(pk_col->getName())) && (rel_pk_col->getType()==gen_col->getType() || (rel_pk_col->getType()==QString("serial") && gen_col->getType()==QString("integer")) || (rel_pk_col->getType()==QString("bigserial") && gen_col->getType()==QString("bigint")) || (rel_pk_col->getType()==QString("smallserial") && gen_col->getType()==QString("smallint")))); } } } /* For copy / generalization relationships, is obtained the number of columns created when connecting it and comparing with the number of columns of the source table */ else if(rel_type==RelationshipDep || rel_type==RelationshipGen || rel_type==RelationshipPart) { table=getReferenceTable(); table1=getReceiverTable(); //Gets the number of columns of the reference table tab_cols_count=table->getColumnCount(); /* Gets the number of columns created with the connection of the relationship and summing with the number of columns rejected at the time of connection according to the rules of copyColumns() method */ rel_cols_count=gen_columns.size() + rejected_col_count; valid=(rel_cols_count == tab_cols_count); /* Checking if the columns created with inheritance / copy still exist in reference table, and their types are compatible */ for(i=0; i < gen_columns.size() && valid; i++) { gen_col = gen_columns[i]; col_aux = table->getColumn(gen_col->getName(true)); valid = col_aux && (col_aux->getType().isEquivalentTo(gen_col->getType()) || col_aux->getType().getAliasType().isEquivalentTo(gen_col->getType())); } // Specific for partition relatoinship: check if all the columns on the source table (partition) exist on the partitioned table if(rel_type==RelationshipPart) { count = table1->getColumnCount(); valid = table->isPartitioned(); for(i=0; i < count && valid; i++) { col_aux1 = table1->getColumn(i); col_aux = table->getColumn(col_aux1->getName(true)); valid = col_aux && col_aux1 && (col_aux->getType().isEquivalentTo(col_aux1->getType()) || col_aux->getType().getAliasType().isEquivalentTo(col_aux1->getType())); } } /* Checking if the reference table columns are in the receiver table. In theory all columns must exist in the two table because one inherits another soon they will possess all the same columns. if this not happen indicates that a reference table column was renamed */ for(i=0; i < tab_cols_count && valid; i++) { col_aux = table->getColumn(i); col_aux1 = table1->getColumn(col_aux->getName(true)); valid = col_aux && col_aux1 && (col_aux->getType().isEquivalentTo(col_aux1->getType()) || col_aux->getType().getAliasType().isEquivalentTo(col_aux1->getType())); } //Checking if the check constraints were not renamed in the parent table for(i=0; i < ck_constraints.size() && valid; i++) { constr=table->getConstraint(ck_constraints[i]->getName(true)); valid=(constr && !constr->isNoInherit() && constr->getConstraintType()==ConstraintType::Check); } } /* For n-n relationships, it is necessary the comparisons: 1) Take up the foreign key table created by the connection which references the source table and verifies if the quantities of columns coincide. The same is done for the second foreign key except that is in relation to the primary key of the target table 2) It is necessary to validate if the names of the table columns generated matches the column names of the originating tables */ else if(rel_type==RelationshipNn) { table=dynamic_cast
(src_table); table1=dynamic_cast
(dst_table); /* To validated the n-n relationship, the first condition is that both tables has primary key */ if(table->getPrimaryKey() && table1->getPrimaryKey()) { count=table_relnn->getConstraintCount(); for(i=0; i < count; i++) { constr=table_relnn->getConstraint(i); if(constr->getConstraintType()==ConstraintType::ForeignKey) { if(!fk && constr->getReferencedTable()==table) fk=constr; else if(!fk1 && constr->getReferencedTable()==table1) fk1=constr; } } /* The number of columns of relationship is calculated by summing quantities of foreign key columns obtained */ rel_cols_count=fk->getColumnCount(Constraint::ReferencedCols) + fk1->getColumnCount(Constraint::ReferencedCols); /* The number of columns in the table is obtained by summing the amount of primary keys columns involved in the relationship */ tab_cols_count=table->getPrimaryKey()->getColumnCount(Constraint::SourceCols) + table1->getPrimaryKey()->getColumnCount(Constraint::SourceCols); valid=(rel_cols_count == tab_cols_count); // Checking if the columns created with the connection still exists in reference table count=fk->getColumnCount(Constraint::SourceCols); pk=table->getPrimaryKey(); for(i=0; i < count && valid; i++) { gen_col=fk->getColumn(i, Constraint::SourceCols); pk_col=pk->getColumn(i, Constraint::SourceCols); valid=(gen_col->getName()==generateObjectName(SrcColPattern, pk_col) || gen_col->getName().contains(pk_col->getName())); } // Checking if the columns created with the connection still exists in receiver table count=fk1->getColumnCount(Constraint::SourceCols); pk=table1->getPrimaryKey(); for(i=0; i < count && valid; i++) { gen_col=fk1->getColumn(i, Constraint::SourceCols); pk_col=pk->getColumn(i, Constraint::SourceCols); valid=(gen_col->getName()==generateObjectName(DstColPattern, pk_col) || gen_col->getName().contains(pk_col->getName())); } } } return(!valid); } else return(true); } QString Relationship::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type); if(!code_def.isEmpty()) return(code_def); if(def_type==SchemaParser::SqlDefinition) { if(fk_rel1n && (rel_type==Relationship11 || rel_type==Relationship1n)) { unsigned count, i; attributes[Attributes::Relationship1n]=Attributes::True; attributes[Attributes::Constraints]=fk_rel1n->getCodeDefinition(def_type); if(uq_rel11) attributes[Attributes::Constraints]+=uq_rel11->getCodeDefinition(def_type); count=rel_constraints.size(); for(i=0; i < count; i++) { if(dynamic_cast(rel_constraints[i])->getConstraintType()!=ConstraintType::PrimaryKey) attributes[Attributes::Constraints]+=dynamic_cast(rel_constraints[i])->getCodeDefinition(def_type, false); } attributes[Attributes::Table]=getReceiverTable()->getName(true); } else if(table_relnn && rel_type==RelationshipNn) { unsigned count, i; attributes[Attributes::RelationshipNn]=Attributes::True; attributes[Attributes::Table]=table_relnn->getCodeDefinition(def_type); count=table_relnn->getConstraintCount(); for(i=0; i < count; i++) { if(table_relnn->getConstraint(i)->getConstraintType()!=ConstraintType::PrimaryKey && table_relnn->getConstraint(i)->getConstraintType()!=ConstraintType::Check) attributes[Attributes::Constraints]+=table_relnn->getConstraint(i)->getCodeDefinition(def_type, true); } } else if(rel_type==RelationshipGen) { attributes[Attributes::RelationshipGen]=Attributes::True; attributes[Attributes::Table]=getReceiverTable()->getName(true); } return(this->BaseObject::__getCodeDefinition(SchemaParser::SqlDefinition)); } else { unsigned count, i; bool reduced_form; setRelationshipAttributes(); attributes[Attributes::Identifier]=(identifier ? Attributes::True : QString()); attributes[Attributes::SinglePkColumn]=(single_pk_column ? Attributes::True : QString()); attributes[Attributes::Deferrable]=(deferrable ? Attributes::True : QString()); attributes[Attributes::DeferType]=~deferral_type; attributes[Attributes::UpdAction]=~upd_action; attributes[Attributes::DelAction]=~del_action; attributes[Attributes::TableName]=tab_name_relnn; attributes[Attributes::RelationshipGen]=(rel_type==RelationshipGen ? Attributes::True : QString()); attributes[Attributes::RelationshipDep]=(rel_type==RelationshipDep ? Attributes::True : QString()); attributes[Attributes::RelationshipPart]=(rel_type==RelationshipPart ? Attributes::True : QString()); attributes[Attributes::SrcColPattern]=name_patterns[SrcColPattern]; attributes[Attributes::DstColPattern]=name_patterns[DstColPattern]; attributes[Attributes::PkPattern]=name_patterns[PkPattern]; attributes[Attributes::UqPattern]=name_patterns[UqPattern]; attributes[Attributes::SrcFkPattern]=name_patterns[SrcFkPattern]; attributes[Attributes::DstFkPattern]=name_patterns[DstFkPattern]; attributes[Attributes::PkColPattern]=name_patterns[PkColPattern]; attributes[Attributes::PartitionBoundExpr]=part_bounding_expr; attributes[Attributes::Columns]=QString(); count=rel_attributes.size(); for(i=0; i < count; i++) { attributes[Attributes::Columns]+=dynamic_cast(rel_attributes[i])-> getCodeDefinition(SchemaParser::XmlDefinition); } attributes[Attributes::Constraints]=QString(); count=rel_constraints.size(); for(i=0; i < count; i++) { if(!rel_constraints[i]->isProtected()) attributes[Attributes::Constraints]+=dynamic_cast(rel_constraints[i])-> getCodeDefinition(SchemaParser::XmlDefinition, true); } if(pk_original) { pk_original->setParentTable(getReceiverTable()); attributes[Attributes::OriginalPk]=pk_original->getCodeDefinition(SchemaParser::XmlDefinition); pk_original->setParentTable(nullptr); } count=column_ids_pk_rel.size(); for(i=0; i < count; i++) { if(!gen_columns.empty() && i < gen_columns.size()) { attributes[Attributes::SpecialPkCols]+=QString("%1").arg(column_ids_pk_rel[i]); if(i < count-1) attributes[Attributes::SpecialPkCols]+=","; } } if(copy_options.getCopyMode()!=0) { attributes[Attributes::CopyOptions]=QString("%1").arg(copy_options.getCopyOptionsIds()); attributes[Attributes::CopyMode]=QString("%1").arg(copy_options.getCopyMode()); } reduced_form=(attributes[Attributes::Columns].isEmpty() && attributes[Attributes::Constraints].isEmpty() && attributes[Attributes::Points].isEmpty() && attributes[Attributes::SpecialPkCols].isEmpty() && attributes[Attributes::Points].isEmpty() && attributes[Attributes::LabelsPos].isEmpty() && attributes[Attributes::PartitionBoundExpr].isEmpty()); if(!reduced_form) cached_reduced_code.clear(); return(this->BaseObject::getCodeDefinition(SchemaParser::XmlDefinition, reduced_form)); } } void Relationship::operator = (Relationship &rel) { (*dynamic_cast(this))=dynamic_cast(rel); this->invalidated=true; this->column_ids_pk_rel=rel.column_ids_pk_rel; this->rel_attributes=rel.rel_attributes; this->rel_constraints=rel.rel_constraints; this->identifier=rel.identifier; this->deferral_type=rel.deferral_type; this->deferrable=rel.deferrable; this->tab_name_relnn=rel.tab_name_relnn; this->table_relnn=nullptr; this->fk_rel1n=pk_relident=pk_special=nullptr; this->gen_columns.clear(); this->copy_options=rel.copy_options; this->name_patterns=rel.name_patterns; this->upd_action=rel.upd_action; this->del_action=rel.del_action; this->custom_color=rel.custom_color; this->single_pk_column=rel.single_pk_column; this->part_bounding_expr=rel.part_bounding_expr; } QString Relationship::getAlterRelationshipDefinition(bool undo_inh_part) { if(rel_type != RelationshipGen && rel_type != RelationshipPart) return(QString()); attributes[Attributes::Inherit]=QString(); attributes[Attributes::AncestorTable]=QString(); attributes[Attributes::PartitionedTable]=QString(); attributes[Attributes::PartitionBoundExpr]=QString(); attributes[Attributes::Partitioning]=QString(); attributes[Attributes::SqlObject]=getReferenceTable()->getSQLName(); if(rel_type == RelationshipGen) { attributes[Attributes::Inherit]=(undo_inh_part ? Attributes::Unset : Attributes::True); attributes[Attributes::Table]=getReceiverTable()->getName(true); attributes[Attributes::AncestorTable]=getReferenceTable()->getName(true); } else { attributes[Attributes::Partitioning]=(undo_inh_part ? Attributes::Unset : Attributes::True); attributes[Attributes::Table]=getReceiverTable()->getName(true); attributes[Attributes::PartitionedTable]=getReferenceTable()->getName(true); attributes[Attributes::PartitionBoundExpr]=getReceiverTable()->getPartitionBoundingExpr(); } return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes)); } bool Relationship::isReferenceTableMandatory(void) { if(rel_type == BaseRelationship::Relationship11 && getReferenceTable() == dst_table && !src_mandatory) return(dst_mandatory); else return((getReferenceTable() == src_table && isTableMandatory(SrcTable)) || (getReferenceTable() == dst_table && isTableMandatory(DstTable))); } bool Relationship::isReceiverTableMandatory(void) { if(rel_type == BaseRelationship::Relationship11 && getReferenceTable() == dst_table && !src_mandatory) return(false); else return((getReceiverTable() == src_table && isTableMandatory(SrcTable)) || (getReceiverTable() == dst_table && isTableMandatory(DstTable))); } pgmodeler-0.9.2/libpgmodeler/src/relationship.h000066400000000000000000000520511360462764600216270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Relationship \brief This class implements the operations to create relationship between tables also generates the SQL code definition to represente the table link on PostgreSQL. \note Creation date: 20/11/2006 */ #ifndef RELATIONSHIP_H #define RELATIONSHIP_H #include "baserelationship.h" #include "table.h" #include "textbox.h" /* ### Relationship implementation rules ### [One to One relationship (1:1)] (0,1) ---<>--- (0,1) >> Columns are added on the destination table in order to represent the relationship. >> The columns that represents the foreign key must accept null values. >> The policy for DELETE and UPDATE events on the foreign key must be SET NULL. >> The relationship attributes and constraints are added on same table where the foreign key columns are added. (1,1) ---<>--- (0,1) (0,1) ---<>--- (1,1) >> Columns ared added on the table which minimum cardinality is 0. >> The columns that represents the foreign key must accept null values. >> The policy for DELETE and UPDATE events on the foreign key must be SET NULL. >> The relationship attributes and constraints are added on same table where the foreign key columns are added. (1,1) ---<>--- (1,1) >> Not implemented because breaks the user modeling since its necessary to merge the envolved tables. If the user persists in creation of this type of relationship an error is raised. ------ [One to Many relationship (1:n)] (0,1) ---<>--- (0,n) (0,1) ---<>--- (1,n) (1,1) ---<>--- (0,n) (1,1) ---<>--- (1,n) >> Columns are added on the destination table in any cardinality combination. >> When the minimum cardinality is 0 on the "One" side (e.g. (0,1)) the foreign key columns must accept null values in order to represent the optionality of the relationship. Also the foreign key ON DELETE and ON UPDATE policy must be SET NULL. >> When the minimum cardinality is 1 on the "One" size (e.g. (1,1)) the foreign key columns mustn't accept null values (NOT NULL) to represent the entity mandatory participation. Also the foreign key ON DELETE and ON UPDATE policy must be RESTRICT. >> For identifier relationships the ON DELETE and ON UPDATE for the foreign key must be CASCADE because the weak entity only exists if the strong exists too. ------ [Many to Many relationship (n:n)] (n) ---<>--- (n) >> One table is created to represent the relationship. In the relationship type there is no cardinality this means that the relationship is alway represented as (n) ---<>--- (n). >> Two foreign key is created on the new table each pointing to one of the envolved tables. >> The ON DELETE policy for the foreign keys must be RESTRICT. >> The ON UPDATE policy for the foreign keys must be UPDATE. >> The created table primary key is the union of the two foreign key columns. ------ [Relationships of degree > 2] Must be manually simulated using the available binary relationships. ------ [NOTE] * Case one relationship attribute is the identifier (primary key) for the "Many to Many" table relationship the fisrt will be merge with the automaticaly created primary key. * "Many to Many" cannot be created as identifier because the two entities (tables) are always strong (in pgModeler's implementation). * Case the relationship is identifier, this means, there is a weak entity in one side of the relatioship must be used the following rule: 1) The weak entity primary key must be composed with the columns used to reference the strong entity (foreign key columns) 2) The ON DELETE and ON UPDATE policy for the foreign key must be CASCADE, because for instance, in the case of one tuple on the strong entity is deleted the weak entity tuples must be destroyed also because this latter exists only because the first. */ class Relationship: public BaseRelationship { private: /*! \brief Indicates that the relationship invalid because one or more critical attributes where modified needing to be revalidated */ bool invalidated, /*! \brief Indicates that the generated table primary key must have only a single column instead of the two from the foreign keys (only for n-n relationships) */ single_pk_column; /*! \brief Stores the number of columns which were rejected at the time of relationship connection. This is used only for generalization relationships because, according to the rule a column is rejected in inheritance when both tables have the same column of the same name and type. This attribute is used as an support to check if the relationship is invalidated or not. */ unsigned rejected_col_count; /*! \brief Stores the columns which are created to be referenced by foreign keys in order to represent the relationship */ vector gen_columns, /*! \brief Stores the primary key columns which from the referenced table This vector is used by the relationship validation method. */ pk_columns; /*! \brief Stores the names of the columns referenced earlier, where the key of the map is the identifier of each column created by the relationship. This map is filled when the relationship is of type 1-1 and 1-n and when it is disconnected and its referenced columns are deallocated, because in this the column name history is lost and may cause the breakdown of references. Yet at the time of connection the old names stored on this map are assigned to columns related to each primary key column that generates the referenced columns and finally this map is cleared */ map prev_ref_col_names; //! \brief This map stores the name patterns for objects generated by relationship map name_patterns; //! \brief Relationship attributes (used as columns on the receiver table) vector rel_attributes; //! \brief Relationship constraint (used as constraints on the receiver table) vector rel_constraints; //! \brief Foreign key that represents the 1-n relationship Constraint *fk_rel1n, /*! \brief Stores reference to the primary key automatically created when the relationship is identifier and the weak entity does not have a primary key */ *pk_relident, /*! \brief Stores the reference to the special primary key. This constraint is only available to generalization / copy relationships */ *pk_special, *pk_original, //! \brief Stores the unique key that represents the 1-1 relationship (including the fk_rel1n) *uq_rel11; //! \brief Stores the CHECK constraints copied from the parent table to its child vector ck_constraints; //! \brief Table created by the relationship n-n Table *table_relnn; //! \brief Indicates if the relationship is identifier (when there is a strong and a weak entity) bool identifier; //! \brief Indicates if the foreign key (for 1-1, 1-n relationships) is deferrable bool deferrable; ActionType del_action, upd_action; //! \brief Deferral type used by the foreign key when this is deferrable DeferralType deferral_type; //! \brief Copy options assinged to receiver table (only copy relationship) CopyOptions copy_options; /*! \brief This vector allows the user to define which columns inherited / copied (via its indexes) will be used on the special primary key in the receiver table */ vector column_ids_pk_rel; //! \brief Name assigned to the generated table on n-n relationships QString tab_name_relnn, src_tab_prev_name, dst_tab_prev_name; //! \brief The partition bounding expression QString part_bounding_expr; //! \brief Indicates if the column exists on the referenced column list bool isColumnExists(Column *column); //! \brief Executes the column addition for 1-1 relationship void addColumnsRel11(void); //! \brief Executes the column addition for 1-n relationship void addColumnsRel1n(void); //! \brief Executes the column addition for n-n relationship void addColumnsRelNn(void); /*! \brief Copy columns from one table to another. This operation is done in relationships of type copy / generalization. It is necessary to check duplicate names and incompatible types of columns */ void addColumnsRelGenPart(void); /*! \brief Copy constraints from the parent table to the child. Currently, only check constraints are copied only if the NO INHERIT attribute is not set and there are no conflicting constraints (name or expression) on the child table */ void addConstraintsRelGenPart(void); /*! \brief Creates the foreign key that represents the relationship and adds it to the receiver table. Must be specified the actions ON DELETE and UPDATE. */ void addForeignKey(PhysicalTable *ref_tab, PhysicalTable *recv_tab, ActionType del_act, ActionType upd_act); /*! \brief Creates the unique key that represents the 1-1 relationship e adds it to the receiver table */ void addUniqueKey(PhysicalTable *recv_tab); //! \brief Adds the relationship attributes (columns) into receiver table void addAttributes(PhysicalTable *recv_tab); /*! \brief Adds relationship constraints on the receiver table. If the relationship is of type n-n, constraints will be added to the created table. If among the constraints there is a primary key, then it will be merged with the primary key of receiver table */ void addConstraints(PhysicalTable *recv_tab); /*! \brief Executes adicional configurations on receiver table primary key when the relationship is identifier */ void configureIndentifierRel(PhysicalTable *recv_tab); /*! \brief Copy the columns from the reference table to the receiver table. The parameter not_null indicates that the columns must not accept null values. The parameter is_dst_table is used to force the usage of destination table and destination name pattern when creating a self many-to-many relationship */ void copyColumns(PhysicalTable *ref_tab, PhysicalTable *recv_tab, bool not_null, bool is_dst_table = false); /*! \brief This method is always executed before disconnection of the relationship. Its function is to remove from the specified table all the attributes which references any relationship generated column avoiding reference break */ void removeTableObjectsRefCols(PhysicalTable *table); //! \brief Creates the special primary key using the names stored in the 'column_ids_pk_rel' vector void createSpecialPrimaryKey(void); //! \brief Removes all the columns created by the relationship from the specified table primary key if exists. void removeColumnsFromTablePK(PhysicalTable *table); //! \brief Removes a single column created by the relationship from the specified table primary key if exists. void removeColumnFromTablePK(PhysicalTable *table, Column *column); //! \brief Generates the object name according to the specified name pattern QString generateObjectName(unsigned pat_id, Column *id_col=nullptr, bool use_alias=false); void setOriginalPrimaryKey(Constraint *pk); protected: //! \brief Destroy all the relationship attributes and constraints void destroyObjects(void); //! \brief Returns all the refenced columns of the relationship vector getGeneratedColumns(void); //! \brief Returns the table generated by the n-n relationship Table *getGeneratedTable(void); /*! \brief Returns the generated foreign key that represents the 1-1, 1-n relationship, as well the primary key generated by the identifier relationship and the unique key used in 1-1 relationships */ vector getGeneratedConstraints(void); public: //! \brief String used as the name suffix separator. Default '_' static const QString SuffixSeparator, SrcTabToken, //{st} DstTabToken, //{dt} GenTabToken, //{gt} SrcColToken; //{sc} //! \brief Patterns ids static constexpr unsigned SrcColPattern=0, DstColPattern=1, PkPattern=2, UqPattern=3, SrcFkPattern=4, DstFkPattern=5, PkColPattern=6; Relationship(Relationship *rel); Relationship(unsigned rel_type, PhysicalTable *src_tab, PhysicalTable *dst_tab, bool src_mdtry=false, bool dst_mdtry=false, bool identifier=false, bool deferrable=false, DeferralType deferral_type=DeferralType::Immediate, ActionType fk_del_act=ActionType::Null, ActionType fk_upd_act=ActionType::Null, CopyOptions copy_op = CopyOptions(0,0)); //! \brief Connects the relationship making the configuration according to its type void connectRelationship(void); /*! \brief Disconnects the relationship from the tables removing all the attributes / constraints deallocating all the created object. */ void disconnectRelationship(bool rem_tab_objs=true); //! \brief Defines the mandatory participation for the specified table void setMandatoryTable(unsigned table_id, bool value); /*! \brief Warning: This method is effective only when the relationship is connected. Only in this situation you obtain the columns generated by connecting relationship. This method defines what columns inherited / copied will be used as special primary key on receiver table. When the relationship is connected the special primary key is created using the columns inherited / copied. This special primary key is always destroyed when the relationship is disconnected and recreated when connected. This is a way available to the user create primary keys using the relationship included columns because on the current modeling, its not possibl directly create primary keys in the receiver table using columns created by the relationship. ** This feature can only be used in generalization / copy relationships ** */ void setSpecialPrimaryKeyCols(vector &cols); //! \brief Returns the column indexes used by the special primary key vector getSpecialPrimaryKeyCols(void); //! \brief Defines the name of the auto generated table on the n-n relationship void setTableNameRelNN(const QString &name); //! \brief Returns the name of the table auto generated by the n-n relationship QString getTableNameRelNN(void); /*! \brief Defines the partition bounding expression associated to the partition table (receiver table) * when the relationship is connected (only for partitioning relationship) */ void setPartitionBoundingExpr(const QString &part_bound_expr); //! \brief Returns the partition bouding expression configured for the relationship (only for partitioning relationship) QString getPartitionBoundingExpr(void); //! \brief Defines if the created foreign key is deferrable (only for 1-1, 1-n relationships) void setDeferrable(bool value); //! \brief Returns if the created foreign key is deferrable (only for 1-1, 1-n relationships) bool isDeferrable(void); //! \brief Defines the deferral type for the created foreign key (only for 1-1, 1-n relationships) void setDeferralType(DeferralType defer_type); /*! \brief Defines the type of action for generated foreign keys (ON DELETE and ON UPDATE) User must use Constraint::[DELETE_ACTION|UPDATE_ACTION] (only for 1-1, 1-n relationships) */ void setActionType(ActionType act_type, unsigned act_id); //! \brief Returns the deferral tyep for the created foreign key (only for 1-1, 1-n relationships) DeferralType getDeferralType(void); //! \brief Defines if the relationship is identifier void setIdentifier(bool value); //! \brief Returns if the relationship is identifier bool isIdentifier(void); //! \brief Set the copy options (only for copy relationships) void setCopyOptions(CopyOptions copy_op); //! \brief Defines the format for the specified pattern void setNamePattern(unsigned pat_id, const QString &pattern); //! \brief Gets the current format for the specified pattern QString getNamePattern(unsigned pat_id); //! \brief Returns the current copy options CopyOptions getCopyOptions(void); //! \brief Retuns the action type (ON DELETE or ON UPDATE) of the generated foreign keys ActionType getActionType(unsigned act_id); /*! \brief Returns if the relationship is invalidated in relation to propagation of columns. This method makes a series of verifications for each type of relationship, and if in any condition this method returns 'true' indicates that the relationship is no longer valid and must be reconnected. The reconnection operation is made on de model class ​​only because it treats all cases of invalidity at once. */ bool isInvalidated(void); /*! \brief Forces the relationship to go into invalidated state. This method is useful to invalidate the relationship without add/remove attributes from it. Calling this method will cause the model to revalidate the relationship even it's structure does not reflect an invalid state (see isInvalidate). Use this wisely or it can cause huge slow downs or unexpected results. */ void forceInvalidate(void); //! \brief Adds an attribute or constaint to the relationship. void addObject(TableObject *tab_obj, int obj_idx=-1); //! \brief Returns one attribute or constraint using its name TableObject *getObject(const QString &name, ObjectType obj_type); //! \brief Returns one attribute or constraint using its index TableObject *getObject(unsigned obj_idx, ObjectType obj_type); //! \brief Removes on attribute or constraint using its index void removeObject(unsigned obj_id, ObjectType obj_type); //! \brief Removes the specified attribute or constraint from the relationship void removeObject(TableObject *object); //! \brief Remove one attribute using its index void removeAttribute(unsigned attrib_idx); //! \brief Remove one constraint using its index void removeConstraint(unsigned constr_idx); //! \brief Gets an attribute using its index Column *getAttribute(unsigned attrib_idx); //! \brief Gets an attribute using its name Column *getAttribute(const QString &name); //! \brief Returns the list of user added attributes vector getAttributes(void); //! \brief Gets an constraint using its index Constraint *getConstraint(unsigned constr_idx); //! \brief Gets an constraint using its name Constraint *getConstraint(const QString &name); //! \brief Returns the list of user added constraints vector getConstraints(void); /*! \brief Returns the index of a relationship attribute or constraint. Returns -1 when the object doesn't exists */ int getObjectIndex(TableObject *object); //! \brief Returns the attribute count unsigned getAttributeCount(void); //! \brief Returns the constraint count unsigned getConstraintCount(void); //! \brief Returns the attribute or constraint count unsigned getObjectCount(ObjectType obj_type); /*! \brief Returns if the relationship has one or more identifier attributes. Identifier attributes are attributes which belongs to a primary key added by the user. This method only scans the list of constraints on the relationship searching for primary keys created by the user. If found returns true. */ bool hasIndentifierAttribute(void); /*! \brief Returns table that receives a copy of the columns that represent the relationship according to its configuration. WARNING: Not necessarily this method returns the destination table this because not in all relationship configuration the receiver is the destination table */ PhysicalTable *getReceiverTable(void); /*! \brief Returns table which serves as a reference when coping the columns to the receiver table. WARNING: Not necessarily this method returns the source table because not in all relationship configuration the reference is the source table For n-n relationships this method returns nullptr as this type of relationship has 2 reference tables, which may be obtained by the method BaseRelationship::getTable() */ PhysicalTable *getReferenceTable(void); void setSiglePKColumn(bool value); bool isSiglePKColumn(void); //! \brief Returns SQL / XML definition for the relationship. virtual QString getCodeDefinition(unsigned def_type) final; //! \brief Copies the attributes from one relationship to another void operator = (Relationship &rel); QString getAlterRelationshipDefinition(bool undo_inh_part); //! \brief Returns true when the reference table is mandatory in the relationship bool isReferenceTableMandatory(void); //! \brief Returns true when the receiver table is mandatory in the relationship bool isReceiverTableMandatory(void); friend class DatabaseModel; friend class ModelWidget; friend class RelationshipWidget; friend class ModelExportHelper; friend class ModelsDiffHelper; }; #endif pgmodeler-0.9.2/libpgmodeler/src/role.cpp000066400000000000000000000266401360462764600204270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "role.h" unsigned Role::role_id=0; Role::Role(void) { obj_type=ObjectType::Role; object_id=Role::role_id++; for(unsigned i=0; i <= OpBypassRls; i++) options[i]=false; conn_limit=-1; attributes[Attributes::Superuser]=QString(); attributes[Attributes::CreateDb]=QString(); attributes[Attributes::CreateRole]=QString(); attributes[Attributes::Inherit]=QString(); attributes[Attributes::Login]=QString(); attributes[Attributes::ConnLimit]=QString(); attributes[Attributes::Password]=QString(); attributes[Attributes::Encrypted]=QString(); attributes[Attributes::Validity]=QString(); attributes[Attributes::RefRoles]=QString(); attributes[Attributes::MemberRoles]=QString(); attributes[Attributes::AdminRoles]=QString(); attributes[Attributes::Replication]=QString(); attributes[Attributes::Group]=QString(); attributes[Attributes::BypassRls]=QString(); attributes[Attributes::EmptyPassword]=QString(); } void Role::setOption(unsigned op_type, bool value) { if(op_type > OpBypassRls) //Raises an error if the option type is invalid throw Exception(ErrorCode::AsgValueInvalidRoleOptionType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(options[op_type] != value); options[op_type]=value; } void Role::addRole(unsigned role_type, Role *role) { //Raises an error if the role to be added is not allocated if(!role) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the role to be added is the 'this' role else if(role && this==role) throw Exception(Exception::getErrorMessage(ErrorCode::AsgRoleMemberItself) .arg(role->getName()), ErrorCode::AsgRoleMemberItself,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { bool role_ref, role_mem, role_adm, role_ref1, role_mem1, role_adm1; //Check if the role to be added already exists in one of the internal role list role_ref=this->isRoleExists(RefRole, role); role_mem=this->isRoleExists(MemberRole, role); role_adm=this->isRoleExists(AdminRole, role); /* Check if the role 'this' is referenced in one of the internal role list of the role to be added */ role_ref1=role->isRoleExists(RefRole, this); role_mem1=role->isRoleExists(MemberRole, this); role_adm1=role->isRoleExists(AdminRole, this); //Raises an error if the role already exists in one of the internal list if((role_type==RefRole && role_ref) || (role_type==MemberRole && (role_mem || role_adm)) || (role_type==AdminRole && (role_adm || role_mem))) throw Exception(Exception::getErrorMessage(ErrorCode::InsDuplicatedRole) .arg(role->getName()) .arg(this->getName()), ErrorCode::InsDuplicatedRole,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Checking for redundant reference between roles. A redundant reference can happen when: 1) The role 'this' is already part of the 'ref_roles' list of 'role' object and the user try to add the object 'role' (from parameter) as an element of 'ref_roles' list of role 'this' 2) The role 'this' is already part of the 'member_roles' list of 'role' object and the user try to add the object 'role' (from parameter) as an element of the 'member_roles' of role 'this' 3) The role 'this' is already part of the 'admin_roles' list of 'role' object and the user try to add the 'role' object (from parameter) as an element of 'admin_roles' list of role 'this' 4) The role 'role' (from parameter) is already part of the 'member_roles' or 'admin_roles' list of the 'this' role and the user try to add the object 'role' as an element of the 'ref_roles' of the role 'this' 5) The role 'role' (from parameter) is already part of the 'ref_roles' list of role 'this' and the user try to add the object 'role' as an element of the 'member_roles' list of the role 'this' */ else if((role_type==RefRole && ((role_mem || role_adm) || role_ref1)) || (role_type==MemberRole && ((role_mem1 || role_adm1) || role_ref)) || (role_type==AdminRole && ((role_mem1 || role_adm1) || role_ref))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgRoleReferenceRedundancy) .arg(this->getName()) .arg(role->getName()), ErrorCode::AsgRoleReferenceRedundancy,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { switch(role_type) { case MemberRole: member_roles.push_back(role); break; case AdminRole: admin_roles.push_back(role); break; case RefRole: default: ref_roles.push_back(role); break; } setCodeInvalidated(true); } } } void Role::setConnectionLimit(int limit) { setCodeInvalidated(conn_limit != limit); conn_limit=limit; } void Role::setValidity(const QString &date) { setCodeInvalidated(validity != date); validity=date.mid(0,19); } void Role::setPassword(const QString &passwd) { setCodeInvalidated(password != passwd); this->password=passwd; } void Role::setRoleAttribute(unsigned role_type) { QString str_roles, attrib; unsigned i, count; vector *roles_vect=nullptr; switch(role_type) { case MemberRole: roles_vect=&member_roles; attrib=Attributes::MemberRoles; break; case AdminRole: roles_vect=&admin_roles; attrib=Attributes::AdminRoles; break; case RefRole: default: roles_vect=&ref_roles; attrib=Attributes::RefRoles; break; } count=roles_vect->size(); for(i=0; i < count; i++) { str_roles+=roles_vect->at(i)->getName(true); if(i < (count-1)) str_roles+=QString(","); } attributes[attrib]=str_roles; } void Role::removeRole(unsigned role_type, unsigned role_idx) { vector *list=nullptr; vector::iterator itr; switch(role_type) { case RefRole: list=&ref_roles; break; case MemberRole: list=&member_roles; break; case AdminRole: list=&admin_roles; break; default: //Raises an error if the role type is invalid throw Exception(ErrorCode::RefInvalidRoleType,__PRETTY_FUNCTION__,__FILE__,__LINE__); break; } if(role_idx >= list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=list->begin() + role_idx; list->erase(itr); setCodeInvalidated(true); } void Role::removeRoles(unsigned role_type) { vector *list=nullptr; switch(role_type) { case RefRole: list=&ref_roles; break; case MemberRole: list=&member_roles; break; case AdminRole: list=&admin_roles; break; default: //Raises an error if the role type is invalid throw Exception(ErrorCode::RefInvalidRoleType,__PRETTY_FUNCTION__,__FILE__,__LINE__); break; } list->clear(); setCodeInvalidated(true); } bool Role::isRoleExists(unsigned role_type, Role *role) { vector *list=nullptr; vector::iterator itr, itr_end; bool found=false; switch(role_type) { case RefRole: list=&ref_roles; break; case MemberRole: list=&member_roles; break; case AdminRole: list=&admin_roles; break; default: //Raises an error if the role type is invalid throw Exception(ErrorCode::RefInvalidRoleType,__PRETTY_FUNCTION__,__FILE__,__LINE__); break; } itr=list->begin(); itr_end=list->end(); while(!found && itr!=itr_end) { found=((*itr)==role); itr++; } return(found); } bool Role::getOption(unsigned op_type) { if(op_type > OpBypassRls) throw Exception(ErrorCode::AsgValueInvalidRoleOptionType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(options[op_type]); } Role *Role::getRole(unsigned role_type, unsigned role_idx) { vector *list=nullptr; switch(role_type) { case RefRole: list=&ref_roles; break; case MemberRole: list=&member_roles; break; case AdminRole: list=&admin_roles; break; default: //Raises an error if the role type is invalid throw Exception(ErrorCode::RefInvalidRoleType,__PRETTY_FUNCTION__,__FILE__,__LINE__); break; } //Raises an error if the role index is invalid (out of bound) if(role_idx > list->size()) throw Exception(ErrorCode::RefRoleInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(list->at(role_idx)); } unsigned Role::getRoleCount(unsigned role_type) { vector *list=nullptr; switch(role_type) { case RefRole: list=&ref_roles; break; case MemberRole: list=&member_roles; break; case AdminRole: list=&admin_roles; break; default: //Raises an error if the role type is invalid throw Exception(ErrorCode::RefInvalidRoleType,__PRETTY_FUNCTION__,__FILE__,__LINE__); break; } return(list->size()); } unsigned Role::getConnectionLimit(void) { return(conn_limit); } QString Role::getValidity(void) { return(validity); } QString Role::getPassword(void) { return(password); } QString Role::getCodeDefinition(unsigned def_type) { return(getCodeDefinition(def_type, false)); } QString Role::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); unsigned i; QString op_attribs[]={ Attributes::Superuser, Attributes::CreateDb, Attributes::CreateRole, Attributes::Inherit, Attributes::Login, Attributes::Encrypted, Attributes::Replication, Attributes::BypassRls }; setRoleAttribute(RefRole); setRoleAttribute(MemberRole); setRoleAttribute(AdminRole); for(i=0; i <= OpBypassRls; i++) attributes[op_attribs[i]]=(options[i] ? Attributes::True : QString()); attributes[Attributes::Password]=password; attributes[Attributes::Validity]=validity; if(conn_limit >= 0) attributes[Attributes::ConnLimit]=QString("%1").arg(conn_limit); return(BaseObject::getCodeDefinition(def_type, reduced_form)); } QString Role::getAlterDefinition(BaseObject *object, bool ignore_name_diff) { Role *role=dynamic_cast(object); if(!role) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { attribs_map attribs; QString op_attribs[]={ Attributes::Superuser, Attributes::CreateDb, Attributes::CreateRole, Attributes::Inherit, Attributes::Login, Attributes::Encrypted, Attributes::Replication, Attributes::BypassRls }; attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object, ignore_name_diff); if(this->password!=role->password) { attribs[Attributes::EmptyPassword]=role->password.isEmpty() ? Attributes::True : QString(); attribs[Attributes::Password]=role->password; } if(this->validity!=role->validity) attribs[Attributes::Validity]=role->validity; for(unsigned i=0; i <= OpBypassRls; i++) { if((attribs.count(Attributes::Password) && i==OpEncrypted) || this->options[i]!=role->options[i]) attribs[op_attribs[i]]=(role->options[i] ? Attributes::True : Attributes::Unset); } copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/role.h000066400000000000000000000076471360462764600201020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Role \brief Implements the operations to manipulate roles on the database. \note Creation date: 12/05/2008 */ #ifndef ROLE_H #define ROLE_H #include "baseobject.h" class Role: public BaseObject { private: static unsigned role_id; /*! \brief Options for the role (SUPERUSER, CREATEDB, CREATEROLE, INHERIT, LOGIN, ENCRYPTED, REPLICATION, BYPASSRLS) */ bool options[8]; //! \brief Connection limit for the role int conn_limit; //! \brief Validity date for the role QString validity, //! \brief Authentication password password; //! \brief Roles that has the 'this' role as member vector ref_roles, //! \brief IN ROLE //! \brief Member roles of 'this' role member_roles, //! \brief ROLE //! \brief Member roles of 'this' role whit admin privileges admin_roles; //! \brief ADMIN //! \brief Formats the role attribute to be used by the SchemaParser void setRoleAttribute(unsigned role_type); public: //! \brief Constants used to reference the available options for the role static constexpr unsigned OpSuperuser=0, OpCreateDb=1, OpCreateRole=2, OpInherit=3, OpLogin=4, OpEncrypted=5, OpReplication=6, OpBypassRls=7; //! \brief Constants used to reference the internal role lists of the class static constexpr unsigned RefRole=10, MemberRole=20, AdminRole=30; Role(void); //! \brief Sets one option for the role (Via OP_??? constants) void setOption(unsigned op_type, bool value); //! \brief Adds one role to the internal role list (Via ???_ROLE constants) void addRole(unsigned role_type, Role *role); //! \brief Defines the connection limit for the role void setConnectionLimit(int limit); //! \brief Defines the validity date for the role void setValidity(const QString &date); //! \brief Sets the password for the role void setPassword(const QString &passwd); //! \brief Gets on option for the role (Via OP_??? constants) bool getOption(unsigned op_type); //! \brief Remove one role from internal role list (Via ???_ROLE constants) void removeRole(unsigned role_type, unsigned role_idx); //! \brief Remove all roles from one iternal list (Via ???_ROLE constants) void removeRoles(unsigned role_type); /*! \brief Gets one role from internal list (Via ???_ROLE constants) referencing the object by its index */ Role *getRole(unsigned role_type, unsigned role_idx); //! \brief Returns whether the role exists on the internal lists (Via ???_ROLE constants) bool isRoleExists(unsigned role_type, Role *role); //! \brief Gets the role count on the specified internal list (Via ???_ROLE constants) unsigned getRoleCount(unsigned role_type); //! \brief Returns the connection limit for the role unsigned getConnectionLimit(void); //! \brief Returns the validity date for the role QString getValidity(void); //! \brief Returns the role password QString getPassword(void); //! \brief Returns the SQL / XML definition for the role virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; virtual QString getAlterDefinition(BaseObject *object, bool ignore_name_diff=false) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/rule.cpp000066400000000000000000000067721360462764600204410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "rule.h" Rule::Rule(void) { execution_type=BaseType::Null; obj_type=ObjectType::Rule; attributes[Attributes::EventType]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::Condition]=QString(); attributes[Attributes::ExecType]=QString(); attributes[Attributes::Commands]=QString(); } void Rule::setCommandsAttribute(void) { QString str_cmds; unsigned i, qtd; qtd=commands.size(); for(i=0; i < qtd; i++) { str_cmds+=commands[i]; if(i < (qtd-1)) str_cmds+=QString(";"); } attributes[Attributes::Commands]=str_cmds; } void Rule::setEventType(EventType type) { setCodeInvalidated(event_type != type); event_type=type; } void Rule::setExecutionType(ExecutionType type) { setCodeInvalidated(execution_type != type); execution_type=type; } void Rule::setConditionalExpression(const QString &expr) { setCodeInvalidated(conditional_expr != expr); conditional_expr=expr; } void Rule::addCommand(const QString &cmd) { //Raises an error if the command is empty if(cmd.isEmpty()) throw Exception(ErrorCode::InsEmptyRuleCommand,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { QString cmd_aux=cmd; cmd_aux.remove(';'); commands.push_back(cmd_aux); setCodeInvalidated(true); } } EventType Rule::getEventType(void) { return(event_type); } ExecutionType Rule::getExecutionType(void) { return(execution_type); } QString Rule::getConditionalExpression(void) { return(conditional_expr); } QString Rule::getCommand(unsigned cmd_idx) { //Raises an error if the command index is out of bound if(cmd_idx >= commands.size()) throw Exception(ErrorCode::RefRuleCommandInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(commands[cmd_idx]); } unsigned Rule::getCommandCount(void) { return(commands.size()); } void Rule::removeCommand(unsigned cmd_idx) { //Raises an error if the command index is out of bound if(cmd_idx>=commands.size()) throw Exception(ErrorCode::RefRuleCommandInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); commands.erase(commands.begin() + cmd_idx); setCodeInvalidated(true); } void Rule::removeCommands(void) { commands.clear(); setCodeInvalidated(true); } QString Rule::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); setCommandsAttribute(); attributes[Attributes::Condition]=conditional_expr; attributes[Attributes::ExecType]=(~execution_type); attributes[Attributes::EventType]=(~event_type); if(getParentTable()) attributes[Attributes::Table]=getParentTable()->getName(true); return(BaseObject::__getCodeDefinition(def_type)); } QString Rule::getSignature(bool format) { if(!getParentTable()) return(BaseObject::getSignature(format)); return(QString("%1 ON %2").arg(this->getName(format)).arg(getParentTable()->getSignature(true))); } pgmodeler-0.9.2/libpgmodeler/src/rule.h000066400000000000000000000053171360462764600201000ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Rule \brief Implements the operations to manipulate table rules. \note Creation date: 26/09/2006 */ #ifndef RULE_H #define RULE_H #include "tableobject.h" #include "column.h" class Rule: public TableObject{ private: //! \brief Commands executed by the rule when activated vector commands; //! \brief Conditional expression for the rule activation QString conditional_expr; //! \brief Rule execution type (ALSO or INSTEAD) ExecutionType execution_type; //! \brief Event when the rule is triggered (ON SELECT, NO UPDATE, ON INSERT, ON DELETE) EventType event_type; //! \brief Formats the commands string to be used by the SchemaParser void setCommandsAttribute(void); public: Rule(void); //! \brief Adds the SQL command to be executed by the rule void addCommand(const QString &cmd); //! \brief Sets the conditional expression for the rule void setConditionalExpression(const QString &expr); //! \brief Sets the rule execution type (ALSO, INSTEAD) void setExecutionType(ExecutionType type); //! \brief Defines the event when the rule is triggered void setEventType(EventType type); //! \brief Returns one command executed by the rule using its index QString getCommand(unsigned cmd_idx); //! \brief Returns the SQL command count unsigned getCommandCount(void); //! \brief Returns the conditional expression for the rule QString getConditionalExpression(void); //! \brief Returns the event when the rule is triggered EventType getEventType(void); //! \brief Returns the execution type for the rule ExecutionType getExecutionType(void); //! \brief Removes one command form the rule using its index void removeCommand(unsigned cmd_idx); //! \brief Remove all commands from the rule void removeCommands(void); //! \brief Returns the SQL / XML definition for the rule virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getSignature(bool format=true) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/schema.cpp000066400000000000000000000041701360462764600207200ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "schema.h" Schema::Schema(void) { obj_type=ObjectType::Schema; fill_color=QColor(225,225,225, 80); rect_visible=false; attributes[Attributes::FillColor]=QString(); attributes[Attributes::RectVisible]=QString(); } void Schema::setName(const QString &name) { /* Schema names starting with pg_ is reserved to PostgreSQL if its the case raises an error */ if(name.mid(0,3)==QString("pg_")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgReservedName) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Schema)), ErrorCode::AsgReservedName,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObject::setName(name); } void Schema::setFillColor(const QColor &color) { setCodeInvalidated(fill_color != color); this->fill_color=color; } QColor Schema::getFillColor(void) { return(fill_color); } void Schema::setRectVisible(bool value) { setCodeInvalidated(rect_visible != value); rect_visible=value; } bool Schema::isRectVisible(void) { return(rect_visible); } QString Schema::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Layer]=QString::number(layer); attributes[Attributes::FillColor]=fill_color.name(); attributes[Attributes::RectVisible]=(rect_visible ? Attributes::True : QString()); setFadedOutAttribute(); return(BaseObject::__getCodeDefinition(def_type)); } pgmodeler-0.9.2/libpgmodeler/src/schema.h000066400000000000000000000025001360462764600203600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Schema \brief Implements the operations to manipulate schemas on the database. \note Creation date: 07/04/2008 */ #ifndef SCHEMA_H #define SCHEMA_H #include "basegraphicobject.h" #include class Schema: public BaseGraphicObject { private: QColor fill_color; bool rect_visible; public: Schema(void); void setName(const QString &name); void setFillColor(const QColor &color); QColor getFillColor(void); void setRectVisible(bool value); bool isRectVisible(void); virtual QString getCodeDefinition(unsigned def_type) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/sequence.cpp000066400000000000000000000331361360462764600212740ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sequence.h" const QString Sequence::MaxPositiveValue=QString("+2147483647"); const QString Sequence::MaxNegativeValue=QString("-2147483648"); const QString Sequence::MaxSmallPositiveValue=QString("+32767"); const QString Sequence::MaxSmallNegativeValue=QString("-32768"); const QString Sequence::MaxBigPositiveValue=QString("+9223372036854775807"); const QString Sequence::MaxBigNegativeValue=QString("-9223372036854775808"); Sequence::Sequence(void) { obj_type=ObjectType::Sequence; cycle=false; setDefaultValues(PgSqlType(QString("serial"))); owner_col=nullptr; attributes[Attributes::Increment]=QString(); attributes[Attributes::MinValue]=QString(); attributes[Attributes::MaxValue]=QString(); attributes[Attributes::Start]=QString(); attributes[Attributes::Cache]=QString(); attributes[Attributes::Cycle]=QString(); attributes[Attributes::OwnerColumn]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::Column]=QString(); attributes[Attributes::ColIsIdentity]=QString(); } bool Sequence::isZeroValue(const QString &value) { if(value.isEmpty()) return(false); unsigned i, count; bool is_zero; i=0; is_zero=true; count=value.size(); while(i < count && is_zero) { is_zero=(value[i]=='0' || value[i]=='+' || value[i]=='-'); i++; } return(is_zero); } bool Sequence::isValidValue(const QString &value) { if(value.isEmpty()) return(false); /* To be valid the value can be start with + or -, have only numbers and it's length must not exceed the MAX_POSITIVE_VALUE length */ if(value.size() > MaxBigPositiveValue.size()) return(false); else { unsigned i, count; bool is_oper=false, is_num=false, is_valid=true; count=value.size(); for(i=0; i < count && is_valid; i++) { if((value[i]=='-' || value[i]=='+') && !is_num) { if(!is_oper) is_oper=true; } else if((value[i]>='0' && value[i]<='9')) { if(!is_num) is_num=true; } else is_valid=false; } if(!is_num) is_valid=false; return(is_valid); } } QString Sequence::formatValue(const QString &value) { QString fmt_value; //Before format the value checks if it is valid if(isValidValue(value)) { unsigned i, count, neg_cnt; i=neg_cnt=0; count=value.size(); /* Counts the number of negative operator because the quantity can interfere on the final result of formating */ while((value[i]=='+' || value[i]=='-') && i < count) { if(value[i]=='-') neg_cnt++; i++; } //When the negative signal count is odd the number is negative if(neg_cnt % 2 != 0) fmt_value+=QString("-"); fmt_value+=value.mid(i, count); } return(fmt_value); } int Sequence::compareValues(QString value1, QString value2) { if(value1==value2 || value1.isEmpty() || value2.isEmpty()) return(0); else { char ops[2]={'\0','\0'}; unsigned i, idx, count; QString *vet_values[2]={&value1, &value2}, aux_value; if(value1.size() < value2.size()) value1=value1.rightJustified(value1.size() + (value2.size()-value1.size()),'0'); else if(value1.size() > value2.size()) value2=value2.rightJustified(value2.size() + (value1.size()-value2.size()),'0'); for(i=0; i < 2; i++) { //Gets the value signal ops[i]=vet_values[i]->at(0).toLatin1(); //Case the value doesn't has a + it will be append if(ops[i]!='-' && ops[i]!='+') ops[i]='+'; idx=0; count=vet_values[i]->size(); while(idx < count) { if(vet_values[i]->at(idx)!='+' && vet_values[i]->at(idx)!='-') aux_value+=vet_values[i]->at(idx); else aux_value+='0'; idx++; } (*vet_values[i])=aux_value; aux_value=QString(); } if(ops[0]==ops[1] && value1==value2) return(0); else if((ops[0]=='-' && ops[1]=='-' && value1 > value2) || (ops[0]=='+' && ops[1]=='+' && value1 < value2) || (ops[0]=='-' && ops[1]=='+')) return(-1); else return(1); } } void Sequence::setDefaultValues(PgSqlType serial_type) { QString min, max; if(serial_type==QString("smallserial") || serial_type.isEquivalentTo(QString("smallint"))) { min=MaxSmallNegativeValue; max=MaxSmallPositiveValue; } else if(serial_type==QString("bigserial") || serial_type.isEquivalentTo(QString("bigint"))) { min=MaxBigNegativeValue; max=MaxBigPositiveValue; } else { min=MaxNegativeValue; max=MaxPositiveValue; } setValues(min, max, QString("1"), QString("1"), QString("1")); } void Sequence::setName(const QString &name) { QString prev_name=this->getName(true); BaseObject::setName(name); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void Sequence::setSchema(BaseObject *schema) { PhysicalTable *table=nullptr; QString prev_name=this->getName(true); if(owner_col) { //Gets the table that owns the column table=dynamic_cast(owner_col->getParentTable()); //Raises an error when the passed schema differs from the table schema if(table && table->getSchema()!=schema) throw Exception(ErrorCode::AsgSchemaSequenceDiffersTableSchema,__PRETTY_FUNCTION__,__FILE__,__LINE__); } BaseObject::setSchema(schema); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void Sequence::setCycle(bool value) { setCodeInvalidated(cycle != value); cycle=value; } void Sequence::setValues(QString minv, QString maxv, QString inc, QString start, QString cache) { minv=formatValue(minv); maxv=formatValue(maxv); inc=formatValue(inc); start=formatValue(start); cache=formatValue(cache); if(compareValues(minv,maxv) > 0) throw Exception(ErrorCode::AsgInvalidSequenceMinValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error when the start value is less that min value or grater than max value else if(compareValues(start, minv) < 0 || compareValues(start, maxv) > 0) throw Exception(ErrorCode::AsgInvalidSequenceStartValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error when the increment value is null (0) else if(isZeroValue(inc)) throw Exception(ErrorCode::AsgInvalidSequenceIncrementValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error when the cache value is null (0) else if(isZeroValue(cache)) throw Exception(ErrorCode::AsgInvalidSequenceCacheValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->min_value=minv; this->max_value=maxv; this->increment=inc; this->cache=cache; this->start=start; setCodeInvalidated(true); } void Sequence::setOwnerColumn(PhysicalTable *table, const QString &col_name) { if(!table || col_name.isEmpty()) this->owner_col=nullptr; else if(table) { //Raises an error if the table schema differs from the sequence schema if(table->getSchema()!=this->schema) throw Exception(Exception::getErrorMessage(ErrorCode::AsgSeqOwnerTableDifferentSchema) .arg(this->getName(true)), ErrorCode::AsgSeqOwnerTableDifferentSchema,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error when the table owner role differs from the sequence owner if(table->getOwner()!=this->owner) throw Exception(Exception::getErrorMessage(ErrorCode::AsgSeqOwnerTableDifferentRole) .arg(this->getName(true)), ErrorCode::AsgSeqOwnerTableDifferentRole,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Gets the column with the passed name this->owner_col=table->getColumn(col_name); //Raises an error if the column doesn't exists if(!this->owner_col) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInexistentSeqOwnerColumn) .arg(this->getName(true)), ErrorCode::AsgInexistentSeqOwnerColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* If the onwer column was added by relationship and the column id is greater than sequence id, change the sequence id to be greater to avoid reference errors */ if(this->owner_col && this->owner_col->isAddedByRelationship() && this->owner_col->getObjectId() > this->object_id) this->object_id=BaseObject::getGlobalId(); } setCodeInvalidated(true); } void Sequence::setOwnerColumn(Column *column) { PhysicalTable *table=nullptr; if(!column) this->owner_col=nullptr; else { table=dynamic_cast(column->getParentTable()); //Raises an error when the column doesn't has a parent table if(!table) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidSeqOwnerColumn) .arg(this->getName(true)), ErrorCode::AsgInvalidSeqOwnerColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the table schema differs from the sequence schema if(table->getSchema()!=this->schema) throw Exception(Exception::getErrorMessage(ErrorCode::AsgSeqOwnerTableDifferentSchema) .arg(this->getName(true)), ErrorCode::AsgSeqOwnerTableDifferentSchema,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error when the table owner role differs from the sequence owner if(table->getOwner()!=this->owner) throw Exception(Exception::getErrorMessage(ErrorCode::AsgSeqOwnerTableDifferentRole) .arg(this->getName(true)), ErrorCode::AsgSeqOwnerTableDifferentRole,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->owner_col=column; /* If the onwer column was added by relationship and the column id is greater than sequence id, change the sequence id to be greater to avoid reference errors */ if(column && column->isAddedByRelationship() && column->getObjectId() > this->object_id) this->object_id=BaseObject::getGlobalId(); } setCodeInvalidated(true); } bool Sequence::isReferRelationshipAddedColumn(void) { return(owner_col && owner_col->isAddedByRelationship()); } bool Sequence::isCycle(void) { return(cycle); } QString Sequence::getMaxValue(void) { return(max_value); } QString Sequence::getMinValue(void) { return(min_value); } QString Sequence::getCache(void) { return(cache); } QString Sequence::getIncrement(void) { return(increment); } QString Sequence::getStart(void) { return(start); } Column *Sequence::getOwnerColumn(void) { return(owner_col); } QString Sequence::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); PhysicalTable *table=nullptr; if(owner_col) { attributes[Attributes::OwnerColumn]=owner_col->getSignature(); table=dynamic_cast(owner_col->getParentTable()); } attributes[Attributes::Table]=(table ? table->getName(true) : QString()); attributes[Attributes::Column]=(owner_col ? owner_col->getName(true) : QString()); attributes[Attributes::ColIsIdentity]= (owner_col && owner_col->getIdentityType() != BaseType::Null ? Attributes::True : QString()); attributes[Attributes::Increment]=increment; attributes[Attributes::MinValue]=min_value; attributes[Attributes::MaxValue]=max_value; attributes[Attributes::Start]=start; attributes[Attributes::Cache]=cache; attributes[Attributes::Cycle]=(cycle ? Attributes::True : QString()); return(BaseObject::__getCodeDefinition(def_type)); } QString Sequence::getAlterDefinition(BaseObject *object) { Sequence *seq=dynamic_cast(object); if(!seq) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { PhysicalTable *table=nullptr; attribs_map attribs; attributes[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object); if((this->owner_col && !seq->owner_col) || (!this->owner_col && seq->owner_col) || (this->owner_col && seq->owner_col && this->owner_col->getSignature()!=seq->owner_col->getSignature())) { if(seq->owner_col) { attribs[Attributes::OwnerColumn]=seq->owner_col->getSignature(); table=dynamic_cast(seq->owner_col->getParentTable()); if(table) { attribs[Attributes::Table]=table->getName(true); attribs[Attributes::Column]=seq->owner_col->getName(true); } } else attribs[Attributes::OwnerColumn]=Attributes::Unset; } if(!seq->increment.isEmpty() && this->increment!=seq->increment) attribs[Attributes::Increment]=seq->increment; if(!seq->min_value.isEmpty() && this->min_value!=seq->min_value) attribs[Attributes::MinValue]=seq->min_value; if(!seq->max_value.isEmpty() && this->max_value!=seq->max_value) attribs[Attributes::MaxValue]=seq->max_value; if(!seq->start.isEmpty() && this->start!=seq->start) attribs[Attributes::Start]=seq->start; if(!seq->cache.isEmpty() && this->cache!=seq->cache) attribs[Attributes::Cache]=seq->cache; if(this->cycle!=seq->cycle) attribs[Attributes::Cycle]=(seq->cycle ? Attributes::True : Attributes::Unset); copyAttributes(attribs); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Sequence::operator = (Sequence &seq) { QString prev_name=this->getName(true); *(dynamic_cast(this))=dynamic_cast(seq); this->cycle=seq.cycle; this->max_value=seq.max_value; this->min_value=seq.min_value; this->start=seq.start; this->increment=seq.increment; this->cache=seq.cache; this->owner_col=seq.owner_col; PgSqlType::renameUserType(prev_name, this, this->getName(true)); } pgmodeler-0.9.2/libpgmodeler/src/sequence.h000066400000000000000000000101301360462764600207260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Sequence \brief Implements the operations to manipulate sequences on the database. \note Creation date: 26/04/2008 */ #ifndef SEQUENCE_H #define SEQUENCE_H #include "baseobject.h" #include "table.h" class Sequence: public BaseObject { private: /*! \brief Indicates taht the sequence is cyclic (the counter resets when maximum value is reached) */ bool cycle; //! \brief Minimum value QString min_value, //! \brief Maximum value max_value, //! \brief Current sequence value start, //! \brief Sequence value increment increment, //! \brief Sequence cache value cache; //! \brief Column that owns the sequence Column *owner_col; //! \brief Returns true when the passed value is a valid number bool isValidValue(const QString &value); //! \brief Returns true when the passed value is null (zero) bool isZeroValue(const QString &value); //! \brief Returns the formated value excluding the aditional operators QString formatValue(const QString &value); /*! \brief Compares two values and returns: -1 when: value1 < value2 0 when: value1 = value2 1 when: value1 > value2 */ int compareValues(QString value1, QString value2); public: //! \brief Constants that indicates the maximum and minimum values accepted by sequence static const QString //For serial sequences MaxPositiveValue, MaxNegativeValue, //For smallserial sequences MaxSmallPositiveValue, MaxSmallNegativeValue, //For bigserial sequences MaxBigPositiveValue, MaxBigNegativeValue; Sequence(void); //! \brief Defines if the sequence is a cycle void setCycle(bool value); //! \brief Sets at once all the necessary fields to define a sequence void setValues(QString minv, QString maxv, QString inc, QString start, QString cache); /*! \brief Sets all values at once based on the serial type specified (smallserial, serial or bigserial). If other type the three serial types are passed the method will consider as 'serial' */ void setDefaultValues(PgSqlType serial_type); //! \brief Defines the owner column using a table and a column name void setOwnerColumn(PhysicalTable *table, const QString &col_name); //! \brief Defines the owner column using a column itself void setOwnerColumn(Column *column); //! \brief Sets the sequence name void setName(const QString &name); /*! \brief Sets the schema that the sequence belongs. This method raises an error when there is a owner column and the schema to be set is different from the column parent table schema */ void setSchema(BaseObject *schema); bool isCycle(void); QString getMaxValue(void); QString getMinValue(void); QString getIncrement(void); QString getStart(void); QString getCache(void); Column *getOwnerColumn(void); /*! \brief Returns whether the sequence references columns added by relationship. This method is used as auxiliary to control which sequence reference columns added by the relationship in order to avoid referece breaking due constants connections and disconnections of relationships */ bool isReferRelationshipAddedColumn(void); //! \brief Makes a copy between two sequences void operator = (Sequence &seq); //! \brief Returns the SQL / XML definition for the sequence virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getAlterDefinition(BaseObject *object) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/table.cpp000066400000000000000000000254431360462764600205550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "table.h" #include "pgmodelerns.h" Table::Table(void) : PhysicalTable() { obj_type = ObjectType::Table; with_oid=unlogged=rls_enabled=rls_forced=false; attributes[Attributes::Unlogged]=QString(); attributes[Attributes::RlsEnabled]=QString(); attributes[Attributes::RlsForced]=QString(); attributes[Attributes::Oids]=QString(); setName(trUtf8("new_table")); } Table::~Table(void) { destroyObjects(); } void Table::setUnlogged(bool value) { setCodeInvalidated(unlogged != value); unlogged=value; } void Table::setRLSEnabled(bool value) { setCodeInvalidated(rls_enabled != value); rls_enabled = value; } void Table::setRLSForced(bool value) { setCodeInvalidated(rls_forced != value); rls_forced = value; } void Table::addObject(BaseObject *object, int obj_idx) { try { PhysicalTable::addObject(object, obj_idx); if(object->getObjectType() == ObjectType::Table) { /* Updating the storage parameter WITH OIDS depending on the ancestors. * According to the docs, the child table will inherit WITH OID status from the parents */ with_oid=(with_oid || dynamic_cast
(object)->isWithOIDs()); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Table::removeObject(unsigned obj_idx, ObjectType obj_type) { try { Table *tab = nullptr; PhysicalTable::removeObject(obj_idx, obj_type); with_oid=false; for(auto &obj : ancestor_tables) { tab = dynamic_cast
(obj); if(!with_oid && tab->isWithOIDs()) { with_oid=true; break; } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Table::removeObject(const QString &name, ObjectType obj_type) { try { PhysicalTable::removeObject(name, obj_type); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Table::removeObject(BaseObject *obj) { try { PhysicalTable::removeObject(obj); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } vector *Table::getObjectList(ObjectType obj_type) { if(obj_type==ObjectType::Rule) return(&rules); if(obj_type==ObjectType::Index) return(&indexes); if(obj_type==ObjectType::Policy) return(&policies); return(PhysicalTable::getObjectList(obj_type)); } void Table::addIndex(Index *ind, int idx) { try { addObject(ind, idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::addRule(Rule *reg, int idx_reg) { try { addObject(reg, idx_reg); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::addPolicy(Policy *pol, int idx_pol) { try { addObject(pol, idx_pol); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::removeIndex(const QString &name) { try { removeObject(name,ObjectType::Index); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::removeIndex(unsigned idx) { try { removeObject(idx,ObjectType::Index); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::removeRule(const QString &name) { try { removeObject(name,ObjectType::Rule); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::removeRule(unsigned idx) { try { removeObject(idx,ObjectType::Rule); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::removePolicy(const QString &name) { try { removeObject(name, ObjectType::Policy); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Table::removePolicy(unsigned idx) { try { removeObject(idx, ObjectType::Policy); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Index *Table::getIndex(const QString &name) { int idx; return(dynamic_cast(getObject(name,ObjectType::Index,idx))); } Index *Table::getIndex(unsigned idx) { return(dynamic_cast(getObject(idx,ObjectType::Index))); } Rule *Table::getRule(const QString &name) { int idx; return(dynamic_cast(getObject(name,ObjectType::Rule,idx))); } Rule *Table::getRule(unsigned idx) { return(dynamic_cast(getObject(idx,ObjectType::Rule))); } Policy *Table::getPolicy(const QString &name) { int idx; return(dynamic_cast(getObject(name, ObjectType::Policy,idx))); } Policy *Table::getPolicy(unsigned idx) { return(dynamic_cast(getObject(idx, ObjectType::Policy))); } unsigned Table::getIndexCount(void) { return(indexes.size()); } unsigned Table::getRuleCount(void) { return(rules.size()); } unsigned Table::getPolicyCount(void) { return(policies.size()); } void Table::getForeignKeys(vector &fks, bool inc_added_by_rel, Table *ref_table) { unsigned count,i; Constraint *constr=nullptr; count=constraints.size(); for(i=0; i < count; i++) { constr=dynamic_cast(constraints[i]); if(constr->getConstraintType()==ConstraintType::ForeignKey && (!ref_table || (ref_table && constr->getReferencedTable()==ref_table)) && (!constr->isAddedByLinking() || (constr->isAddedByLinking() && inc_added_by_rel))) fks.push_back(constr); } } bool Table::isUnlogged(void) { return(unlogged); } bool Table::isRLSEnabled(void) { return(rls_enabled); } bool Table::isRLSForced(void) { return(rls_forced); } void Table::setWithOIDs(bool value) { setCodeInvalidated(with_oid != value); with_oid=value; } bool Table::isWithOIDs(void) { return(with_oid); } bool Table::isReferTableOnForeignKey(Table *ref_tab) { unsigned count,i; Constraint *constr=nullptr; bool found=false; count=constraints.size(); for(i=0; i < count && !found; i++) { constr=dynamic_cast(constraints[i]); found=(constr->getConstraintType()==ConstraintType::ForeignKey && !constr->isAddedByLinking() && constr->getReferencedTable() == ref_tab); } return(found); } QString Table::__getCodeDefinition(unsigned def_type, bool incl_rel_added_objs) { setTableAttributes(def_type, incl_rel_added_objs); attributes[Attributes::Oids]=(with_oid ? Attributes::True : QString()); attributes[Attributes::Unlogged]=(unlogged ? Attributes::True : QString()); attributes[Attributes::RlsEnabled]=(rls_enabled ? Attributes::True : QString()); attributes[Attributes::RlsForced]=(rls_forced ? Attributes::True : QString()); attributes[Attributes::CopyTable]=QString(); if(def_type==SchemaParser::SqlDefinition && copy_table) attributes[Attributes::CopyTable]=copy_table->getName(true) + copy_op.getSQLDefinition(); return(BaseObject::__getCodeDefinition(def_type)); } QString Table::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); return(__getCodeDefinition(def_type, false)); } void Table::operator = (Table &tab) { (*dynamic_cast(this))=dynamic_cast(tab); this->copy_op=tab.copy_op; this->unlogged=tab.unlogged; this->with_oid=tab.with_oid; this->rls_forced=tab.rls_forced; this->rls_enabled=tab.rls_enabled; } void Table::getColumnReferences(Column *column, vector &refs, bool exclusion_mode) { if(column && !column->isAddedByRelationship()) { unsigned count, i; IndexElement elem; Column *col=nullptr; vector::iterator itr, itr_end; bool found=false; Index *ind=nullptr; itr=indexes.begin(); itr_end=indexes.end(); while(itr!=itr_end && (!exclusion_mode || (exclusion_mode && !found))) { ind=dynamic_cast(*itr); itr++; count=ind->getIndexElementCount(); for(i=0; i < count && (!exclusion_mode || (exclusion_mode && !found)); i++) { elem=ind->getIndexElement(i); col=elem.getColumn(); if(col && col==column) { found=true; refs.push_back(ind); } } } PhysicalTable::getColumnReferences(column, refs, exclusion_mode); } } QString Table::getTruncateDefinition(bool cascade) { try { BaseObject::setBasicAttributes(true); attributes[Attributes::Cascade]=(cascade ? Attributes::True : QString()); return(BaseObject::getAlterDefinition(Attributes::TruncatePriv, attributes, false, false)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString Table::getAlterDefinition(BaseObject *object) { Table *tab=dynamic_cast
(object); if(!tab) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { QString alter_def; attribs_map attribs; attribs[Attributes::Oids]=QString(); attribs[Attributes::AlterCmds]=BaseObject::getAlterDefinition(object, true); if(this->getName()==tab->getName()) { attribs[Attributes::HasChanges]=Attributes::True; if(this->with_oid!=tab->with_oid) attribs[Attributes::Oids]=(tab->with_oid ? Attributes::True : Attributes::Unset); if(this->unlogged!=tab->unlogged) attribs[Attributes::Unlogged]=(tab->unlogged ? Attributes::True : Attributes::Unset); if(this->rls_enabled!=tab->rls_enabled) attribs[Attributes::RlsEnabled]=(tab->rls_enabled ? Attributes::True : Attributes::Unset); if(this->rls_forced!=tab->rls_forced) attribs[Attributes::RlsForced]=(tab->rls_forced ? Attributes::True : Attributes::Unset); } copyAttributes(attribs); alter_def=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true); return(alter_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler/src/table.h000066400000000000000000000146731360462764600202250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate tables on the database. \note Creation date: 17/09/2006 */ #ifndef TABLE_H #define TABLE_H #include "index.h" #include "rule.h" #include "policy.h" #include "physicaltable.h" #include class Table: public PhysicalTable { private: //! \brief Stores the indexes vector indexes; //! \brief Stores the rules vector rules; //! \brief Stores the policies vector policies; //! \brief Indicates if the table is unlogged, which means, is not controled by the WAL (write ahead logs) bool unlogged, //! \brief Indicates if the row level security is enabled rls_enabled, //! \brief Indicates if the row level security is enforced rls_forced, //! \brief Indicates if the table accepts OIDs with_oid; public: Table(void); ~Table(void); //! \brief Defines if the table is unlogged void setUnlogged(bool value); //! \brief Defines if the row level security on table is enabled void setRLSEnabled(bool value); //! \brief Defines if the row level security on table is forced for the table owner void setRLSForced(bool value); //! \brief Defines if the table accepts OIDs void setWithOIDs(bool value); //! \brief Returns if the table is configured with oids bool isWithOIDs(void); void addObject(BaseObject *object, int obj_idx = -1); void removeObject(unsigned obj_idx, ObjectType obj_type); void removeObject(const QString &name, ObjectType obj_type); void removeObject(BaseObject *obj); //! \brief Adds a index to table (optionally the user can add the object at the specified index 'idx') void addIndex(Index *ind, int idx=-1); //! \brief Adds a rule to table (optionally the user can add the object at the specified index 'idx') void addRule(Rule *reg, int idx_reg=-1); //! \brief Adds a policy to table (optionally the user can add the object at the specified index 'idx') void addPolicy(Policy *pol, int idx_pol=-1); //! \brief Gets a index object through its name Index *getIndex(const QString &name); //! \brief Gets a index object through its position Index *getIndex(unsigned idx); //! \brief Gets a rule through its name Rule *getRule(const QString &name); //! \brief Gets a rule through its index Rule *getRule(unsigned idx); //! \brief Gets a policy through its name Policy *getPolicy(const QString &name); //! \brief Gets a policy through its index Policy *getPolicy(unsigned idx); //! \brief Gets the index count unsigned getIndexCount(void); //! \brief Gets the rule count unsigned getRuleCount(void); //! \brief Gets the policy count unsigned getPolicyCount(void); //! \brief Removes a index through its name void removeIndex(const QString &name); //! \brief Removes a index through its position void removeIndex(unsigned idx); //! \brief Removes a rule through its name void removeRule(const QString &name); //! \brief Removes a rule through its index void removeRule(unsigned idx); //! \brief Removes a policy through its name void removePolicy(const QString &name); //! \brief Removes a policy through its index void removePolicy(unsigned idx); //! \brief Returns the SQL / XML definition for table virtual QString getCodeDefinition(unsigned def_type) final; /*! \brief Stores on the specified vector 'fks' the foreign key present on table. The boolean paramenter is used to include those foreign keys includes by relationship. The third parameter is used to filter the search, including only the foreign keys that references the specified table */ void getForeignKeys(vector &fks, bool inc_added_by_rel=false, Table *ref_table=nullptr); //! \brief Returns if the table is configured as unlogged bool isUnlogged(void); //! \brief Returns if RLS is enabled on the table bool isRLSEnabled(void); //! \brief Returns if RLS is forced on the table bool isRLSForced(void); //! \brief Copy the attributes between two tables void operator = (Table &tabela); //! \brief Returns the specified object type list virtual vector *getObjectList(ObjectType obj_type); /*! \brief Returns if some of the foreign keys references the specified table. This method only considers the foreign keys created by the user. Relationship created foreign keys are discarded from the search. */ bool isReferTableOnForeignKey(Table *ref_tab); /*! \brief Gets objects which refer to object of the parameter (directly or indirectly) and stores them in a vector. The 'exclusion_mode' is used to speed up the execution of the method when it is used to validate the deletion of the object, getting only the first reference to the object candidate for deletion. To get ALL references to the object must be specified as 'false' the parameter 'exclusion_mode'. */ void getColumnReferences(Column *column, vector &refs, bool exclusion_mode=false); //! \brief Returns the alter definition comparing the this table against the one provided via parameter virtual QString getAlterDefinition(BaseObject *object) final; //! \brief Returns the truncate definition for this table QString getTruncateDefinition(bool cascade); /*! \brief Generates the table's SQL code considering adding the relationship added object or not. * Note if the method is called with incl_rel_added_objs = true it can produce an SQL/XML code * that does not reflect the real semantics of the table. So take care to use this method and always * invalidate the tables code (see setCodeInvalidated()) after retrieving the resulting code */ QString __getCodeDefinition(unsigned def_type, bool incl_rel_added_objs); friend class Relationship; friend class OperationList; }; #endif pgmodeler-0.9.2/libpgmodeler/src/tableobject.cpp000066400000000000000000000060551360462764600217420ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tableobject.h" TableObject::TableObject(void) { parent_table=nullptr; decl_in_table=true; add_by_linking=add_by_generalization=add_by_copy=false; } void TableObject::setParentTable(BaseTable *table) { parent_table=table; } BaseTable *TableObject::getParentTable(void) { return(parent_table); } void TableObject::setAddedByLinking(bool value) { add_by_linking=value; add_by_generalization=false; add_by_copy=false; } bool TableObject::isAddedByLinking(void) { return(add_by_linking); } void TableObject::setAddedByGeneralization(bool value) { add_by_generalization=value; add_by_linking=false; add_by_copy=false; } void TableObject::setDeclaredInTable(bool value) { setCodeInvalidated(decl_in_table != value); decl_in_table=value; } bool TableObject::isAddedByGeneralization(void) { return(add_by_generalization); } void TableObject::setAddedByCopy(bool value) { add_by_copy=value; add_by_generalization=false; add_by_linking=false; } bool TableObject::isAddedByCopy(void) { return(add_by_copy); } bool TableObject::isAddedByRelationship(void) { return(add_by_linking || add_by_generalization || add_by_copy); } bool TableObject::isDeclaredInTable(void) { return(decl_in_table); } bool TableObject::isTableObject(ObjectType type) { return(type==ObjectType::Column || type==ObjectType::Constraint || type==ObjectType::Trigger || type==ObjectType::Rule || type==ObjectType::Index || type==ObjectType::Policy); } void TableObject::operator = (TableObject &object) { *(dynamic_cast(this))=dynamic_cast(object); this->parent_table=object.parent_table; this->add_by_copy=false; this->add_by_generalization=false; this->add_by_linking=false; this->decl_in_table=object.decl_in_table; } void TableObject::setCodeInvalidated(bool value) { if(parent_table) parent_table->BaseObject::setCodeInvalidated(value); BaseObject::setCodeInvalidated(value); } QString TableObject::getDropDefinition(bool cascade) { if(getParentTable()) attributes[Attributes::Table]=getParentTable()->getName(true); attributes[this->getSchemaName()]=Attributes::True; return(BaseObject::getDropDefinition(cascade)); } QString TableObject::getSignature(bool format) { if(!parent_table) return(BaseObject::getSignature(format)); return(QString("%1.%2").arg(parent_table->getSignature(format)).arg(this->getName(format))); } pgmodeler-0.9.2/libpgmodeler/src/tableobject.h000066400000000000000000000071301360462764600214020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class TableObject \brief This class serves as a base class for objects that are embedded on tables like columns, rules, triggers, indexes, constraints. \note Creation date: 24/07/2008 */ #ifndef TABLE_OBJECT_H #define TABLE_OBJECT_H #include "basetable.h" class TableObject: public BaseObject { private: //! \brief Stores the table that owns this object BaseTable *parent_table; /*! \brief Indicates that the object was included automaticaly by "one to many", "one to many", "many to many" relationships */ bool add_by_linking; /*! \brief Indicates that the object was included automaticaly by "one to many", "generalization" relationships */ bool add_by_generalization; /*! \brief Indicates that the object was included automaticaly by "one to many", "copy" relationships */ bool add_by_copy; bool decl_in_table; protected: //! \brief Defines that the object is included by relationship (1-1, 1-n, n-n) void setAddedByLinking(bool value); //! \brief Defines that the object is included by generalization relationship void setAddedByGeneralization(bool value); //! \brief Defines that the object is include by copy relationship void setAddedByCopy(bool value); /*! \brief Defines that the object's SQL code must be created inside parent's table declaration, this is true by default. This attribute is only changed on export operations. This attribute is used only by columns and constraints, other types of child objects will ignore it */ void setDeclaredInTable(bool value); public: TableObject(void); //! \brief Defines the parent table for the object virtual void setParentTable(BaseTable *table); //! \brief Returns the object parent table BaseTable *getParentTable(void); /*! \brief This method is purely virtual to force the derived classes overload this method. This also makes class TableObject not instantiable */ virtual QString getCodeDefinition(unsigned def_type)=0; virtual QString getDropDefinition(bool cascade); virtual QString getSignature(bool format = true); //! \brief Returns whether the object was added by relationship 1-1, 1-n, n-n bool isAddedByLinking(void); //! \brief Returns whether the object was added by generalization bool isAddedByGeneralization(void); //! \brief Returns whether the object was added by copy relationship bool isAddedByCopy(void); /*! \brief Returns whether the object was added by relationship (covering all the possible relationship types) */ bool isAddedByRelationship(void); bool isDeclaredInTable(void); //! \brief Returns if the passed type is a table child object (column, constraint, index, rule, trigger) static bool isTableObject(ObjectType type); void setCodeInvalidated(bool value); void operator = (TableObject &object); friend class Relationship; friend class PhysicalTable; friend class Table; }; #endif pgmodeler-0.9.2/libpgmodeler/src/tablespace.cpp000066400000000000000000000041041360462764600215600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tablespace.h" unsigned Tablespace::tabspace_id=1000; Tablespace::Tablespace(void) { obj_type=ObjectType::Tablespace; attributes[Attributes::Directory]=QString(); object_id=Tablespace::tabspace_id++; } void Tablespace::setName(const QString &name) { /* Tablespace names starting with pg_ is reserved to PostgreSQL if its the case raises an error */ if(name.mid(0,3)==QString("pg_")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgReservedName) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Tablespace)), ErrorCode::AsgReservedName,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObject::setName(name); } void Tablespace::setDirectory(const QString &dir) { QString dir_aux=dir; dir_aux.remove('\''); //Raises an error if the directory is an empty path if(dir_aux.isEmpty()) throw Exception(ErrorCode::AsgEmptyDirectoryName,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->directory != dir_aux); this->directory=dir_aux; } QString Tablespace::getDirectory(void) { return(directory); } QString Tablespace::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); if(!directory.isEmpty()) attributes[Attributes::Directory]=QString("'") + directory + QString("'"); return(BaseObject::__getCodeDefinition(def_type)); } pgmodeler-0.9.2/libpgmodeler/src/tablespace.h000066400000000000000000000027521360462764600212340ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Tablespace \brief Implements the operations to manipulate tablespace on the database. \note Creation date: 05/06/2008 */ #ifndef TABLESPACE_H #define TABLESPACE_H #include "baseobject.h" class Tablespace: public BaseObject{ private: static unsigned tabspace_id; //! \brief Directory where the tablespace resides QString directory; public: Tablespace(void); void setName(const QString &name); //! \brief Sets the directory where tablespace resides void setDirectory(const QString &dir); //! \brief Returns the directory where the tablespace resides QString getDirectory(void); //! \brief Returns the SQL / XML code for the tablespace virtual QString getCodeDefinition(unsigned def_type) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/tag.cpp000066400000000000000000000121241360462764600202310ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tag.h" unsigned Tag::tag_id=3000; Tag::Tag(void) { QStringList attribs={ Attributes::TableName, Attributes::TableSchemaName, Attributes::TableTitle, Attributes::TableBody, Attributes::TableExtBody }; obj_type=ObjectType::Tag; object_id=Tag::tag_id++; attributes[Attributes::Styles]=QString(); for(auto &attr : attribs) { if(attr!=Attributes::TableName && attr!=Attributes::TableSchemaName) color_config[attr] = { QColor(0,0,0), QColor(0,0,0), QColor(0,0,0) }; else color_config[attr] = { QColor(0,0,0) }; } } void Tag::setName(const QString &name) { if(name.isEmpty()) throw Exception(ErrorCode::AsgEmptyNameObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(name.size() > BaseObject::ObjectNameMaxLength) throw Exception(ErrorCode::AsgLongNameObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->obj_name=name; } QString Tag::getName(bool, bool) { return(this->obj_name); } void Tag::setElementColor(const QString &elem_id, const QColor &color, unsigned color_id) { try { validateElementId(elem_id, color_id); color_config[elem_id][color_id]=color; setCodeInvalidated(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Tag::setElementColors(const QString &elem_id, const QString &colors) { try { QStringList color_lst=colors.split(','); unsigned color_id=FillColor1; for(auto &color : color_lst) { validateElementId(elem_id, color_id); color_config[elem_id][color_id]=QColor(color); color_id++; } setCodeInvalidated(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QColor Tag::getElementColor(const QString &elem_id, unsigned color_id) { try { validateElementId(elem_id, color_id); return(color_config[elem_id][color_id]); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void Tag::validateElementId(const QString &id, unsigned color_id) { if(color_config.count(id) == 0) throw Exception(Exception::getErrorMessage(ErrorCode::OprInvalidElementId).arg(id), ErrorCode::OprInvalidElementId ,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if((color_id > ColorCount) || (color_id > 0 && (id==Attributes::TableName || id==Attributes::TableSchemaName))) throw Exception(Exception::getErrorMessage(ErrorCode::RefInvalidElementColorId).arg(id).arg(color_id), ErrorCode::RefInvalidElementColorId ,__PRETTY_FUNCTION__,__FILE__,__LINE__); } QLinearGradient Tag::getFillStyle(const QString &elem_id) { try { validateElementId(elem_id, 1); QLinearGradient grad(QPointF(0,0),QPointF(0,1)); grad.setCoordinateMode(QGradient::ObjectBoundingMode); grad.setColorAt(0, color_config[elem_id][FillColor1]); grad.setColorAt(1, color_config[elem_id][FillColor2]); return(grad); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString Tag::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString Tag::getCodeDefinition(unsigned def_type, bool reduced_form) { if(def_type==SchemaParser::SqlDefinition) return(QString()); else { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); try { attribs_map attribs; for(auto &itr : color_config) { attribs[Attributes::Id]=itr.first; attribs[Attributes::Colors]=QString(); if(itr.first==Attributes::TableName || itr.first==Attributes::TableSchemaName) attribs[Attributes::Colors]=itr.second[FillColor1].name(); else attribs[Attributes::Colors]=itr.second[FillColor1].name() + QString(",") + itr.second[FillColor2].name() + QString(",") + itr.second[BorderColor].name(); attributes[Attributes::Styles]+=schparser.getCodeDefinition(Attributes::Style, attribs, SchemaParser::XmlDefinition); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } return(BaseObject::getCodeDefinition(def_type, reduced_form)); } } void Tag::operator = (Tag &tag) { (*dynamic_cast(this))=dynamic_cast(tag); for(auto &attr : tag.color_config) this->color_config[attr.first]=attr.second; } pgmodeler-0.9.2/libpgmodeler/src/tag.h000066400000000000000000000053621360462764600177040ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Tag \brief Implements a way to separate tables and views via tags. Each tag contain custom colors that replaces the original colors of tables/views that owns them. */ #ifndef TAG_H #define TAG_H #include "baseobject.h" #include #include class Tag: public BaseObject { private: static unsigned tag_id; //! \brief Stores the object colors configuration map> color_config; /*! \brief Validates the element id and the color id. This method will raise an error if some of parameters are invalid */ void validateElementId(const QString &elem_id, unsigned color_id); public: static constexpr unsigned FillColor1=0, FillColor2=1, BorderColor=2, ColorCount=3; Tag(void); /*! \brief Set the tag name. Different from regular database model object there is no rule when setting the name. The only exception is that the name cannot be greater than BaseObject::OBJECT_NAME_MAX_LENGTH */ void setName(const QString &name) final; QString getName(bool=false, bool=false) final; //! \brief Set the specified element id color void setElementColor(const QString &elem_id, const QColor &color, unsigned color_id); /*! \brief Set the specified element colors using a string that contains a color set on the format: [#RRGGBB],[#RRGGBB],[#RRGGBB]. Color on the string beyond position 3 will be ignored */ void setElementColors(const QString &elem_id, const QString &colors); //! \brief Returns a sigle color (at specified index) of the element. QColor getElementColor(const QString &elem_id, unsigned color_id); /*! \brief Returns a gradient configured for the current element id. This method will return an error if the current element does not have at least 2 colors configured */ QLinearGradient getFillStyle(const QString &elem_id); QString getCodeDefinition(unsigned def_type); QString getCodeDefinition(unsigned def_type, bool reduced_form) final; //! \brief Copy the attributes between two tags void operator = (Tag &tag); }; #endif pgmodeler-0.9.2/libpgmodeler/src/textbox.cpp000066400000000000000000000060111360462764600211510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "textbox.h" Textbox::Textbox(void) { obj_type=ObjectType::Textbox; font_size=9.0; text_attributes[0]=text_attributes[1]=text_attributes[2]=false; attributes[Attributes::Italic]=QString(); attributes[Attributes::Bold]=QString(); attributes[Attributes::Underline]=QString(); attributes[Attributes::Color]=QString(); attributes[Attributes::FontSize]=QString(); } QString Textbox::getCodeDefinition(unsigned def_type) { if(def_type==SchemaParser::SqlDefinition) return(QString()); else { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); setPositionAttribute(); setFadedOutAttribute(); if(text_attributes[ItalicText]) attributes[Attributes::Italic]=Attributes::True; if(text_attributes[BoldText]) attributes[Attributes::Bold]=Attributes::True; if(text_attributes[UnderlineText]) attributes[Attributes::Underline]=Attributes::True; if(text_color.name()!=QString("#000000")) attributes[Attributes::Color]=text_color.name(); attributes[Attributes::FontSize]=QString("%1").arg(font_size); attributes[Attributes::Layer]=QString::number(layer); return(this->BaseObject::__getCodeDefinition(SchemaParser::XmlDefinition)); } } void Textbox::operator = (Textbox &txtbox) { (*dynamic_cast(this))=reinterpret_cast(txtbox); this->comment=txtbox.comment; this->text_attributes[0]=txtbox.text_attributes[0]; this->text_attributes[1]=txtbox.text_attributes[1]; this->text_attributes[2]=txtbox.text_attributes[2]; this->text_color=txtbox.text_color; this->font_size=txtbox.font_size; this->layer = txtbox.layer; } void Textbox::setTextAttribute(unsigned attrib, bool value) { if(attrib > UnderlineText) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); text_attributes[attrib]=value; } void Textbox::setTextColor(const QColor &color) { text_color=color; } QColor Textbox::getTextColor(void) { return(text_color); } bool Textbox::getTextAttribute(unsigned attrib) { if(attrib > UnderlineText) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(text_attributes[attrib]); } void Textbox::setFontSize(double size) { font_size=(size <= 0 ? 1 : size); } double Textbox::getFontSize(void) { return(font_size); } pgmodeler-0.9.2/libpgmodeler/src/textbox.h000066400000000000000000000044261360462764600206260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Textbox \brief This class is used to represent informative textboxes over the model also used to represent relationship labels. \note Creation date: 05/09/2007 */ #ifndef TEXTBOX_H #define TEXTBOX_H #include "basegraphicobject.h" #include class Textbox: public BaseGraphicObject{ private: //! \brief Stores the status of text attributes (bold / italic / underline) bool text_attributes[3]; double font_size; //! \brief Color used to draw the text QColor text_color; public: //! \brief Constants used to configure the text attributes static constexpr unsigned ItalicText=0, BoldText=1, UnderlineText=2; /*! \brief To define the content of the textboxes the method setComment() must be used and the getComment() method used to get the current text */ Textbox(void); //! \brief Sets the attributes of the text void setTextAttribute(unsigned attrib, bool value); //! \brief Sets the color used to draw the text of textbox void setTextColor(const QColor &color); void setFontSize(double size); /*! \brief Since textboxes doesn't has SQL code definition this method will return a empty definition whenever the user try to generate a SQL for this object. */ virtual QString getCodeDefinition(unsigned def_type) final; //! \brief Returns the current state of the passed text attribute bool getTextAttribute(unsigned attrib); QColor getTextColor(void); double getFontSize(void); //! \brief Copies the attributes between textboxes void operator = (Textbox &txtbox); }; #endif pgmodeler-0.9.2/libpgmodeler/src/trigger.cpp000066400000000000000000000341361360462764600211300ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "trigger.h" Trigger::Trigger(void) { unsigned i; EventType tipos[4]={EventType::OnInsert, EventType::OnDelete, EventType::OnUpdate, EventType::OnTruncate}; function=nullptr; is_exec_per_row=is_constraint=is_deferrable=false; obj_type=ObjectType::Trigger; referenced_table=nullptr; for(i=0; i < 4; i++) events[tipos[i]]=false; attributes[Attributes::Arguments]=QString(); attributes[Attributes::Events]=QString(); attributes[Attributes::TriggerFunc]=QString(); attributes[Attributes::Table]=QString(); attributes[Attributes::Columns]=QString(); attributes[Attributes::FiringType]=QString(); attributes[Attributes::PerRow]=QString(); attributes[Attributes::InsEvent]=QString(); attributes[Attributes::DelEvent]=QString(); attributes[Attributes::UpdEvent]=QString(); attributes[Attributes::TruncEvent]=QString(); attributes[Attributes::Condition]=QString(); attributes[Attributes::RefTable]=QString(); attributes[Attributes::DeferType]=QString(); attributes[Attributes::Deferrable]=QString(); attributes[Attributes::DeclInTable]=QString(); attributes[Attributes::Constraint]=QString(); attributes[Attributes::OldTableName]=QString(); attributes[Attributes::NewTableName]=QString(); } void Trigger::addArgument(const QString &arg) { arguments.push_back(arg); } void Trigger::setArgumentAttribute(unsigned def_type) { QString str_args; unsigned i, count; count=arguments.size(); for(i=0; i < count; i++) { if(def_type==SchemaParser::SqlDefinition) str_args+=QString("'") + arguments[i] + QString("'"); else str_args+=arguments[i]; if(i < (count-1)) str_args+=QString(","); } attributes[Attributes::Arguments]=str_args; } void Trigger::setFiringType(FiringType firing_type) { setCodeInvalidated(this->firing_type != firing_type); this->firing_type=firing_type; } void Trigger::setEvent(EventType event, bool value) { if(event==EventType::OnSelect) throw Exception(ErrorCode::RefInvalidTriggerEvent,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(events[event] != value); events[event]=value; } void Trigger::setFunction(Function *func) { //Case the function is null an error is raised if(!func) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Trigger)), ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { //Case the function doesn't returns 'trigger' it cannot be used with the trigger thus raise an error if(func->getReturnType()!=QString("trigger")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidTriggerFunction).arg(QString("trigger")),__PRETTY_FUNCTION__,__FILE__,__LINE__); //Case the function has some parameters raise an error else if(func->getParameterCount()!=0) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Trigger)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(function != func); this->function=func; } } void Trigger::setCondition(const QString &cond) { setCodeInvalidated(condition != cond); this->condition=cond; } void Trigger::addColumn(Column *column) { if(!column) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedColumn) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgNotAllocatedColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!column->getParentTable()) throw Exception(Exception::getErrorMessage(ErrorCode::AsgColumnNoParent) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgNotAllocatedColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(this->getParentTable() && column->getParentTable() != this->getParentTable()) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidColumnTrigger) .arg(column->getName(true)) .arg(this->getName(true)), ErrorCode::AsgInvalidColumnTrigger,__PRETTY_FUNCTION__,__FILE__,__LINE__); upd_columns.push_back(column); setCodeInvalidated(true); } void Trigger::editArgument(unsigned arg_idx, const QString &new_arg) { //Raises an error if the argument index is invalid (out of bound) if(arg_idx>=arguments.size()) throw Exception(ErrorCode::RefArgumentInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); vector::iterator itr; itr=arguments.begin()+arg_idx; (*itr)=new_arg; setCodeInvalidated(true); } void Trigger::setExecutePerRow(bool value) { setCodeInvalidated(is_exec_per_row != value); is_exec_per_row=value; } bool Trigger::isExecuteOnEvent(EventType event) { if(event==EventType::OnSelect) throw Exception(ErrorCode::RefInvalidTriggerEvent,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(events.at(!event)); } bool Trigger::isExecutePerRow(void) { return(is_exec_per_row); } QString Trigger::getArgument(unsigned arg_idx) { //Raises an error if the argument index is invalid (out of bound) if(arg_idx>=arguments.size()) throw Exception(ErrorCode::RefArgumentInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(arguments[arg_idx]); } Column *Trigger::getColumn(unsigned col_idx) { //Raises an error if the column index is invalid (out of bound) if(col_idx>=upd_columns.size()) throw Exception(ErrorCode::RefColumnInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(upd_columns[col_idx]); } unsigned Trigger::getArgumentCount(void) { return(arguments.size()); } unsigned Trigger::getColumnCount(void) { return(upd_columns.size()); } Function *Trigger::getFunction(void) { return(function); } QString Trigger::getCondition(void) { return(condition); } FiringType Trigger::getFiringType(void) { return(firing_type); } void Trigger::removeArgument(unsigned arg_idx) { //Raises an error if the argument index is invalid (out of bound) if(arg_idx>=arguments.size()) throw Exception(ErrorCode::RefArgumentInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); vector::iterator itr; itr=arguments.begin()+arg_idx; arguments.erase(itr); setCodeInvalidated(true); } void Trigger::removeArguments(void) { arguments.clear(); setCodeInvalidated(true); } void Trigger::removeColumns(void) { upd_columns.clear(); setCodeInvalidated(true); } void Trigger::setReferecendTable(BaseTable *ref_table) { //If the referenced table isn't valid raises an error if(ref_table && ref_table->getObjectType()!=ObjectType::Table) throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(referenced_table != ref_table); this->referenced_table=ref_table; } void Trigger::setDeferralType(DeferralType type) { setCodeInvalidated(deferral_type != type); deferral_type=type; } void Trigger::setDeferrable(bool value) { setCodeInvalidated(is_deferrable != value); is_deferrable=value; } BaseTable *Trigger::getReferencedTable(void) { return(referenced_table); } DeferralType Trigger::getDeferralType(void) { return(deferral_type); } bool Trigger::isDeferrable(void) { return(is_deferrable); } void Trigger::setConstraint(bool value) { setCodeInvalidated(is_constraint != value); is_constraint=value; } void Trigger::setTransitionTableName(unsigned tab_idx, const QString &name) { if(tab_idx > NewTableName) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(transition_tabs_names[tab_idx] != name); transition_tabs_names[tab_idx] = name; } QString Trigger::getTransitionTableName(unsigned tab_idx) { if(tab_idx > NewTableName) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(transition_tabs_names[tab_idx]); } bool Trigger::isConstraint(void) { return(is_constraint); } bool Trigger::isReferRelationshipAddedColumn(void) { vector::iterator itr, itr_end; Column *col=nullptr; bool enc=false; itr=upd_columns.begin(); itr_end=upd_columns.end(); while(itr!=itr_end && !enc) { col=(*itr); enc=col->isAddedByRelationship(); itr++; } return(enc); } vector Trigger::getRelationshipAddedColumns(void) { vector cols; for(auto &col : upd_columns) { if(col->isAddedByRelationship()) cols.push_back(col); } return(cols); } void Trigger::setBasicAttributes(unsigned def_type) { QString str_aux, attribs[4]={Attributes::InsEvent, Attributes::DelEvent, Attributes::TruncEvent, Attributes::UpdEvent }, sql_event[4]={"INSERT OR ", "DELETE OR ", "TRUNCATE OR ", "UPDATE "}; unsigned count, i, i1, event_types[4]={EventType::OnInsert, EventType::OnDelete, EventType::OnTruncate, EventType::OnUpdate}; setArgumentAttribute(def_type); for(i=0; i < 4; i++) { if(events.at(event_types[i])) { str_aux+=sql_event[i]; attributes[attribs[i]]=Attributes::True; if(event_types[i]==EventType::OnUpdate) { count=upd_columns.size(); attributes[Attributes::Columns]=QString(); for(i1=0; i1 < count; i1++) { attributes[Attributes::Columns]+=upd_columns.at(i1)->getName(true); if(i1 < count-1) attributes[Attributes::Columns]+=QString(","); } } } } if(!str_aux.isEmpty()) str_aux.remove(str_aux.size()-3,3); if(def_type==SchemaParser::SqlDefinition && !attributes[Attributes::Columns].isEmpty()) str_aux+=QString(" OF ") + attributes[Attributes::Columns]; attributes[Attributes::Events]=str_aux; if(function) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::TriggerFunc]=function->getName(true); else attributes[Attributes::TriggerFunc]=function->getCodeDefinition(def_type, true); } } QString Trigger::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); setBasicAttributes(def_type); /* Case the trigger doesn't referece some column added by relationship it will be declared inside the parent table construction by the use of 'decl-in-table' schema attribute */ if(!isReferRelationshipAddedColumn()) attributes[Attributes::DeclInTable]=Attributes::True; if(getParentTable()) attributes[Attributes::Table]=getParentTable()->getName(true); attributes[Attributes::Constraint]=(is_constraint ? Attributes::True : QString()); attributes[Attributes::FiringType]=(~firing_type); //** Constraint trigger MUST execute per row ** attributes[Attributes::PerRow]=((is_exec_per_row && !is_constraint) || is_constraint ? Attributes::True : QString()); attributes[Attributes::Condition]=condition; if(referenced_table) attributes[Attributes::RefTable]=referenced_table->getName(true); attributes[Attributes::Deferrable]=(is_deferrable ? Attributes::True : QString()); attributes[Attributes::DeferType]=(~deferral_type); if(def_type == SchemaParser::XmlDefinition) { attributes[Attributes::OldTableName]=transition_tabs_names[OldTableName]; attributes[Attributes::NewTableName]=transition_tabs_names[NewTableName]; } else { attributes[Attributes::OldTableName]=BaseObject::formatName(transition_tabs_names[OldTableName]); attributes[Attributes::NewTableName]=BaseObject::formatName(transition_tabs_names[NewTableName]); } return(BaseObject::__getCodeDefinition(def_type)); } void Trigger::validateTrigger(void) { if(getParentTable()) { ObjectType parent_type=getParentTable()->getObjectType(); if(!is_constraint) { //The INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers if(firing_type==FiringType::InsteadOf && parent_type != ObjectType::View) throw Exception(ErrorCode::InvTableTriggerInsteadOfFiring,__PRETTY_FUNCTION__,__FILE__,__LINE__); //The INSTEAD OF mode cannot be used on view triggers that executes for each statement else if(firing_type==FiringType::InsteadOf && parent_type==ObjectType::View && !is_exec_per_row) throw Exception(ErrorCode::InvUsageInsteadOfOnTrigger,__PRETTY_FUNCTION__,__FILE__,__LINE__); //A trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event else if(firing_type==FiringType::InsteadOf && events[EventType::OnUpdate] && !upd_columns.empty()) throw Exception(ErrorCode::InvUsageInsteadOfUpdateTrigger,__PRETTY_FUNCTION__,__FILE__,__LINE__); //The TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table else if(events[EventType::OnTruncate] && (is_exec_per_row || parent_type==ObjectType::View)) throw Exception(ErrorCode::InvUsageTruncateOnTrigger,__PRETTY_FUNCTION__,__FILE__,__LINE__); //A view trigger cannot be AFTER/BEFORE when it executes for each row else if(parent_type==ObjectType::View && is_exec_per_row && (firing_type==FiringType::After || firing_type==FiringType::Before)) throw Exception(ErrorCode::InvUsageAfterBeforeViewTrigger,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Only constraint triggers can be deferrable or reference another table else if(referenced_table || is_deferrable) throw Exception(ErrorCode::InvUseConstraintTriggerAttribs,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Constraint triggers can only be executed on AFTER events and for each row else { if(firing_type!=FiringType::After && !is_exec_per_row) throw Exception(ErrorCode::InvConstrTriggerNotAfterRow,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } QString Trigger::getSignature(bool format) { if(!getParentTable()) return(BaseObject::getSignature(format)); return(QString("%1 ON %2").arg(this->getName(format)).arg(getParentTable()->getSignature(true))); } pgmodeler-0.9.2/libpgmodeler/src/trigger.h000066400000000000000000000152131360462764600205700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Trigger \brief Implements the operations to manipulate triggers on the database. \note Creation date: 11/10/2006 */ #ifndef TRIGGER_H #define TRIGGER_H #include "tableobject.h" #include "function.h" class Trigger: public TableObject{ private: //! \brief Stores the transtion tables names (OLD and NEW) [REFERENCING { OLD | NEW } TABLE name] QString transition_tabs_names[2]; //! \brief Arguments passed to the function that trigger executes vector arguments; /*! \brief Column list used as the trigger firing condition. This attribute was introduced in PostgreSQL 9.1 and it is used only when the UPDATE event is assigned to trigger. */ vector upd_columns; //! \brief Function that is excuted when the trigger is activated Function *function; //! \brief Condition that guarantees the trigger's execution QString condition; //! \brief Trigger firing mode (BEFORE, AFTER, INSTEAD OF) FiringType firing_type; //! \brief Map that marks which events activates the trigger map events; //! \brief Flag that indicates whether the function must be executed by row bool is_exec_per_row; //! \brief Table referecend by the trigger (only for constraint trigger) BaseTable *referenced_table; //! \brief Indicates if the trigger is a constraint trigger bool is_constraint, //! \brief Indicates whether the trigger is deferrable (only for constraint trigger) is_deferrable; //! \brief Deferral type for the trigger (only for constraint trigger) DeferralType deferral_type; //! \brief Formats the basic trigger attributes to be used by SchemaParser void setBasicAttributes(unsigned def_type); //! \brief Format the function arguments to be used by the SchemaParser void setArgumentAttribute(unsigned tipo_def); public: static constexpr unsigned OldTableName=0, NewTableName=1; Trigger(void); /*! \brief Adds a column as a firing condition (only when the event UPDATE is used). The columns added by this method must belongs to the trigger owner table. */ void addColumn(Column *column); //! \brief Adds an argument to the trigger void addArgument(const QString &arg); //! \brief Defines in which events the trigger is executed void setEvent(EventType event, bool value); //! \brief Defines the function to be executed by the trigger void setFunction(Function *func); //! \brief Defines the firing condition for trigger void setCondition(const QString &cond); //! \brief Defines the referenced table (only for constraint trigger) void setReferecendTable(BaseTable *ref_table); //! \brief Defines the deferral type void setDeferralType(DeferralType type); //! \brief Defines whether the trigger is deferrable or not void setDeferrable(bool value); //! \brief Changes the specified trigger agument replacing the current argument by the 'new_arg' void editArgument(unsigned arg_idx, const QString &new_arg); //! \brief Defines the moment when the trigger must be executed void setFiringType(FiringType firing_type); //! \brief Defines wheter the trigger executes per row void setExecutePerRow(bool value); //! \brief Defines if the trigger is constraint void setConstraint(bool value); //! \brief Defines the transition table name (OLD|NEW) referenced by the trigger void setTransitionTableName(unsigned tab_idx, const QString &name); //! \brief Returns the transition table name (OLD|NEW) referenced by the trigger QString getTransitionTableName(unsigned tab_idx); //! \brief Returns true if the trigger executes on the passed event bool isExecuteOnEvent(EventType event); //! \brief Returns the current EXECUTE PER ROW state bool isExecutePerRow(void); //! \brief Gets one reference column by its index Column *getColumn(unsigned col_idx); //! \brief Gets one argument by its index QString getArgument(unsigned arg_idx); //! \brief Gets the trigger firing condition QString getCondition(void); //! \brief Returns the function executed by the trigger Function *getFunction(void); //! \brief Returns the trigger argument count unsigned getArgumentCount(void); //! \brief Returns the reference column count unsigned getColumnCount(void); //! \brief Returns when the trigger executes FiringType getFiringType(void); //! \brief Remove an argument using its index void removeArgument(unsigned arg_idx); //! \brief Remove all arguments void removeArguments(void); //! \brief Remove all referenced columns void removeColumns(void); //! \brief Returns the referenced table BaseTable *getReferencedTable(void); //! \brief Returns the deferral type of the constraint trigger DeferralType getDeferralType(void); //! \brief Returns if the constraint trigger is deferrable or not bool isDeferrable(void); //! \brief Returns if the trigger is configured as a constraint trigger bool isConstraint(void); /*! \brief Returns whether the trigger references columns added by relationship. This method is used as auxiliary to control which triggers reference columns added by the relationship in order to avoid referece breaking due constants connections and disconnections of relationships */ bool isReferRelationshipAddedColumn(void); /*! \brief Returns the list of all columns that is created by relationships. This method is slower than isReferRelationshipAddedColumn() so it's not recommended to use it only check if the object is referencing columns added by relationship */ vector getRelationshipAddedColumns(void); //! \brief Returns the SQL / XML definition for the trigger virtual QString getCodeDefinition(unsigned def_type) final; /*! \brief Validates the trigger attributes according to the docs. This method is executed whenever the trigger is added to a table or view. Normally the user don't need to call it explicitly */ void validateTrigger(void); virtual QString getSignature(bool format=true) final; }; #endif pgmodeler-0.9.2/libpgmodeler/src/type.cpp000066400000000000000000000623701360462764600204470ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "type.h" Type::Type(void) { obj_type=ObjectType::Type; setConfiguration(EnumerationType); attributes[Attributes::BaseType]=QString(); attributes[Attributes::CompositeType]=QString(); attributes[Attributes::RangeType]=QString(); attributes[Attributes::TypeAttribute]=QString(); attributes[Attributes::EnumType]=QString(); attributes[Attributes::Enumerations]=QString(); attributes[Attributes::InputFunc]=QString(); attributes[Attributes::OutputFunc]=QString(); attributes[Attributes::RecvFunc]=QString(); attributes[Attributes::SendFunc]=QString(); attributes[Attributes::TpmodInFunc]=QString(); attributes[Attributes::TpmodOutFunc]=QString(); attributes[Attributes::AnalyzeFunc]=QString(); attributes[Attributes::InternalLength]=QString(); attributes[Attributes::ByValue]=QString(); attributes[Attributes::Alignment]=QString(); attributes[Attributes::Storage]=QString(); attributes[Attributes::DefaultValue]=QString(); attributes[Attributes::Element]=QString(); attributes[Attributes::Delimiter]=QString(); attributes[Attributes::ReducedForm]=QString(); attributes[Attributes::Category]=QString(); attributes[Attributes::Preferred]=QString(); attributes[Attributes::LikeType]=QString(); attributes[Attributes::Collatable]=QString(); attributes[Attributes::Subtype]=QString(); attributes[Attributes::SubtypeDiffFunc]=QString(); attributes[Attributes::CanonicalFunc]=QString(); attributes[Attributes::OpClass]=QString(); } void Type::setName(const QString &name) { QString prev_name; prev_name=this->getName(true);//this->nome; BaseObject::setName(name); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void Type::setSchema(BaseObject *schema) { QString prev_name; prev_name=this->getName(true); BaseObject::setSchema(schema); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } int Type::getAttributeIndex(const QString &attrib_name) { vector::iterator itr, itr_end; int idx=-1; itr=type_attribs.begin(); itr_end=type_attribs.end(); while(itr!=itr_end) { if(itr->getName()==attrib_name) { idx=(itr - type_attribs.begin()); break; } itr++; } return(idx); } void Type::addAttribute(TypeAttribute attrib) { //Raises an error if the attribute has an empty name or null type if(attrib.getName().isEmpty() || attrib.getType()==PgSqlType::Null) throw Exception(ErrorCode::InsInvalidTypeAttribute,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the passed attribute has the same type as the defining type (this) else if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !attrib.getType()) throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)), ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error when the attribute already exists else if(getAttributeIndex(attrib.getName()) >= 0) throw Exception(ErrorCode::InsDuplicatedItems,__PRETTY_FUNCTION__,__FILE__,__LINE__); type_attribs.push_back(attrib); setCodeInvalidated(true); } void Type::removeAttribute(unsigned attrib_idx) { //Raises an error if the attribute index is out of bound if(attrib_idx >= type_attribs.size()) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); type_attribs.erase(type_attribs.begin() + attrib_idx); setCodeInvalidated(true); } void Type::removeAttributes(void) { type_attribs.clear(); setCodeInvalidated(true); } bool Type::isEnumerationExists(const QString &enum_name) { vector::iterator itr, itr_end; bool found=false; itr=enumerations.begin(); itr_end=enumerations.end(); while(itr!=itr_end && !found) { found=((*itr)==enum_name); itr++; } return(found); } void Type::addEnumeration(const QString &enum_name) { //Raises an error if the enumaration name is empty if(enum_name.isEmpty()) throw Exception(ErrorCode::InsInvalidEnumerationItem,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the enumeration name is invalid (exceeds the maximum length) else if(enum_name.size() > BaseObject::ObjectNameMaxLength) throw Exception(Exception::getErrorMessage(ErrorCode::AsgEnumLongName).arg(enum_name).arg(this->getName(true)), ErrorCode::AsgEnumLongName,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(enum_name.contains(QChar(','))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgEnumInvalidChars).arg(enum_name).arg(this->getName(true)), ErrorCode::AsgEnumInvalidChars,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the enumeration already exists else if(isEnumerationExists(enum_name)) throw Exception(ErrorCode::InsDuplicatedEnumerationItem,__PRETTY_FUNCTION__,__FILE__,__LINE__); enumerations.push_back(enum_name); setCodeInvalidated(true); } void Type::removeEnumeration(unsigned enum_idx) { if(enum_idx >= enumerations.size()) throw Exception(ErrorCode::RefEnumerationInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); enumerations.erase(enumerations.begin() + enum_idx); setCodeInvalidated(true); } void Type::removeEnumerations(void) { enumerations.clear(); setCodeInvalidated(true); } void Type::setConfiguration(unsigned conf) { //Raises an error if the configuration type is invalid if(conf < BaseType || conf > RangeType) throw Exception(ErrorCode::AsgInvalidTypeConfiguration,__PRETTY_FUNCTION__,__FILE__,__LINE__); type_attribs.clear(); enumerations.clear(); for(unsigned idx=0; idx < sizeof(functions)/sizeof(Function *); idx++) functions[idx]=nullptr; setCollation(nullptr); subtype_opclass=nullptr; alignment=QString("integer"); delimiter='\0'; storage=StorageType::Plain; element=QString("\"any\""); internal_len=0; category=CategoryType::UserDefined; preferred=collatable=by_value=false; like_type=QString("\"any\""); this->config=conf; setCodeInvalidated(true); } void Type::setFunction(unsigned func_id, Function *func) { unsigned param_count=0; LanguageType lang; lang=LanguageType::C; unsigned funcs_len=sizeof(functions)/sizeof(Function *); //Raises an error if the function id is invalid if(func_id >= funcs_len) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(func) param_count=func->getParameterCount(); /* Raises an error if the user try to reference a function id which is incompatible according to the type's configuraiton */ if((config==BaseType && func_id >= CanonicalFunc) || (config==RangeType && func_id <= AnalyzeFunc)) throw Exception(ErrorCode::RefInvalidFunctionIdTypeConfig,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the function isn't defined and the function id is INPUT or OUTPUT, because this function is mandatory for base types */ else if(!func && (func_id==InputFunc || func_id==OutputFunc)) throw Exception(Exception::getErrorMessage(ErrorCode::AsgNotAllocatedFunction) .arg(this->getName(true)) .arg(BaseObject::getTypeName(ObjectType::Type)), ErrorCode::AsgNotAllocatedFunction,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(func) { /* Raises an error if the function language is not C. Functions assigned to base type must be written in C */ if((func_id!=CanonicalFunc && func_id!=SubtypeDiffFunc) && func->getLanguage()->getName()!=~LanguageType(LanguageType::C) && func->getLanguage()->getName()!=~LanguageType(LanguageType::Internal)) throw Exception(ErrorCode::AsgFunctionInvalidLanguage,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Raises an error if the parameter count for INPUT and RECV functions is different from 1 or 3. */ else if((param_count!=1 && param_count!=3 && (func_id==InputFunc || func_id==RecvFunc)) || (param_count!=2 && func_id==SubtypeDiffFunc) || (param_count!=1 && (func_id==OutputFunc || func_id==SendFunc || func_id==TpmodInFunc || func_id==TpmodOutFunc || func_id==AnalyzeFunc || func_id==CanonicalFunc))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParamCount) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Type)), ErrorCode::AsgFunctionInvalidParamCount,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Checking the return types of function in relation to type. INPUT, RECV and CANONICAL functions must return the data type that is being defined according to the documentation, but to facilitate the implementation the function must return data type 'any' which will be replaced by the defined type name at the moment of generation of SQL. OUTPUT and TPMOD_OUT should return cstring. The other functions SEND, TPMOD_IN and ANALYZE should return bytea, integer and boolean, respectively. Raises an error if some of conditions above is not satisfied. */ else if((func_id==InputFunc && func->getReturnType()!=QString("\"any\"")) || (func_id==OutputFunc && func->getReturnType()!=QString("cstring")) || (func_id==RecvFunc && func->getReturnType()!=QString("\"any\"")) || (func_id==SendFunc && func->getReturnType()!=QString("bytea")) || (func_id==TpmodInFunc && func->getReturnType()!=QString("integer")) || (func_id==TpmodOutFunc && func->getReturnType()!=QString("cstring")) || (func_id==AnalyzeFunc && func->getReturnType()!=QString("boolean")) || (func_id==CanonicalFunc && func->getReturnType()!=QString("\"any\"")) || (func_id==SubtypeDiffFunc && func->getReturnType()!=QString("double precision"))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidReturnType) .arg(this->getName()) .arg(BaseObject::getTypeName(ObjectType::Type)), ErrorCode::AsgFunctionInvalidReturnType,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* Validating the parameter types of function in relation to the type configuration. The INPUT function must have parameters with type (cstring, oid, integer). SEND, OUTPUT, CANONICAL must have a parameter of the same type being defined in this case, to facilitate implementation simply use a type parameter "any". The RECV function must have parameters (internal, oid, integer). The function TPMOD_IN must have a type parameter (ctring []). TPMOD_OUT function must have a parameter of type (integer). The ANALYZE function must have a parameter of type (internal). Raises an error if some of above conditions is not satisfied.*/ else if((func_id==InputFunc && (func->getParameter(0).getType()!=QString("cstring") || (param_count==3 && (func->getParameter(1).getType()!=QString("oid") || func->getParameter(2).getType()!=QString("integer"))))) || (func_id==RecvFunc && (func->getParameter(0).getType()!=QString("internal") || (param_count==3 && (func->getParameter(1).getType()!=QString("oid") || func->getParameter(2).getType()!=QString("integer"))))) || ((func_id==SendFunc || func_id==CanonicalFunc || func_id==OutputFunc) && func->getParameter(0).getType()!=QString("\"any\"")) || (func_id==TpmodInFunc && *(func->getParameter(0).getType())!=QString("cstring[]")) || (func_id==TpmodOutFunc && func->getParameter(0).getType()!=QString("integer")) || (func_id==AnalyzeFunc && func->getParameter(0).getType()!=QString("internal")) || (func_id==SubtypeDiffFunc && (func->getParameter(0).getType()!=this->subtype || func->getParameter(1).getType()!=this->subtype))) throw Exception(Exception::getErrorMessage(ErrorCode::AsgFunctionInvalidParameters) .arg(this->getName()) .arg(this->getTypeName()), ErrorCode::AsgFunctionInvalidParameters,__PRETTY_FUNCTION__,__FILE__,__LINE__); func->setProtected(false); } setCodeInvalidated(functions[func_id] != func); functions[func_id]=func; } void Type::convertFunctionParameters(bool inverse_conv) { unsigned i, conf_funcs[]={ InputFunc, RecvFunc, OutputFunc, SendFunc }; Parameter param; Function *func=nullptr; for(i=0; i < 4; i++) { func=functions[conf_funcs[i]]; if(func) { if(conf_funcs[i]==OutputFunc || conf_funcs[i]==SendFunc) { param=func->getParameter(0); func->removeParameter(0); if(!inverse_conv) { param.setType(PgSqlType(this)); func->addParameter(param); } else { param.setType(PgSqlType(QString("\"any\""))); func->addParameter(param); } } else if(conf_funcs[i]==InputFunc || conf_funcs[i]==RecvFunc) { if(!inverse_conv) func->setReturnType(PgSqlType(this)); else func->setReturnType(PgSqlType(QString("\"any\""))); } } } setCodeInvalidated(true); } void Type::setInternalLength(unsigned length) { setCodeInvalidated(internal_len != length); internal_len=length; } void Type::setByValue(bool value) { setCodeInvalidated(by_value != value); by_value=value; } void Type::setAlignment(PgSqlType type) { QString tp=(*type); //Raises an error if the type assigned to the alignment is invalid according to the rule if(tp!=QString("char") && tp!=QString("smallint") && tp!=QString("integer") && tp!=QString("double precision")) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidAlignmentType).arg(this->getName(true)), ErrorCode::AsgInvalidAlignmentType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(alignment != type); alignment=tp; } void Type::setStorage(StorageType strg) { setCodeInvalidated(storage != strg); storage=strg; } void Type::setDefaultValue(const QString &value) { QString def=value.trimmed(); setCodeInvalidated(default_value != def); this->default_value=def; } void Type::setElement(PgSqlType elem) { if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !elem) throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)), ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(elem!=QString("\"any\"") && (elem.isOIDType() || elem.isPseudoType() || elem.isUserType() || elem.isArrayType())) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidElementType).arg(this->getName(true)), ErrorCode::AsgInvalidElementType,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(element != elem); this->element=elem; } void Type::setDelimiter(char delim) { setCodeInvalidated(delimiter != delim); delimiter=delim; } void Type::setElementsAttribute(unsigned def_type) { QString str_elem; unsigned i, count; count=type_attribs.size(); for(i=0; i < count; i++) str_elem+=type_attribs[i].getCodeDefinition(def_type); if(def_type==SchemaParser::SqlDefinition) str_elem.remove(str_elem.lastIndexOf(','), str_elem.size()); attributes[Attributes::TypeAttribute]=str_elem; } void Type::setEnumerationsAttribute(unsigned def_type) { QString str_enum; unsigned i, count; count=enumerations.size(); for(i=0; i < count; i++) { if(def_type==SchemaParser::SqlDefinition) str_enum+=QString("'") + enumerations[i] + QString("'"); else str_enum+=enumerations[i]; if(i < (count-1)) str_enum+=QString(","); } attributes[Attributes::Enumerations]=str_enum; } void Type::setCategory(CategoryType categ) { setCodeInvalidated(category != categ); this->category=categ; } void Type::setPreferred(bool value) { setCodeInvalidated(preferred != value); this->preferred=value; } void Type::setCollatable(bool value) { setCodeInvalidated(collatable != value); this->collatable=value; } void Type::setLikeType(PgSqlType like_type) { if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !like_type) throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)), ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->like_type != like_type); this->like_type=like_type; } void Type::setSubtype(PgSqlType subtype) { if(PgSqlType::getUserTypeIndex(this->getName(true), this) == !subtype) throw Exception(Exception::getErrorMessage(ErrorCode::InvUserTypeSelfReference).arg(this->getName(true)), ErrorCode::InvUserTypeSelfReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(this->subtype != subtype); this->subtype=subtype; } void Type::setSubtypeOpClass(OperatorClass *opclass) { if(opclass && opclass->getIndexingType()!=IndexingType::Btree) throw Exception(Exception::getErrorMessage(ErrorCode::AsgInvalidOpClassObject) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgInvalidOpClassObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setCodeInvalidated(subtype_opclass != opclass); subtype_opclass=opclass; } TypeAttribute Type::getAttribute(unsigned attrib_idx) { if(attrib_idx >= type_attribs.size()) throw Exception(ErrorCode::RefAttributeInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(type_attribs[attrib_idx]); } unsigned Type::getAttributeCount(void) { return(type_attribs.size()); } QString Type::getEnumeration(unsigned idx_enum) { if(idx_enum >= enumerations.size()) throw Exception(ErrorCode::RefEnumerationInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(enumerations[idx_enum]); } unsigned Type::getEnumerationCount(void) { return(enumerations.size()); } Function *Type::getFunction(unsigned func_id) { if(func_id >= sizeof(functions)/sizeof(Function *)) throw Exception(ErrorCode::RefFunctionInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(functions[func_id]); } unsigned Type::getInternalLength(void) { return(internal_len); } bool Type::isByValue(void) { return(by_value); } PgSqlType Type::getAlignment(void) { return(alignment); } StorageType Type::getStorage(void) { return(storage); } QString Type::getDefaultValue(void) { return(default_value); } PgSqlType Type::getElement(void) { return(element); } char Type::getDelimiter(void) { return(delimiter); } unsigned Type::getConfiguration(void) { return(config); } CategoryType Type::getCategory(void) { return(category); } bool Type::isPreferred(void) { return(preferred); } bool Type::isCollatable(void) { return(collatable); } PgSqlType Type::getLikeType(void) { return(like_type); } PgSqlType Type::getSubtype(void) { return(subtype); } OperatorClass *Type::getSubtypeOpClass(void) { return(subtype_opclass); } QString Type::getCodeDefinition(unsigned def_type) { return(this->getCodeDefinition(def_type, false)); } QString Type::getCodeDefinition(unsigned def_type, bool reduced_form) { QString code_def=getCachedCode(def_type, reduced_form); if(!code_def.isEmpty()) return(code_def); if(config==EnumerationType) { attributes[Attributes::EnumType]=Attributes::True; setEnumerationsAttribute(def_type); } else if(config==CompositeType) { attributes[Attributes::CompositeType]=Attributes::True; setElementsAttribute(def_type); } else if(config==RangeType) { attributes[Attributes::RangeType]=Attributes::True; if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Subtype]=(*subtype); else attributes[Attributes::Subtype]=subtype.getCodeDefinition(SchemaParser::XmlDefinition); if(subtype_opclass) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::OpClass]=subtype_opclass->getName(true); else attributes[Attributes::OpClass]=subtype_opclass->getCodeDefinition(def_type, true); } } else { attributes[Attributes::BaseType]=Attributes::True; if(internal_len==0 && def_type==SchemaParser::SqlDefinition) attributes[Attributes::InternalLength]=QString("VARIABLE"); else attributes[Attributes::InternalLength]=QString("%1").arg(internal_len); attributes[Attributes::ByValue]=(by_value ? Attributes::True : QString()); attributes[Attributes::Alignment]=(*alignment); attributes[Attributes::Storage]=(~storage); attributes[Attributes::DefaultValue]=default_value; if(element!=QString("\"any\"")) attributes[Attributes::Element]=(*element); if(delimiter!='\0') attributes[Attributes::Delimiter]=delimiter; attributes[Attributes::Category]=~(category); attributes[Attributes::Preferred]=(preferred ? Attributes::True : QString()); attributes[Attributes::Collatable]=(collatable ? Attributes::True : QString()); if(like_type!=QString("\"any\"")) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::LikeType]=(*like_type); else attributes[Attributes::LikeType]=like_type.getCodeDefinition(SchemaParser::XmlDefinition); } } if(config==BaseType || config==RangeType) { unsigned i; QString func_attrib[]={Attributes::InputFunc, Attributes::OutputFunc, Attributes::RecvFunc, Attributes::SendFunc, Attributes::TpmodInFunc, Attributes::TpmodOutFunc, Attributes::AnalyzeFunc, Attributes::CanonicalFunc, Attributes::SubtypeDiffFunc}; for(i=0; i < sizeof(functions)/sizeof(Function *); i++) { if(functions[i]) { if(def_type==SchemaParser::SqlDefinition) attributes[func_attrib[i]]=functions[i]->getName(); else { functions[i]->setAttribute(Attributes::RefType, func_attrib[i]); attributes[func_attrib[i]]=functions[i]->getCodeDefinition(def_type, true); } } } } return(BaseObject::getCodeDefinition(def_type, reduced_form)); } QString Type::getAlterDefinition(BaseObject *object) { Type *type=dynamic_cast(object); if(!type) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { attribs_map attribs; QString alter_def, prev_val; int attrib_idx=-1; alter_def=BaseObject::getAlterDefinition(object); if(this->config==type->config) { if(config==EnumerationType) { for(QString enum_val : type->enumerations) { if(std::find(this->enumerations.begin(), this->enumerations.end(), enum_val)==this->enumerations.end()) { attribs[Attributes::Before]=QString(); if(prev_val.isEmpty()) { attribs[Attributes::Before]=Attributes::True; prev_val=this->enumerations[0]; } attribs[Attributes::Value]=enum_val; attribs[Attributes::ExistingValue]=prev_val; copyAttributes(attribs); alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true); attribs.clear(); } prev_val=enum_val; } } else if(config==CompositeType) { //Removing type attributes for(TypeAttribute attrib : this->type_attribs) { if(type->getAttributeIndex(attrib.getName()) < 0) { attribs[Attributes::Drop]=Attributes::True; attribs[Attributes::Attribute]=attrib.getName(true); copyAttributes(attribs); alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true); attribs.clear(); attributes[Attributes::Drop]=QString(); } } for(TypeAttribute attrib : type->type_attribs) { attrib_idx=this->getAttributeIndex(attrib.getName()); //Creating type attributes if(attrib_idx < 0) { attribs[Attributes::Attribute]=attrib.getName(true); attribs[Attributes::Type]=attrib.getType().getCodeDefinition(SchemaParser::SqlDefinition); attribs[Attributes::Collation]=QString(); if(attrib.getCollation()) attribs[Attributes::Collation]=attrib.getCollation()->getName(true); copyAttributes(attribs); alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true); } //Changing type attributes else { attribs[Attributes::Change]=Attributes::True; if(!type_attribs[attrib_idx].getType().isEquivalentTo(attrib.getType())) { attribs[Attributes::Attribute]=attrib.getName(true); attribs[Attributes::Type]=attrib.getType().getCodeDefinition(SchemaParser::SqlDefinition); } copyAttributes(attribs); alter_def+=BaseObject::getAlterDefinition(this->getSchemaName(), attributes, true, true); attributes[Attributes::Change]=QString(); } attribs.clear(); } } } return(alter_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Type::operator = (Type &type) { QString prev_name; unsigned i=0; prev_name=this->getName(true); *(dynamic_cast(this))=dynamic_cast(type); this->config=type.config; this->type_attribs=type.type_attribs; this->enumerations=type.enumerations; this->internal_len=type.internal_len; this->by_value=type.by_value; this->alignment=type.alignment; this->element=type.element; this->storage=type.storage; this->default_value=type.default_value; this->category=type.category; this->preferred=type.preferred; this->like_type=type.like_type; this->delimiter=type.delimiter; this->collatable=type.collatable; this->subtype=type.subtype; this->subtype_opclass=type.subtype_opclass; while(i < sizeof(functions)/sizeof(Function *)) { this->functions[i]=type.functions[i]; i++; } PgSqlType::renameUserType(prev_name, this, this->getName(true)); } pgmodeler-0.9.2/libpgmodeler/src/type.h000066400000000000000000000171051360462764600201100ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Type \brief Implements the operations to manipulate user defined types on database. \note Creation date: 05/06/2008 */ #ifndef TYPE_H #define TYPE_H #include "baseobject.h" #include "schema.h" #include "function.h" #include "role.h" #include "typeattribute.h" #include "operatorclass.h" class Type: public BaseObject { private: //! \brief Type configuration (BASE | ENUMERATION | COMPOSITE | RANGE) unsigned config; //! \brief Attributes for composite type vector type_attribs; //! \brief Enumerations of enumeration type vector enumerations; //! \brief Functions used by the base type Function *functions[9]; //! \brief Type's internal length ( > 0 - Fixed length, 0 - Variable length) unsigned internal_len; //! \brief INTERNALLENGTH //! \brief Indicates that the type can be passed by value bool by_value, // PASSEDBYVALUE //! \brief Indicates if type can use collations collatable, //COLLATABLE //! \brief Used with the category attribute (only for base type) - Default FALSE preferred; //PREFERRED //! \brief Storage alignmnet (char, smallint (int2), integer (int4) ou double precision) PgSqlType alignment, //ALIGNMENT element; //ELEMENT //! \brief Type's storage StorageType storage; //STORAGE //! \brief Default value for the type QString default_value; //DEFAULT //! \brief Type's category (only for base type) - Default 'U' CategoryType category; //CATEGORY /*! \brief Type which will have some of its attributes copied to the current type (only for base type). If like_type is 'any' means that the current type does not copy attributes of any type */ PgSqlType like_type, //LIKE //! \brief Subtype used by a range type subtype; //SUBTYPE //! \brief Character used as value delimiter when the type is used as array char delimiter; //DELIMITER //! \brief Operator class associated to the subtype (only for range type) OperatorClass *subtype_opclass; //! \brief Checks if the named attribute exists int getAttributeIndex(const QString &attrib_name); //! \brief Checks if the named enumeration exists bool isEnumerationExists(const QString &enum_name); //! \brief Formats the elements string used by the SchemaParser void setElementsAttribute(unsigned def_type); //! \brief Formats the enumeration string used by the SchemaParser void setEnumerationsAttribute(unsigned def_type); /*! \brief Performs the conversion of parameters and return types of functions. If the parameter 'inverse_conv' is selected, the method makes the conversion from 'type_name' to 'any' otherwise makes the conversion from 'any' to 'type_name'. This method is used when generating the SQL codes for user-defined type */ void convertFunctionParameters(bool inverse_conv=false); public: static constexpr unsigned BaseType=10, EnumerationType=11, CompositeType=12, RangeType=13; static constexpr unsigned InputFunc=0, OutputFunc=1, RecvFunc=2, SendFunc=3, TpmodInFunc=4, TpmodOutFunc=5, AnalyzeFunc=6, CanonicalFunc=7, SubtypeDiffFunc=8; Type(void); //! \brief Sets the type name void setName(const QString &name); //! \brief Sets the type schema void setSchema(BaseObject *schema); /*! \brief Defines the type configuration (BASE | ENUMARATION | COMPOSITE | RANGE). Calling this method causes all attribute to be reset, so it may be executed before any other attribute of the type be defined. */ void setConfiguration(unsigned conf); //! \brief Adds an attribute to the type (only for composite type) void addAttribute(TypeAttribute attrib); //! \brief Removes an attribute from the type (only for composite type) void removeAttribute(unsigned attrib_idx); //! \brief Removes all attributes from the type (only for composite type) void removeAttributes(void); //! \brief Adds an enumeration to the type (only for enumeration type) void addEnumeration(const QString &enum_name); //! \brief Removes an enumeration from the type (only for enumeration type) void removeEnumeration(unsigned enum_idx); //! \brief Removes all enumerations from the type (only for enumeration type) void removeEnumerations(void); //! \brief Sets on function to the type (only for base type) void setFunction(unsigned func_id, Function *func); //! \brief Sets the type internal length (only for base type) void setInternalLength(unsigned length); //! \brief Sets if the type can be passed by value (only for base type) void setByValue(bool value); //! \brief Sets if the type can use collation (only for base type) void setCollatable(bool value); //! \brief Sets the alignment for the type (only for base type) void setAlignment(PgSqlType type); //! \brief Sets the storage type (only for base type) void setStorage(StorageType strg); //! \brief Sets the default value for the type (only for base type) void setDefaultValue(const QString &value); //! \brief Sets the element for the type (only for base type) void setElement(PgSqlType elem); //! \brief Sets the delimiter for the type (only for base type) void setDelimiter(char delim); //! \brief Sets the category for the type (only for base type) void setCategory(CategoryType categ); //! \brief Sets if the type is preferred (only for base type) void setPreferred(bool value); //! \brief Sets the type that will be used as template (only for base type) void setLikeType(PgSqlType like_type); //! \brief Sets the subtype that will be used by the range (only for range type) void setSubtype(PgSqlType subtype); //! \brief Sets the subtype operator class (only for range type) void setSubtypeOpClass(OperatorClass *opclass); PgSqlType getSubtype(void); OperatorClass *getSubtypeOpClass(void); TypeAttribute getAttribute(unsigned attrib_idx); unsigned getAttributeCount(void); QString getEnumeration(unsigned idx_enum); unsigned getEnumerationCount(void); unsigned getConfiguration(void); CategoryType getCategory(void); bool isPreferred(void); PgSqlType getLikeType(void); Function *getFunction(unsigned func_id); unsigned getInternalLength(void); bool isByValue(void); bool isCollatable(void); PgSqlType getAlignment(void); StorageType getStorage(void); QString getDefaultValue(void); PgSqlType getElement(void); char getDelimiter(void); /*! \brief Returns the SQL / XML definition for the type. If the boolean parameter is set the code definition is generated in a reduced form (XML only) */ virtual QString getCodeDefinition(unsigned def_type, bool reduced_form) final; //! \brief Returns the SQL / XML definition for the type virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getAlterDefinition(BaseObject *object) final; //! \brief Makes a copy between two type void operator = (Type &tipo); friend class DatabaseModel; friend class ModelsDiffHelper; }; #endif pgmodeler-0.9.2/libpgmodeler/src/typeattribute.cpp000066400000000000000000000034301360462764600223630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "typeattribute.h" TypeAttribute::TypeAttribute(void) { obj_type=ObjectType::TypeAttribute; } void TypeAttribute::setType(PgSqlType type) { setCodeInvalidated(this->type != type); this->type=type; } PgSqlType TypeAttribute::getType(void) { return(type); } QString TypeAttribute::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Name]=BaseObject::formatName(obj_name); else attributes[Attributes::Name]=obj_name; attributes[Attributes::Type]=type.getCodeDefinition(def_type); if(collation) { if(def_type==SchemaParser::SqlDefinition) attributes[Attributes::Collation]=collation->getName(true); else attributes[Attributes::Collation]=collation->getCodeDefinition(def_type, true); } return(BaseObject::__getCodeDefinition(def_type)); } void TypeAttribute::operator = (const TypeAttribute &tpattrib) { this->obj_name=tpattrib.obj_name; this->type=tpattrib.type; this->collation=tpattrib.collation; } pgmodeler-0.9.2/libpgmodeler/src/typeattribute.h000066400000000000000000000025001360462764600220250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class TypeArgument \brief Implements the operations to manipulate user defined types arguments. */ #ifndef TYPE_ARGUMENT_H #define TYPE_ARGUMENT_H #include "baseobject.h" class TypeAttribute: public BaseObject { private: PgSqlType type; QString getCodeDefinition(unsigned, bool){ return(""); } public: TypeAttribute(void); void setType(PgSqlType type); PgSqlType getType(void); //! \brief Returns the SQL / XML code definition for the parameter virtual QString getCodeDefinition(unsigned def_type) final; void operator = (const TypeAttribute &tpattrib); }; #endif pgmodeler-0.9.2/libpgmodeler/src/usermapping.cpp000066400000000000000000000056661360462764600220250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "usermapping.h" UserMapping::UserMapping(void) : BaseObject() { obj_type = ObjectType::UserMapping; foreign_server = nullptr; setName(""); attributes[Attributes::Server] = QString(); attributes[Attributes::Options] = QString(); } void UserMapping::setForeignServer(ForeignServer *server) { setCodeInvalidated(foreign_server != server); foreign_server = server; setName(""); } ForeignServer *UserMapping::getForeignServer(void) { return(foreign_server); } void UserMapping::setOwner(BaseObject *role) { BaseObject::setOwner(role); setName(""); } void UserMapping::setName(const QString &) { //Configures a fixed name for the user mapping (in form: role@server) this->obj_name=QString("%1@%2").arg(owner ? owner->getName() : QString("public")) .arg(foreign_server ? foreign_server->getName() : QString()); } QString UserMapping::getName(bool, bool) { return(this->obj_name); } QString UserMapping::getSignature(bool) { return(QString("FOR %1 SERVER %2").arg(owner ? owner->getName() : QString("public")) .arg(foreign_server ? foreign_server->getName() : QString())); } QString UserMapping::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::Role] = QString(); attributes[Attributes::Server] = QString(); if(foreign_server) { if(def_type == SchemaParser::SqlDefinition) attributes[Attributes::Server] = foreign_server->getName(true); else attributes[Attributes::Server] = foreign_server->getCodeDefinition(def_type, true); } attributes[Attributes::Options] = getOptionsAttribute(def_type); return(this->BaseObject::__getCodeDefinition(def_type)); } QString UserMapping::getAlterDefinition(BaseObject *object) { try { attributes[Attributes::AlterCmds] = BaseObject::getAlterDefinition(object); getAlteredAttributes(dynamic_cast(object), attributes); return(BaseObject::getAlterDefinition(this->getSchemaName(), attributes, false, true)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString UserMapping::getDropDefinition(bool) { return(BaseObject::getDropDefinition(false)); } pgmodeler-0.9.2/libpgmodeler/src/usermapping.h000066400000000000000000000031101360462764600214500ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \class Server \brief Implements the operations to manipulate user mappings on the database. */ #ifndef USER_MAPPING_H #define USER_MAPPING_H #include "baseobject.h" #include "foreignserver.h" class UserMapping: public BaseObject, public ForeignObject { private: //! \brief The foreign server which is managed by this user mapping the server ForeignServer *foreign_server; public: UserMapping(void); void setForeignServer(ForeignServer *server); ForeignServer *getForeignServer(void); virtual void setName(const QString &); virtual void setOwner(BaseObject *role); virtual QString getName(bool = false, bool = false); virtual QString getSignature(bool = false); virtual QString getCodeDefinition(unsigned def_type); virtual QString getAlterDefinition(BaseObject *object); virtual QString getDropDefinition(bool); }; #endif pgmodeler-0.9.2/libpgmodeler/src/view.cpp000066400000000000000000000701141360462764600204330ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "view.h" View::View(void) : BaseTable() { obj_type=ObjectType::View; materialized=recursive=with_no_data=false; attributes[Attributes::Definition]=QString(); attributes[Attributes::References]=QString(); attributes[Attributes::SelectExp]=QString(); attributes[Attributes::FromExp]=QString(); attributes[Attributes::SimpleExp]=QString(); attributes[Attributes::EndExp]=QString(); attributes[Attributes::CteExpression]=QString(); attributes[Attributes::Materialized]=QString(); attributes[Attributes::Recursive]=QString(); attributes[Attributes::WithNoData]=QString(); attributes[Attributes::Columns]=QString(); } View::~View(void) { ObjectType types[]={ ObjectType::Trigger, ObjectType::Rule, ObjectType::Index }; vector *list=nullptr; for(unsigned i=0; i < 3; i++) { list=getObjectList(types[i]); while(!list->empty()) { delete(list->back()); list->pop_back(); } } } void View::setName(const QString &name) { QString prev_name=this->getName(true); BaseObject::setName(name); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void View::setSchema(BaseObject *schema) { QString prev_name=this->getName(true); BaseObject::setSchema(schema); PgSqlType::renameUserType(prev_name, this, this->getName(true)); } void View::setProtected(bool value) { ObjectType obj_types[]={ ObjectType::Rule, ObjectType::Trigger }; unsigned i; vector::iterator itr, itr_end; vector *list=nullptr; //Protected the table child objects for(i=0; i < sizeof(obj_types)/sizeof(ObjectType); i++) { list=getObjectList(obj_types[i]); itr=list->begin(); itr_end=list->end(); while(itr!=itr_end) { (*itr)->setProtected(value); itr++; } } //Protects the view itself BaseGraphicObject::setProtected(value); } void View::setMaterialized(bool value) { setCodeInvalidated(materialized != value); materialized=value; if(materialized) recursive=false; } void View::setRecursive(bool value) { setCodeInvalidated(recursive != value); recursive=value; if(recursive) materialized=false; } void View::setWithNoData(bool value) { setCodeInvalidated(materialized && with_no_data != value); with_no_data=(materialized ? value : false); } bool View::isMaterialized(void) { return(materialized); } bool View::isRecursive(void) { return(recursive); } bool View::isWithNoData(void) { return(with_no_data); } void View::setCommomTableExpression(const QString &expr) { setCodeInvalidated(cte_expression != expr); cte_expression=expr; } bool View::hasDefinitionExpression(void) { vector::iterator itr; bool found=false; itr=references.begin(); while(itr!=references.end() && !found) { found=((*itr).isDefinitionExpression()); itr++; } return(found); } QString View::getCommomTableExpression(void) { return(cte_expression); } int View::getReferenceIndex(Reference &refer) { vector::iterator itr, itr_end; bool found=false; int idx=-1; itr=references.begin(); itr_end=references.end(); while(itr!=itr_end && !found) { found=((*itr)==refer); itr++; idx++; } if(!found) idx=-1; return(idx); } vector *View::getExpressionList(unsigned sql_type) { if(sql_type==Reference::SqlReferSelect) return(&exp_select); else if(sql_type==Reference::SqlReferFrom) return(&exp_from); else if(sql_type==Reference::SqlReferWhere) return(&exp_where); else if(sql_type==Reference::SqlReferEndExpr) return(&exp_end); else return(nullptr); } void View::generateColumns(void) { unsigned col_id = 0, col_count = 0, expr_idx = 0; PhysicalTable *tab = nullptr; Reference ref; Column *col = nullptr; QString name, alias; columns.clear(); if(hasDefinitionExpression()) { vector ref_cols = references[0].getColumns(); if(ref_cols.empty()) columns.push_back(SimpleColumn(QString("%1...").arg(references[0].getExpression().simplified().mid(0, 20)), Attributes::Expression, !references[0].getReferenceAlias().isEmpty() ? references[0].getReferenceAlias() : QString())); else columns = ref_cols; } else { for(auto ref_id : exp_select) { ref = references[ref_id]; if(!ref.getExpression().isEmpty()) { if(!ref.getAlias().isEmpty()) name = ref.getAlias(); else name = QString("_expr%1_").arg(expr_idx++); name = getUniqueColumnName(name); columns.push_back(SimpleColumn(name, Attributes::Expression, !ref.getReferenceAlias().isEmpty() ? ref.getReferenceAlias() : name)); } else if(!ref.getColumn()) { tab=ref.getTable(); col_count=tab->getColumnCount(); for(col_id=0; col_id < col_count; col_id++) { col = tab->getColumn(col_id); name = getUniqueColumnName(col->getName()); columns.push_back(SimpleColumn(name, *col->getType(), !col->getAlias().isEmpty() ? col->getAlias() : col->getName())); } } else { col = ref.getColumn(); if(!ref.getColumnAlias().isEmpty()) name = getUniqueColumnName(ref.getColumnAlias()); else name = getUniqueColumnName(col->getName()); if(!ref.getReferenceAlias().isEmpty()) alias = ref.getReferenceAlias(); else alias = !col->getAlias().isEmpty() ? col->getAlias() : col->getName(); columns.push_back(SimpleColumn(name, *col->getType(), alias)); } } } } vector View::getColumns(void) { return(columns); } void View::addReference(Reference &refer, unsigned sql_type, int expr_id) { int idx; vector *expr_list=nullptr; Column *col=nullptr; //Specific tests for expressions used as view definition if(sql_type==Reference::SqlViewDefinition) { //Raises an error if the expression is empty if(refer.getExpression().isEmpty()) throw Exception(ErrorCode::AsgInvalidViewDefExpression,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if already exists a definition expression else if(hasDefinitionExpression()) throw Exception(ErrorCode::AsgSecondViewDefExpression,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the user try to add a definition expression when already exists another references else if(!references.empty()) throw Exception(ErrorCode::MixingViewDefExprsReferences,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the user try to add a ordinary reference when there is a reference used as definition expression else if(hasDefinitionExpression()) throw Exception(ErrorCode::MixingViewDefExprsReferences,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Checks if the reference already exists idx=getReferenceIndex(refer); //If not exists if(idx < 0) { //Inserts the reference on the view refer.setDefinitionExpression(sql_type==Reference::SqlViewDefinition); references.push_back(refer); idx=references.size()-1; } if(sql_type!=Reference::SqlViewDefinition) { //Gets the expression list expr_list=getExpressionList(sql_type); //Avoiding the insertion of a duplicated reference in the expression list if(std::find(expr_list->begin(), expr_list->end(), idx) != expr_list->end()) return; //Inserts the reference id on the expression list if(expr_id >= 0 && expr_id < static_cast(expr_list->size())) expr_list->insert(expr_list->begin() + expr_id, static_cast(idx)); //Raises an error if the expression id is invalid else if(expr_id >= 0 && expr_id >= static_cast(expr_list->size())) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); else expr_list->push_back(static_cast(idx)); col=refer.getColumn(); if(col && col->isAddedByRelationship() && col->getObjectId() > this->object_id) this->object_id=BaseObject::getGlobalId(); } generateColumns(); setCodeInvalidated(true); } unsigned View::getReferenceCount(void) { return(references.size()); } unsigned View::getReferenceCount(unsigned sql_type, int ref_type) { vector *vect_idref=getExpressionList(sql_type); if(!vect_idref) { if(sql_type==Reference::SqlViewDefinition) return(references.size()); else return(0); } else { if(ref_type < 0) return(vect_idref->size()); else { vector::iterator itr, itr_end; unsigned count=0; itr=vect_idref->begin(); itr_end=vect_idref->end(); while(itr!=itr_end) { if(references[(*itr)].getReferenceType()==static_cast(ref_type)) count++; itr++; } return(count); } } } Reference View::getReference(unsigned ref_id) { //Raises an error if the reference id is out of bound if(ref_id >= references.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(references[ref_id]); } Reference View::getReference(unsigned ref_id, unsigned sql_type) { vector *vect_idref=getExpressionList(sql_type); //Raises an error if the reference id is out of bound if(ref_id >= references.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(sql_type==Reference::SqlViewDefinition || vect_idref) return(references[ref_id]); else return(references[vect_idref->at(ref_id)]); } void View::removeReference(unsigned ref_id) { vector *vect_idref[4]={&exp_select, &exp_from, &exp_where, &exp_end}; vector::iterator itr, itr_end; unsigned i; //Raises an error if the reference id is out of bound if(ref_id >= references.size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); for(i=0; i < 3; i++) { itr=vect_idref[i]->begin(); itr_end=vect_idref[i]->end(); while(itr!=itr_end && !vect_idref[i]->empty()) { //Removes the reference id from the expression list if(references[*itr]==references[ref_id]) itr = vect_idref[i]->erase(itr); else itr++; } } //Removes the reference from the view references.erase(references.begin() + ref_id); generateColumns(); setCodeInvalidated(true); } void View::removeReferences(void) { references.clear(); exp_select.clear(); exp_from.clear(); exp_where.clear(); exp_end.clear(); columns.clear(); setCodeInvalidated(true); } void View::removeReference(unsigned expr_id, unsigned sql_type) { vector *vect_idref=getExpressionList(sql_type); if(expr_id >= vect_idref->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); vect_idref->erase(vect_idref->begin() + expr_id); setCodeInvalidated(true); } int View::getReferenceIndex(Reference &ref, unsigned sql_type) { vector *vet_idref=getExpressionList(sql_type); vector::iterator itr, itr_end; int idx_ref; bool found=false; idx_ref=getReferenceIndex(ref); if(sql_type==Reference::SqlViewDefinition && idx_ref >=0 && ref.isDefinitionExpression()) return(idx_ref); else if(sql_type!=Reference::SqlViewDefinition) { itr=vet_idref->begin(); itr_end=vet_idref->end(); while(itr!=itr_end && !found) { found=(static_cast(*itr)==idx_ref); if(!found) itr++; } if(!found) return(-1); else return(itr-vet_idref->begin()); } else return(-1); } void View::setDefinitionAttribute(void) { QString decl; if(!references.empty()) { if(exp_select.empty()) { decl=references[0].getExpression(); } else { vector *refs_vect[4]={&exp_select, &exp_from, &exp_where, &exp_end}; vector::iterator itr, itr_end; QString keywords[4]={"SELECT\n", "\nFROM\n", "\nWHERE\n", "\n"}; unsigned i, cnt, idx, sql_type[4]={ Reference::SqlReferSelect, Reference::SqlReferFrom, Reference::SqlReferWhere, Reference::SqlReferEndExpr }; for(i=0; i < 4; i++) { if(refs_vect[i]->size() > 0) { decl+=keywords[i]; itr=refs_vect[i]->begin(); itr_end=refs_vect[i]->end(); while(itr!=itr_end) { idx=(*itr); decl+=references[idx].getSQLDefinition(sql_type[i]); itr++; } if(sql_type[i]==Reference::SqlReferSelect || sql_type[i]==Reference::SqlReferFrom) { //Removing the final comma from SELECT / FROM declarations cnt=decl.size(); if(decl[cnt-2]==',') decl.remove(cnt-2,2); } } } } } decl=decl.trimmed(); if(!decl.isEmpty() && !decl.endsWith(QChar(';'))) decl.append(QChar(';')); attributes[Attributes::Definition]=decl; } void View::setReferencesAttribute(void) { QString str_aux; QString attribs[]={ Attributes::SelectExp, Attributes::FromExp, Attributes::SimpleExp, Attributes::EndExp}; vector *vect_exp[]={&exp_select, &exp_from, &exp_where, &exp_end}; int cnt, i, i1; cnt=references.size(); for(i=0; i < cnt; i++) str_aux+=references[i].getXMLDefinition(); attributes[Attributes::References]=str_aux; for(i=0; i < 4; i++) { str_aux=QString(); cnt=vect_exp[i]->size(); for(i1=0; i1 < cnt; i1++) { str_aux+=QString("%1").arg(vect_exp[i]->at(i1)); if(i1 < cnt-1) str_aux+=QString(","); } attributes[attribs[i]]=str_aux; } } bool View::isReferRelationshipAddedColumn(void) { Column *column=nullptr; unsigned count, i; bool found=false; count=references.size(); for(i=0; i < count && !found; i++) { column=references[i].getColumn(); found=(column && column->isAddedByRelationship()); } return(found); } vector View::getRelationshipAddedColumns(void) { vector cols; Column *col=nullptr; for(auto &ref : references) { col=ref.getColumn(); if(col && col->isAddedByRelationship()) cols.push_back(col); } return(cols); } bool View::isReferencingTable(PhysicalTable *tab) { PhysicalTable *aux_tab=nullptr; unsigned count, i; bool found=false; count=references.size(); for(i=0; i < count && !found; i++) { if(references[i].isDefinitionExpression()) found = references[i].getReferencedTableIndex(tab) >= 0; else { aux_tab = references[i].getTable(); found = (aux_tab && (aux_tab == tab)); } } return(found); } bool View::isReferencingColumn(Column *col) { unsigned count, i; bool found=false; if(col) { count=references.size(); for(i=0; i < count && !found; i++) found=(col==references[i].getColumn()); } return(found); } QString View::getCodeDefinition(unsigned def_type) { QString code_def=getCachedCode(def_type, false); if(!code_def.isEmpty()) return(code_def); attributes[Attributes::CteExpression]=cte_expression; attributes[Attributes::Materialized]=(materialized ? Attributes::True : QString()); attributes[Attributes::Recursive]=(recursive ? Attributes::True : QString()); attributes[Attributes::WithNoData]=(with_no_data ? Attributes::True : QString()); attributes[Attributes::Columns]=QString(); attributes[Attributes::Tag]=QString(); attributes[Attributes::Layer]=QString::number(layer); attributes[Attributes::Pagination]=(pagination_enabled ? Attributes::True : QString()); attributes[Attributes::CollapseMode]=QString::number(enum_cast(collapse_mode)); attributes[Attributes::AttribsPage]=(pagination_enabled ? QString::number(curr_page[AttribsSection]) : QString()); attributes[Attributes::ExtAttribsPage]=(pagination_enabled ? QString::number(curr_page[ExtAttribsSection]) : QString()); setSQLObjectAttribute(); // We use column names only if the view has references that aren't its whole definition (Reference::SqlViewDefinition) if(recursive && !hasDefinitionExpression()) { QStringList fmt_names; //for(auto &name : col_names) // fmt_names.push_back(formatName(name)); for(auto &col : columns) fmt_names.push_back(formatName(col.name)); attributes[Attributes::Columns]=fmt_names.join(','); } if(tag && def_type==SchemaParser::XmlDefinition) attributes[Attributes::Tag]=tag->getCodeDefinition(def_type, true); if(def_type==SchemaParser::SqlDefinition) setDefinitionAttribute(); else { setPositionAttribute(); setFadedOutAttribute(); setReferencesAttribute(); attributes[Attributes::MaxObjCount]=QString::number(static_cast(getMaxObjectCount() * 1.20)); } return(BaseObject::__getCodeDefinition(def_type)); } void View::setSQLObjectAttribute(void) { if(materialized) attributes[Attributes::SqlObject]=QString("MATERIALIZED ") + BaseObject::getSQLName(ObjectType::View); } QString View::getUniqueColumnName(const QString &name) { unsigned idx = 1; QString fmt_name = name; vector::iterator itr, itr_end; itr = columns.begin(); itr_end = columns.end(); while(itr != itr_end) { if(itr->name == fmt_name) { fmt_name = name + QString::number(idx); idx++; itr = columns.begin(); } else itr++; } return(fmt_name); } void View::setObjectListsCapacity(unsigned capacity) { if(capacity < DefMaxObjectCount || capacity > DefMaxObjectCount * 10) capacity = DefMaxObjectCount; references.reserve(capacity); indexes.reserve(capacity/2); rules.reserve(capacity/2); triggers.reserve(capacity/2); } unsigned View::getMaxObjectCount(void) { unsigned count = 0, max = references.size(); vector types = { ObjectType::Index, ObjectType::Rule, ObjectType::Trigger }; for(auto type : types) { count = getObjectList(type)->size(); if(count > max) max = count; } return(max); } QString View::getDropDefinition(bool cascade) { setSQLObjectAttribute(); return(BaseObject::getDropDefinition(cascade)); } int View::getObjectIndex(BaseObject *obj) { TableObject *tab_obj=dynamic_cast(obj); if(!obj || (tab_obj && tab_obj->getParentTable()!=this)) return(-1); else { vector::iterator itr, itr_end; vector *obj_list=getObjectList(obj->getObjectType()); bool found=false; itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && !found) { found=((*itr)==tab_obj); if(!found) itr++; } if(found) return(itr - obj_list->begin()); else return(-1); } } int View::getObjectIndex(const QString &name, ObjectType obj_type) { if(name.isEmpty()) return(-1); else { vector::iterator itr, itr_end; vector *obj_list=getObjectList(obj_type); bool found=false, format=name.contains('"'); itr=obj_list->begin(); itr_end=obj_list->end(); while(itr!=itr_end && !found) { found=((*itr)->getName(format)==name); if(!found) itr++; } if(found) return(itr - obj_list->begin()); else return(-1); } } void View::addObject(BaseObject *obj, int obj_idx) { if(!obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { try { vector *obj_list = getObjectList(obj->getObjectType()); TableObject *tab_obj=dynamic_cast(obj); //Raises an error if already exists a object with the same name and type if(getObjectIndex(obj->getName(), tab_obj->getObjectType()) >= 0) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(obj->getName(true)) .arg(obj->getTypeName()) .arg(this->getName(true)) .arg(this->getTypeName()), ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Validates the object definition tab_obj->setParentTable(this); tab_obj->getCodeDefinition(SchemaParser::SqlDefinition); //Make a additional validation if the object is a trigger if(tab_obj->getObjectType()==ObjectType::Trigger) dynamic_cast(tab_obj)->validateTrigger(); //Inserts the object at specified position if(obj_idx < 0 || obj_idx >= static_cast(obj_list->size())) obj_list->push_back(tab_obj); else obj_list->insert(obj_list->begin() + obj_idx, tab_obj); setCodeInvalidated(true); } catch(Exception &e) { if(e.getErrorCode()==ErrorCode::UndefinedAttributeValue) throw Exception(Exception::getErrorMessage(ErrorCode::AsgObjectInvalidDefinition) .arg(obj->getName()) .arg(obj->getTypeName()), ErrorCode::AsgObjectInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void View::addTrigger(Trigger *trig, int obj_idx) { try { addObject(trig, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::addRule(Rule *rule, int obj_idx) { try { addObject(rule, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::addIndex(Index *index, int obj_idx) { try { addObject(index, obj_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::removeObject(unsigned obj_idx, ObjectType obj_type) { vector *obj_list = getObjectList(obj_type); vector::iterator itr; //Raises an error if the object index is out of bound if(obj_idx >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); itr=obj_list->begin() + obj_idx; (*itr)->setParentTable(nullptr); obj_list->erase(itr); setCodeInvalidated(true); } void View::removeObject(BaseObject *obj) { try { removeObject(getObjectIndex(obj), obj->getObjectType()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::removeObject(const QString &name, ObjectType obj_type) { try { removeObject(getObjectIndex(name, obj_type), obj_type); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::removeTrigger(unsigned idx) { try { removeObject(idx, ObjectType::Trigger); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::removeRule(unsigned idx) { try { removeObject(idx, ObjectType::Rule); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void View::removeIndex(unsigned idx) { try { removeObject(idx, ObjectType::Index); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } TableObject *View::getObject(unsigned obj_idx, ObjectType obj_type) { vector *obj_list=getObjectList(obj_type); //Raises an error if the object index is out of bound if(obj_idx >= obj_list->size()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(obj_list->at(obj_idx)); } TableObject *View::getObject(const QString &name, ObjectType obj_type) { try { int idx=getObjectIndex(name, obj_type); if(idx >= 0) return(getObject(idx, obj_type)); else return(nullptr); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Trigger *View::getTrigger(unsigned obj_idx) { try { return(dynamic_cast(getObject(obj_idx, ObjectType::Trigger))); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Rule *View::getRule(unsigned obj_idx) { try { return(dynamic_cast(getObject(obj_idx, ObjectType::Rule))); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Index *View::getIndex(unsigned obj_idx) { try { return(dynamic_cast(getObject(obj_idx, ObjectType::Index))); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } unsigned View::getObjectCount(ObjectType obj_type, bool) { vector *obj_list = getObjectList(obj_type); return(!obj_list ? 0 : obj_list->size()); } unsigned View::getTriggerCount(void) { return(triggers.size()); } unsigned View::getRuleCount(void) { return(rules.size()); } unsigned View::getIndexCount() { return(indexes.size()); } vector *View::getObjectList(ObjectType obj_type) { if(obj_type==ObjectType::Trigger) return(&triggers); if(obj_type==ObjectType::Rule) return(&rules); if(obj_type==ObjectType::Index) return(&indexes); return(nullptr); } void View::removeObjects(void) { while(!triggers.empty()) { triggers.back()->setParentTable(nullptr); triggers.pop_back(); } while(!rules.empty()) { rules.back()->setParentTable(nullptr); rules.pop_back(); } while(!indexes.empty()) { indexes.back()->setParentTable(nullptr); indexes.pop_back(); } } void View::operator = (View &view) { QString prev_name = this->getName(true); (*dynamic_cast(this))=reinterpret_cast(view); this->pagination_enabled = view.pagination_enabled; this->layer = view.layer; this->references=view.references; this->exp_select=view.exp_select; this->exp_from=view.exp_from; this->exp_where=view.exp_where; this->cte_expression=view.cte_expression; this->materialized=view.materialized; this->recursive=view.recursive; this->with_no_data=view.with_no_data; PgSqlType::renameUserType(prev_name, this, this->getName(true)); } vector View::getObjects(const vector &excl_types) { vector list; vector types={ ObjectType::Trigger, ObjectType::Index, ObjectType::Rule }; for(auto type : types) { if(std::find(excl_types.begin(), excl_types.end(), type) != excl_types.end()) continue; list.insert(list.end(), getObjectList(type)->begin(), getObjectList(type)->end()) ; } return(list); } QString View::getDataDictionary(bool splitted, attribs_map extra_attribs) { attribs_map attribs, aux_attrs; QStringList tab_names, col_names; QString dict_files_root = GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::DataDictSchemaDir + GlobalAttributes::DirSeparator, view_dict_file = dict_files_root + getSchemaName() + GlobalAttributes::SchemaExt, col_dict_file = dict_files_root + Attributes::Column + GlobalAttributes::SchemaExt, link_dict_file = dict_files_root + Attributes::Link + GlobalAttributes::SchemaExt; attribs.insert(extra_attribs.begin(), extra_attribs.end()); attribs[Attributes::Type] = getTypeName(); attribs[Attributes::TypeClass] = getSchemaName(); attribs[Attributes::Splitted] = splitted ? Attributes::True : QString(); attribs[Attributes::Name] = obj_name; attribs[Attributes::Schema] = schema ? schema->getName() : QString(); attribs[Attributes::Comment] = comment; attribs[Attributes::Columns] = QString(); aux_attrs[Attributes::Splitted] = attribs[Attributes::Splitted]; for(auto &ref : references) { if(ref.getTable()) { aux_attrs[Attributes::Name] = ref.getTable()->getSignature().remove(QChar('"')); tab_names.push_back(schparser.getCodeDefinition(link_dict_file, aux_attrs)); } for(auto &tab : ref.getReferencedTables()) { aux_attrs[Attributes::Name] = tab->getSignature().remove(QChar('"')); tab_names.push_back(schparser.getCodeDefinition(link_dict_file, aux_attrs)); } } tab_names.removeDuplicates(); attribs[Attributes::References] = tab_names.join(", "); aux_attrs.clear(); for(auto &col : columns) { aux_attrs[Attributes::Parent] = getSchemaName(); aux_attrs[Attributes::Name] = col.name; aux_attrs[Attributes::Type] = col.type; schparser.ignoreUnkownAttributes(true); attribs[Attributes::Columns] += schparser.getCodeDefinition(col_dict_file, aux_attrs); aux_attrs.clear(); } schparser.ignoreEmptyAttributes(true); return(schparser.getCodeDefinition(view_dict_file, attribs)); } pgmodeler-0.9.2/libpgmodeler/src/view.h000066400000000000000000000223751360462764600201060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \brief Implements the operations to manipulate views on database. \note Creation date: 07/04/2008 */ #ifndef VIEW_H #define VIEW_H #include "reference.h" #include "basetable.h" class View: public BaseTable { private: //! \brief Stores the references to expressions and objects vector references; /*! \brief Vectors that stores indexes to the view references in each SQL part: SELECT-FROM, FROM-WHERE, after WHERE, expressions at the very end of definition (e.g. group by) */ vector exp_select, exp_from, exp_where, exp_end; vector triggers; vector rules; vector indexes; vector columns; /*! \brief Commom table expression. This is prepend on the views definition. CTE's are available since PostgreSQL 8.4: > http://www.postgresql.org/docs/8.4/interactive/queries-with.html */ QString cte_expression; //! \brief Indicates that the view is a materialized one. This setting is auto exclusive with 'recursive' bool materialized, //! \brief Indicates that the materialized view should not be initialized at creation time (default=false) with_no_data, //! \brief Indicates that the view is a a recursive one. This setting is auto exclusive with 'materialized' recursive; //! \brief Sets the definition attribute used by the SchemaParser void setDefinitionAttribute(void); //! \brief Sets the references attribute used by the SchemaParser void setReferencesAttribute(void); /*! \brief Returns the reference index on the view. When it doesn't exists, the method returns -1 */ int getReferenceIndex(Reference &refer); //! \brief Returns the reference to internal expression list according to the SQL expression type vector *getExpressionList(unsigned sql_type); void setSQLObjectAttribute(void); //! \brief Returns a unique name for a columns comparing it to the existent columns. In case of duplication the name receives a suffix QString getUniqueColumnName(const QString &name); public: View(void); ~View(void); void setName(const QString &name); void setSchema(BaseObject *schema); void setProtected(bool value); void setMaterialized(bool value); void setRecursive(bool value); void setWithNoData(bool value); bool isMaterialized(void); bool isRecursive(void); bool isWithNoData(void); /*! \brief Adds a reference to the view specifying the SQL expression type for it (refer to class Reference::SQL_??? constants). The 'expr_id' parameter is the index where the reference must be inserted. By defaul the method always adds new references at the end of the list */ void addReference(Reference &refer, unsigned sql_type, int expr_id=-1); /*! \brief Adds a trigger or rule into the view. If the index is specified ( obj_idx >= 0) inserts the object at the position */ void addObject(BaseObject *obj, int obj_idx=-1); //! \brief Adds a trigger into the view void addTrigger(Trigger *trig, int obj_idx=-1); //! \brief Adds a rule into the view void addRule(Rule *rule, int obj_idx=-1); //! \brief Adds an index into the view void addIndex(Index *index, int obj_idx=-1); //! \brief Remove a object from view using its reference void removeObject(BaseObject *obj); //! \brief Removes the object using the index and type void removeObject(unsigned obj_idx, ObjectType obj_type); //! \brief Removes the object using the name and type void removeObject(const QString &name, ObjectType obj_type); //! \brief Remove a trigger from view using its index void removeTrigger(unsigned idx); //! \brief Remove a rule from view using its index void removeRule(unsigned idx); //! \brief Remove an index from view using its index void removeIndex(unsigned idx); //! \brief Returns the object index searching by its reference int getObjectIndex(BaseObject *obj); //! \brief Returns the object index searching by its index and type int getObjectIndex(const QString &name, ObjectType obj_type); //! \brief Returns the children objects of the view excluding the provided children types (does not include references) vector getObjects(const vector &excl_types = {}); //! \brief Returns the view's child object using its index and type TableObject *getObject(unsigned obj_idx, ObjectType obj_type); //! \brief Returns the view's child object using its name and type TableObject *getObject(const QString &name, ObjectType obj_type); //! \brief Returns a trigger searching by its index Trigger *getTrigger(unsigned obj_idx); //! \brief Returns a rule searching by its index Rule *getRule(unsigned obj_idx); //! \brief Returns a index searching by its index Index *getIndex(unsigned obj_idx); //! \brief Returns the view's child object count unsigned getObjectCount(ObjectType obj_type, bool=false); //! \brief Returns the view's trigger count unsigned getTriggerCount(void); //! \brief Returns the view's rule count unsigned getRuleCount(void); //! \brief Returns the view's index count unsigned getIndexCount(void); //! \brief Removes all objects (triggers / roles) from view void removeObjects(void); //! \brief Returns the object list according to specified type vector *getObjectList(ObjectType obj_type); //! \brief Sets the commom table expression for the view void setCommomTableExpression(const QString &expr); /*! \brief Remove the reference from the view using its index, removing all the elements from the exp_??? vectors when they make use of the deleted reference. */ void removeReference(unsigned ref_id); //! \brief Removes all the references from the view void removeReferences(void); //! \brief Removes an element from the expression list specified by the 'sql_type' parameter void removeReference(unsigned expr_id, unsigned sql_type); //! \brief Returns the commom table expression QString getCommomTableExpression(void); //! \brief Returns the reference count from view unsigned getReferenceCount(void); /*! \brief Returns the element count on the specified SQL expression type list (sql_type). It possible to filter the reference type via 'ref_type' which must be filled with the Reference::REFER_??? constants */ unsigned getReferenceCount(unsigned sql_type, int ref_type=-1); //! \brief Returs one reference using its index Reference getReference(unsigned ref_id); /*! \brief Retuns one reference in the specified position (ref_id) on the specified expression list (sql_type) */ Reference getReference(unsigned ref_id, unsigned sql_type); //! \brief Returns the specified reference index on the specified expression list int getReferenceIndex(Reference &ref, unsigned sql_type); //! \brief Returns the SQL / XML definition for the view virtual QString getCodeDefinition(unsigned def_type) final; virtual QString getDropDefinition(bool cascade) final; /*! \brief Returns whether the view references columns added by relationship. This method is used as auxiliary to control which view reference columns added by the relationship in order to avoid referece breaking due constants connections and disconnections of relationships */ bool isReferRelationshipAddedColumn(void); /*! \brief Returns the list of all columns that is created by relationships. This method is slower than isReferRelationshipAddedColumn() so it's not recommended to use it only check if the object is referencing columns added by relationship */ vector getRelationshipAddedColumns(void); //! \brief Returns if the view is referencing the specified table bool isReferencingTable(PhysicalTable *tab); //! \brief Returns if the view is referencing the specified column bool isReferencingColumn(Column *col); //! \brief Returns if the view has an reference expression that is used as view definition bool hasDefinitionExpression(void); void setObjectListsCapacity(unsigned capacity); unsigned getMaxObjectCount(void); /*! \brief Returns a list of deduced names for view's colums (useful for recursive views). * The names are retrieved, first, from columns aliases and lastly from table's columns * when TABLE.* syntax is used. For expressions, if aliases aren't defined, a column name in the * for _expr#_ is used. */ void generateColumns(void); //! \brief Returns the deduced columns of the view vector getColumns(void); virtual QString getDataDictionary(bool splitted, attribs_map extra_attribs = {}); //! \brief Copy the attributes between two views void operator = (View &visao); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/000077500000000000000000000000001360462764600166605ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/libpgmodeler_ui.pro000066400000000000000000000245011360462764600225460ustar00rootroot00000000000000# libpgmodeler_ui.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = lib TARGET = pgmodeler_ui RESOURCES += res/resources.qrc windows:RCC_DIR += src windows:DESTDIR = $$PWD SOURCES += src/mainwindow.cpp \ src/modelwidget.cpp \ src/messagebox.cpp \ src/textboxwidget.cpp \ src/baseobjectwidget.cpp \ src/operationlistwidget.cpp \ src/modelobjectswidget.cpp \ src/baseform.cpp \ src/sourcecodewidget.cpp \ src/syntaxhighlighter.cpp \ src/databasewidget.cpp \ src/schemawidget.cpp \ src/rolewidget.cpp \ src/permissionwidget.cpp \ src/tablespacewidget.cpp \ src/languagewidget.cpp \ src/objectselectorwidget.cpp \ src/functionwidget.cpp \ src/pgsqltypewidget.cpp \ src/parameterwidget.cpp \ src/castwidget.cpp \ src/conversionwidget.cpp \ src/domainwidget.cpp \ src/aggregatewidget.cpp \ src/sequencewidget.cpp \ src/operatorwidget.cpp \ src/operatorfamilywidget.cpp \ src/operatorclasswidget.cpp \ src/typewidget.cpp \ src/viewwidget.cpp \ src/columnwidget.cpp \ src/constraintwidget.cpp \ src/rulewidget.cpp \ src/triggerwidget.cpp \ src/indexwidget.cpp \ src/relationshipwidget.cpp \ src/tablewidget.cpp \ src/taskprogresswidget.cpp \ src/objectdepsrefswidget.cpp \ src/generalconfigwidget.cpp \ src/appearanceconfigwidget.cpp \ src/connectionsconfigwidget.cpp \ src/configurationform.cpp \ src/baseconfigwidget.cpp \ src/modelexportform.cpp \ src/modeloverviewwidget.cpp \ src/modelrestorationform.cpp \ src/objectrenamewidget.cpp \ src/pgmodelerplugin.cpp \ src/pluginsconfigwidget.cpp \ src/collationwidget.cpp \ src/modelexporthelper.cpp \ src/modelvalidationwidget.cpp \ src/modelvalidationhelper.cpp \ src/validationinfo.cpp \ src/extensionwidget.cpp \ src/objectfinderwidget.cpp \ src/databaseimporthelper.cpp \ src/databaseimportform.cpp \ src/codecompletionwidget.cpp \ src/swapobjectsidswidget.cpp \ src/sqltoolwidget.cpp \ src/tagwidget.cpp \ src/modelfixform.cpp \ src/updatenotifierwidget.cpp \ src/newobjectoverlaywidget.cpp \ src/eventtriggerwidget.cpp \ src/aboutwidget.cpp \ src/colorpickerwidget.cpp \ src/modelnavigationwidget.cpp \ src/relationshipconfigwidget.cpp \ src/datamanipulationform.cpp \ src/customsqlwidget.cpp \ src/findreplacewidget.cpp \ src/modeldatabasediffform.cpp \ src/modelsdiffhelper.cpp \ src/objectsdiffinfo.cpp \ src/hinttextwidget.cpp \ src/databaseexplorerwidget.cpp \ src/snippetsconfigwidget.cpp \ src/pgmodeleruins.cpp \ src/bugreportform.cpp \ src/sqlexecutionwidget.cpp \ src/htmlitemdelegate.cpp \ src/donatewidget.cpp \ src/numberedtexteditor.cpp \ src/linenumberswidget.cpp \ src/metadatahandlingform.cpp \ src/welcomewidget.cpp \ src/tabledatawidget.cpp \ src/plaintextitemdelegate.cpp \ src/csvloadwidget.cpp \ src/genericsqlwidget.cpp \ src/sceneinfowidget.cpp \ src/bulkdataeditwidget.cpp \ src/policywidget.cpp \ src/objectstablewidget.cpp \ src/resultsetmodel.cpp \ src/referencewidget.cpp \ src/sqlexecutionhelper.cpp \ src/elementstablewidget.cpp \ src/elementwidget.cpp \ src/layerswidget.cpp \ src/foreigndatawrapperwidget.cpp \ src/foreignserverwidget.cpp \ src/usermappingwidget.cpp HEADERS += src/mainwindow.h \ src/modelwidget.h \ src/messagebox.h \ src/baseobjectwidget.h \ src/textboxwidget.h \ src/operationlistwidget.h \ src/modelobjectswidget.h \ src/baseform.h \ src/sourcecodewidget.h \ src/syntaxhighlighter.h \ src/databasewidget.h \ src/schemawidget.h \ src/rolewidget.h \ src/permissionwidget.h \ src/tablespacewidget.h \ src/languagewidget.h \ src/objectselectorwidget.h \ src/functionwidget.h \ src/pgsqltypewidget.h \ src/parameterwidget.h \ src/castwidget.h \ src/conversionwidget.h \ src/domainwidget.h \ src/aggregatewidget.h \ src/sequencewidget.h \ src/operatorwidget.h \ src/operatorfamilywidget.h \ src/operatorclasswidget.h \ src/typewidget.h \ src/viewwidget.h \ src/columnwidget.h \ src/constraintwidget.h \ src/rulewidget.h \ src/triggerwidget.h \ src/indexwidget.h \ src/relationshipwidget.h \ src/tablewidget.h \ src/taskprogresswidget.h \ src/objectdepsrefswidget.h \ src/generalconfigwidget.h \ src/configurationform.h \ src/connectionsconfigwidget.h \ src/appearanceconfigwidget.h \ src/baseconfigwidget.h \ src/modelexportform.h \ src/pgmodelerplugin.h \ src/modeloverviewwidget.h \ src/modelrestorationform.h \ src/objectrenamewidget.h \ src/pluginsconfigwidget.h \ src/collationwidget.h \ src/modelexporthelper.h \ src/modelvalidationwidget.h \ src/modelvalidationhelper.h \ src/validationinfo.h \ src/extensionwidget.h \ src/objectfinderwidget.h \ src/databaseimporthelper.h \ src/databaseimportform.h \ src/codecompletionwidget.h \ src/swapobjectsidswidget.h \ src/sqltoolwidget.h \ src/tagwidget.h \ src/modelfixform.h \ src/updatenotifierwidget.h \ src/newobjectoverlaywidget.h \ src/eventtriggerwidget.h \ src/aboutwidget.h \ src/colorpickerwidget.h \ src/modelnavigationwidget.h \ src/relationshipconfigwidget.h \ src/datamanipulationform.h \ src/customsqlwidget.h \ src/findreplacewidget.h \ src/modeldatabasediffform.h \ src/modelsdiffhelper.h \ src/objectsdiffinfo.h \ src/hinttextwidget.h \ src/databaseexplorerwidget.h \ src/snippetsconfigwidget.h \ src/pgmodeleruins.h \ src/bugreportform.h \ src/sqlexecutionwidget.h \ src/htmlitemdelegate.h \ src/donatewidget.h \ src/numberedtexteditor.h \ src/linenumberswidget.h \ src/metadatahandlingform.h \ src/welcomewidget.h \ src/tabledatawidget.h \ src/plaintextitemdelegate.h \ src/csvloadwidget.h \ src/genericsqlwidget.h \ src/sceneinfowidget.h \ src/bulkdataeditwidget.h \ src/policywidget.h \ src/objectstablewidget.h \ src/resultsetmodel.h \ src/referencewidget.h \ src/sqlexecutionhelper.h \ src/elementstablewidget.h \ src/elementwidget.h \ src/layerswidget.h \ src/foreigndatawrapperwidget.h \ src/foreignserverwidget.h \ src/usermappingwidget.h FORMS += ui/mainwindow.ui \ ui/textboxwidget.ui \ ui/messagebox.ui \ ui/operationlistwidget.ui \ ui/modelobjectswidget.ui \ ui/baseform.ui \ ui/sourcecodewidget.ui \ ui/databasewidget.ui \ ui/baseobjectwidget.ui \ ui/rolewidget.ui \ ui/permissionwidget.ui \ ui/tablespacewidget.ui \ ui/languagewidget.ui \ ui/objectselectorwidget.ui \ ui/functionwidget.ui \ ui/pgsqltypewidget.ui \ ui/parameterwidget.ui \ ui/castwidget.ui \ ui/conversionwidget.ui \ ui/domainwidget.ui \ ui/aggregatewidget.ui \ ui/sequencewidget.ui \ ui/operatorwidget.ui \ ui/operatorfamilywidget.ui \ ui/operatorclasswidget.ui \ ui/typewidget.ui \ ui/viewwidget.ui \ ui/columnwidget.ui \ ui/constraintwidget.ui \ ui/rulewidget.ui \ ui/triggerwidget.ui \ ui/indexwidget.ui \ ui/relationshipwidget.ui \ ui/tablewidget.ui \ ui/taskprogresswidget.ui \ ui/objectdepsrefswidget.ui \ ui/modelexportform.ui \ ui/configurationform.ui \ ui/generalconfigwidget.ui \ ui/appearanceconfigwidget.ui \ ui/connectionsconfigwidget.ui \ ui/modeloverviewwidget.ui \ ui/modelrestorationform.ui \ ui/objectrenamewidget.ui \ ui/pluginsconfigwidget.ui \ ui/schemawidget.ui \ ui/collationwidget.ui \ ui/modelvalidationwidget.ui \ ui/extensionwidget.ui \ ui/objectfinderwidget.ui \ ui/databaseimportform.ui \ ui/swapobjectsidswidget.ui \ ui/sqltoolwidget.ui \ ui/tagwidget.ui \ ui/modelfixform.ui \ ui/updatenotifierwidget.ui \ ui/newobjectoverlaywidget.ui \ ui/eventtriggerwidget.ui \ ui/aboutwidget.ui \ ui/colorpickerwidget.ui \ ui/modelnavigationwidget.ui \ ui/relationshipconfigwidget.ui \ ui/datamanipulationform.ui \ ui/customsqlwidget.ui \ ui/findreplacewidget.ui \ ui/modeldatabasediffform.ui \ ui/hinttextwidget.ui \ ui/databaseexplorerwidget.ui \ ui/snippetsconfigwidget.ui \ ui/bugreportform.ui \ ui/sqlexecutionwidget.ui \ ui/donatewidget.ui \ ui/metadatahandlingform.ui \ ui/welcomewidget.ui \ ui/tabledatawidget.ui \ ui/csvloadwidget.ui \ ui/genericsqlwidget.ui \ ui/sceneinfowidget.ui \ ui/bulkdataeditwidget.ui \ ui/policywidget.ui \ ui/objectstablewidget.ui \ ui/referencewidget.ui \ ui/elementwidget.ui \ ui/layerswidget.ui \ ui/foreigndatawrapperwidget.ui \ ui/foreignserverwidget.ui \ ui/usermappingwidget.ui unix|windows: LIBS += -L$$OUT_PWD/../libobjrenderer/ -lobjrenderer \ -L$$OUT_PWD/../libpgconnector/ -lpgconnector \ -L$$OUT_PWD/../libpgmodeler/ -lpgmodeler \ -L$$OUT_PWD/../libparsers/ -lparsers \ -L$$OUT_PWD/../libutils/ -lutils INCLUDEPATH += $$PWD/../libobjrenderer/src \ $$PWD/../libpgconnector/src \ $$PWD/../libpgmodeler/src \ $$PWD/../libparsers/src \ $$PWD/../libutils/src DEPENDPATH += $$PWD/../libobjrenderer \ $$PWD/../libpgconnector \ $$PWD/../libpgmodeler \ $$PWD/../libparsers \ $$PWD/../libutils # Deployment settings target.path = $$PRIVATELIBDIR INSTALLS = target pgmodeler-0.9.2/libpgmodeler_ui/res/000077500000000000000000000000001360462764600174515ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/res/icones/000077500000000000000000000000001360462764600207315ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/res/icones/abrir.png000066400000000000000000000022301360462764600225330ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX=oE3w{90 V !SnZ:>@$>@JDhCH@ɊE(wޗ{:wrR(Kvvvy~<3" C^k_nܸ+~6ƼwBZÇ\@[J坛7oIZ 0?;wѣG+PJejtp-5!Gh,ĥKc֞ \̄jZ?<aTnH(sd<TZeDKȍE-n/D[ZT J>D%T/l,4> SzQJ  cѿBS^/| 6kd%5J_<^TR N R8ݝ;>3$!J WToV)iR $UziU*$AX;XhbggDbpdDC$v- xxQˡLgX?515k`mZt8)\ȍ1*Kky>:a[BH `|S@ 0 ,-27+IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/addcol.png000066400000000000000000000016271360462764600226730ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME;I$IDATXNJc]U0+xb'+ԬX)*! ةh}@ղ4)MOs8+u;50] VWW-\׵RaLNX[*Н\u3P@*(2y71P }"e |899O)󜃃DZ([QB3w*O4}2??_I5߀U#p]'q{8Y~fYv_u]6lO~NrJ |>9583JoZ~C ׉IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/adddata.png000066400000000000000000000020711360462764600230210ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME g`IDATXOhU?o&1v1B/7bJ@LO ŋ֣%@\"XI5Ym1;xevv&;yf-߇n,//u]wI)qc ZTJq{Ry؞ہHKbm{/|r[ZZ@kG֚a< "~@ZFGG~  i4;LkbJ /)>[lfk/<:m_uYѼEwЖvn|)}=ӯ>EpaĎ/0p'X~t++>ueִii` 2挡(,0V:Zۛ~ @`:&uk.Q3e9z/#9`#}/moU$z'?uO%<+-OYWn c_=4EN͘&, OFp'"ZJ4h` 8m1F:z;G.D$? Hâo}G^KD|^p3;!Xv0yIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/addrow.png000066400000000000000000000016311360462764600227200ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME2<&IDATXWN@v8 R9号^78\T\{ 5'}^x 9A8kJIAY:4g=o66899yyg؊8)%X׳%|wzz%Qݾ}xxPIdҲ8=>>Z6ݩt>7=!\<A1 _M' J):_$Ik>c QYs777ϧpé}[岞rmu?X ӔOMTZ0"qcV 4W*op]{{{zZMnZMẇHzѫ+$I~Y$lc Jc j鄥Rbqu8 C]_2!@߷4@՚(bu] 3M`*|0"Q1zV^W Lwi`ggGRi %P1\RB`kkk(&Lh,V0 9t&To2`nPJ= ihXi6:@?,8Bd2@ ɕR@v&Ԇjbqq'ZWSfI: \ 8fǀ|==vGG>={x7W~1j>,$jt mPcT&tlV%~~3# jiw] (0[@ 4w$H^wIH|4N rZc'2Se_T0/]X&΍-OV +0JOhC3o? WLvIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/aggregate.png000066400000000000000000000047131360462764600233720ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs : :dJtIME.ǹQ KIDATXýW{tݹ3Wy@ B5FV *9X}j֣G[xN * LxEy`I6dw#K?:|gν~|^8kcrdmue9x| {%ZsH9nWSa"'hkt @aI>Mܲt J7G@ D* [xyie:EK_\fS k0O k9Xj}0xJd3b\ڤ}m-guI3o7o~}z~9.3WgՃIV#BEi'ML֙n0|!HN0A/57vvtYĖ>o]s'l~tCdP`i Y P~YB{!dTxJo`^2K0hDx=t:+^]q$3?%Wr$Ut[LCʅ"O!R (B##cB,tdDEggWwSg̔Q c#90D~Uy7H㇫^V%P]Y.Oyy, @{H"%ф#G5TEpy7e[Nu%! {* JiSo4xhhFtl߾ŵ|l>D#[=ޭ7,\ (lFN3>β`p cՕHFGaO4;ɚ&qDUU`kv{w7xuk?( ^`() y^zw{B}C o݃7ɜPBV LNO}Wsk Mgȱ%'hTAGg?apldG@i#8A@S\ר=ۉ@ VPGrܷ D Lehs0@x$&d,"*ޮy{yf8U:_w4hܲNaʊ}{ 9Y&Uez iP{n`)+qHCwZ=d9 ` Ƌ:y|m+Jo!⻖45 $l[okַlĴPUF t{|$Rjy,,cBdBCO_>J4Cp82Z\(˷Z!60J|!Z-گk"HlY7+ӶgHommGhy.+T&ə|i￵ u;+{+o<1^t>Zl⢟>`˞;Ϛ =vmYpL۳WP'_cM۱8pxLȗ,0@NSYKn`^%v:?yY"5` gMѰ ho+SΝ9p j `b^b4Sknic b,GDHxS<e^7\Q-u_} 1Ǿ˹tx pS@ics_}ٶJIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/aggregate_grp.png000066400000000000000000000047151360462764600242440ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs : :dJtIME 9l; MIDATXí}TTuǿ{3wf`@ayyPIZ-=Vn"MmۭYm530üCk級}zs}5鹥; #o-17_ĥ>3/9 8噱 E[PԬdfAZY[NQ 7y.ߦߠw=s/& 41u<Xj묒` ssл?Yүӗ_[]pHd3o꧑~HRg]P17T&~ug|}U,WZZXG' i3I&I8bFƧmK,q"f.5 ;@WTRƞ}ozi^Dz[V2'gRXĂ!n70qKitSƎKtV%F?:'##y@ߠ'4P&  ^K8%-\iRT[ƤDgMmtaLj{cJïGcǁ%BFBxݲov̆"u+cKJ'Lpտ_OOT.HKJNBH9>qGk+.;/ sU[I{j~\!rw[vn_/޼jeIqP+xts۾n&Cc6Ȁ)lӖ+MWH]s͗/۔ $\",1߷/p ۱Hx@ym`Xx&"i P/`QSk&,"(Ivp0yZWŞ2uiVV ۺ&k BXJ=#.`ŸS:OsJcW.Ƥ'$,aQFAZjlqgw~txDIVj՘9K:ĖCLC]-)9/Z,X1ը{ZMBf*1,c8{In^<'yIg cPW ;mRʦ&ea O/Ξ@ -YBCzZC0C YT{txHX8 j)Y QͅClv7&FŸ܈6cnnݻH!.৑3HTXf?yܖ˖r`B"fA'zo8|x_v22mFo@*!`;D)yx[;uE%e, 8ňyݧ5Vﳻכ\k392 ihVͅ _̟e9R͊R)3|*H<\8֣e*z LXx$!a!CFA~wLOiNu5PѼG+Y] `5nfNq0 S F.{Hνr9O1t*1:c3/\3PG-_Ǘ6Epެg mz剙V|Vdk&)%CSYY%]7ifj8v-_kx-a(eԏbrbh2y)Xnu~>~ꣳ AO9b驣Pر Rdxxན'~vt6sQn:;&. o93UZsC##շ`Pzf8V^RmSnkNTBBbw4}ɩ/*YֲJuLC}; uG3V6+:TJ/v "0؍ګګۖJ{NGl#h0 t3&/!42B'U~34 ?Ejz4>.X  K'VŹEhjxѧpLcMq /S3f'ưM¤&Go '_UccChh#Wk|#7n-@Gfu|C[D𨩌+ы_wPN| @TxDJRGvymP4PPPKyEˊб}k7Z{PMAi,%y,Y[%j' e^ֿtۧV{֮9MwIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/aligntogrid.png000066400000000000000000000023671360462764600237520ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME9&z !iTXtCommentCreated with The GIMPmWIDATXí_hUswvfwId3nFBF[})`@E!5d "蓐?EѐnRmԤyQFX%-%Vd2wdwR2w{=3^ka؄aQa %>MM)""1WϜ,#8P`ii)<2:;vg[YYlU*9K+/~: 1ز͋Ҙ a|)rY'g 99<x_HVHŅ<;Ӷ3= 0]]5jg*ZU,U䫳#+'HOĉU|[QM^|z3 cz^9sY^5 rnMMM\VbMӤJsr lY^5#\KtZ.}9\>لb989Qbw={Bˉx{$_dV,m,Pm{;/rNfD{^QJT֦^j2uڼ^+삸7bYRbs7bZ;Y⡏n`ӡ)%y2j"E.@H zvnwnK639̙5} *@ ~7gIn+ X/f `ΝH$r4n"Dt%%"B @GG&~ݺuϦ幘ơ-f]58Q3;IىQ`4@:ac~7yS8nqU@ŐMF' uEi({CI.֚=WՁksh;WZ@)ݰm_姽2`Wj";?<3I$|0NtfF3E|r"ǰ4n䓓_r4?dfW?[0no;R&{[Lg uԔ/f*wZpg8uc׏3:ӟb)W6g-Gь:޸B[U: z &}d||><1k`MAPj/6L]lC68p/o)/LBfr;LSt%ՁE=]Ցzm*|3+ysGce=M+s4e3(}QgM*XrO('ƌkcMY=p'5z2"_pKc_?+@]λ+$} eA `V,DR \}:hXf^?߲HkKMs"[07K 2]P,3]ǹص\ц!Z.5j1D2*fXb.~GH|>9LH/z T\Ts0ñ5ldLɔbɼEV)"knl_.m|p͜J lnn>DZkcO;k$ٓg 1`ٞHHV?t?SJi@'>ূͩ(x`wx֌Igc:d:P@ FQ=%`Q8P6Yѳ[=]IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/anterior.png000066400000000000000000000030311360462764600232570ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATXŗ{LWƿsgveA "*hwQblV@*VjĤ6U4M6!j,&5ab+V(-D%ݙ{;dv]*ZjOrr'7w;sg?H[st$"GZg[$6?D13f>hiŪ*'DK$)b>&!8/!Xg/pPDg.r)8\d@-UF5~m& e]p:cr>lH`qʦM[0%&u?v;j!@U xRh.^"䇄M;JTYU9ܼ:*K!:s$vv???ؼD&nݭCx8}i}ʿ95KM3r 荬,AM]=TVQw .;@bK~ˌD,]BЄs+BB sm,4-c!0mDr=Ə 6:wn.,pY*Ax-"jbfXYG#rc`䪁e (61) -%+Ŭ \y N EndAdF02d@H ~&<Uh z8$U:fJjaJIY $L17 %4=vh/vmUKKoȞ@CDp;}[xRRb2Mje*~Gk{3j/ UW?3RS1uWQ~2ZZ)) z.`(W?𰘿h-KIIC-nAKh~0b5Se8E/ X]X~+w [\x9k씹FF]U\Bcs@OSˀ{iZ{' [{sΜ2Դy<17kP%44xs6 \u]Mg}ذX\1ظ"˳1zT,0DB%b k#i9kT23(}a>K~}C~(ęC -R's5Wuh?@kt86ֵ\=?Wo|*DgW>k`zF͵z_d3c`\6+{5 -(!OhCOai}_Ȅ 0j"ԶKc] +Z.Оݢ/\#T)c~MϏS"[5ẍ́+jw Zz³8OnЛ8,+WIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/aparencia.png000066400000000000000000000027721360462764600233720ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATXŗOl[I?~~OR;b$lUmZEpX8ą 7qAD{q@*t*ҥt+g[otNR{{Yih|g~3o i ~M;HqDէPsC,Z(H%ll4{SM]FK1_:;[o0{mJeVJGy_rRj5zsȗR|Qs nѰc@5[%A4@>a-ɉQ36={{xu)dxr@Hemgs /GT /i*qanYrȁu4(>b)h_OZzAԊq+DS J +i6G^ϳ\! m=?pxK¥7#,\rj=JIB+j Azm#Bm; $,1*'p]RJ|_51M~T/RUi###y"RJ:N(B&ѣEΤJ6UM Mk8--a" s5ԻRJA4McffVť?^&R.o`YQJFh4F)^fau#\ʕuP$E4\uB}ЭT֮pq])%l)%կ9i!eUoujہcG458k۱pX!յ5>7CQ"w'q\cY^8<7b9s>PA۞5qC*$H`;6a-D?oI/ 3P}w.C8y^_tr :X{+^zRh>&{8kL&v ](Tmv= $`I]SD  O1"NHPPȑ uNT*lA$~Ƿ7~+/߾o|^3gϜfzz#_ E%~_~\߹|`hWvv*x]vIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/arrangetables.png000066400000000000000000000020661360462764600242550ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 00'IDATXíVoEf=M ؇(1qP\@$.+U[q@Ҟ!4D "ABRǵ؂Nq xM3Oiv4|KwsnRQ!Aފd❷s!h@A]Tigq aRO!bc.x쒱.,fBj!_57/brLO(c m `3W ÍqF=(18#4;f4Sq#WRs9rg('@4t* dh8ЁX,4 ህ(V#(_Coo/ = 0ƚ;*Ԍ>{eqX{\y(a6\3M5l\hV0gu]|r]VW(׻P(T2 0=s\6UUf4sssX^^Ts DQ~BjFpjFDT'yIaS:q~7So~.`3"LA4 9=GqԀ 'b=MNAh\/@ӹvG%F1==#i 0666D2 *ҩ8^PǞ`hAҩ8QX[[COO677M:;s֝  I~@Zw~L %Z_(QT`6dZ DN,.&) $(觧=æCԕ,6eQLl;,}N-6,Frޮ< W SF3hTlooWMtBhW."C:u.{8.=EH: e_Q:GOIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/attribute.png000066400000000000000000000022431360462764600234430ustar00rootroot00000000000000PNG  IHDR szzjIDATxڵOlUǿ;Tl411 `HLqIK. [8!]kn4YƔhL4b4@Rݝͬ23;cK^73~@z8JHo4l@A(ech4]ɻxew6?dw7B0ĬyC0{(E:xy{#:P>y4ozca8bګL{%@$U(N8e t{Pc4'Q.bc`X˥pn .G`훙TGP B\I~"ʇ Q:ʩl)VA]oZapW^ځQ{Kî}kT0, v Dc*` t~ Ab ̟jOT#hO?d*P$-0} aQlƖ΀Ju= :B0)T洆z) =on9\3'_1n2KV+۩uY|Wi pץ(C*m,b( 3Й/M47T 鶳M5渞-h Ի|IK5p9A$nfANŃi. vNT@B/0W@a|[ $Ԭ x 2`,[ 5a\2@pG.OK.n;JQW.|AKk]|V>? @aX"@<`<`u-@ʀ' F0r(`Ns&g~j ,PCN"'øk3?|A`U'"Vx~qȀP` Yoe e1 87 U,X q: t&f}={lc18%6'i [6prфn\gX-& IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/atualizar.png000066400000000000000000000037501360462764600234400ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATXŗilT޷q ij,\5(%%QBZ〚㦊RRPFE,iIҪ qC Mc xggz7͹;w= 66O7.(;U8[9sX n#u13mǷ[SZ[[Č5~0-ݰXtM#%Lp@`ʽ|s }?EAӢ߷xSt ~]U..eD$IK)s~3@ }Cn#e!XƇE]70-m]=kad^@ q$ %A )$|t}p&_[7U8y^e].jx:0+KrKdaX!P lWr$HlI0m3=6Yͬx)w|e"y`D8S'<&"F: &x\H"خBMb߉)ronmܸ(ۋo2'q>BI˝ vq3kwRgp͖:/177 @M 0f4Iv p*/>, N]YQUmk[cO2idmxmtF.i_pjH$w0XBL }f7{G 9w> kʷ uGkª8eME"9.^%8c_GO, %F,F%Y"/uvj}#_ TGѴPw枹Ա /S֤w?ڌ""/Ep UhP{'dt!qvKA hX~ɚ.q nIoK[6`{Cۉg:9@{@ݘ&n?s퍽ͅ{QZȒEJ)eii cp$`6҆d2&cmf}_y5n̓@r{Q8{s)*[ee5zQٗB 9*׈}8t\?Y 篆L*j~w;8l"1XN~aAX`l#BL ?َ.S!F=HA^UK /x!Nѻ$k >_=ˆm2svIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/baixo.png000066400000000000000000000022771360462764600225510ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<QIDATX]LUgfv D[4VIHLH%MԄFkjԘn1Q*%F`RcҤ!@"X mJGwνLJef|p7'Ν;瞹wѶU`xtwWjѪc ugTV@*,XʄT4M^a=@8 d B2CH9ٸ^Dk=%df0EPY3v.Ki)a_y΁w0g:MY.{8N@AYN6 RYX5CI^nx^j]SS~W^(>cVP,XY h K]Aci@YɮVͺ:=v_n )ͮUGgV6Q4 ""HlQ2` daRd?XXN\kNJwV0zGW8t ,Hlb9> tn}aw~BGtK.Z{/6gER0I0I(_c>-q#c_!h,Z/M _~ IF`" _*;H$Y@Ox?wG*t9D5Xea\_l3/m)34"t|~,9 0! W]둫7NY[=֭.\{lg-H'F g)ȏ?hv9؋_ ͫSV "x WY@I19ZhNy_a ~\&3RiHMxMN}Wj~ 9"V\Ŝ .q b [֎VK`&DK\w,fDIuRN_8}3u92րTZHL3ErS$K]~sU~IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/bloqobjeto.png000066400000000000000000000020601360462764600235750ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME a IDATXŗKlTeν3aZH>3Դj>V,!Ƹs ]…1MD!_I ->G<:E;K|=#爪˵aő( 0STju6L(@D`\&N89v:vWS|~]N:ruQ/v%QCr9r.qsag,-v$ٳ,Ủi֩*AU Ê{5gA2٤֟%T|?{myL0 CA`)cU*d.pg>wgƴGh j )oFE!ߏbY>NSTj[ywR+U5/.1F|cC6h s/UShat E&,܋Z@U`+t\T4l(,d rQR`9IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/bloqtodosobjetos.png000066400000000000000000000030101360462764600250250ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME +IDATXí_lEǿ3{wj˟JDbl F"*@c{_CS4>bbHox `P"M?K - \^۝v\I&;;3>3'ȑ&#p`׾3 & ɪHx# *X*ܸ7lJWhd `@isӚսe ɊYx& D`\k1szJ8NP(p5o-,ÙR>/INI)|XMn͘pOPr4BL%yYԐvʓom\ 5sy> &PSQhXF|Qԉ 29*cfq09\FQ)"9e g?28֡C}$B@"4>Q yAT`t:6գ}CJ##PY>>/sιc4 ?@U38K`pN!8Hd&BD܇EСeC@nPUZHL**ԙTKJ}hݹ.#S\)CJ8`Y$xi:J\ m{m3O ?D"D"0 O)#<=(-E1반χ\ }}}t*J(rP)( R8C|c'N񢲢 |_m@D PGGG JBJT:w~!9.+:IqjUt:4ﷱ.>y%%%===k~c Z(* ::: !Jyt`pp7R7p9~11X\@]l:;;MMM4hiiQ(ftݺJ)TMElnऄ_U H;$hCC |>_ Þ ;7ϗ.OogR54 Nl܌nX g=  %BO1'֩*nGݛ؈.bhhȦ o:A,zQiCF"EŐb0/^cc5.=z׮]CWWC@ݞ=5j]u8ؽ{7 ?~F0N#N}Q6lnZ}躆:BB t눨 i}dhhhFGGVi9'GPujy #A$pZOx~Rd] `u`&`6Ƕ?EuMu+ Os9L5k/}W!Vz/&jo˲*$ɶ*F\*1Vh- V7#j juu4vl @ Ѓs[ -{Os*v`ӹIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/breakline_290dv.png000066400000000000000000000015131360462764600243170ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs+tIME'M#IDATXOOAƟ3;u Hr'+pQk$P w `'Ѓ'7 M&p@k14nFl'dy~}_/L&5] ^HƞWƦiu]BjЦrnGGGp8 B 9牚eNT}`Mmmxr岏!jU˙P?>~ei?w BUUA0mPptSSν!~d"i` m΅LOO;G( 4 )\K8`gGehZLi @Ey4BT}KuWe74  b1gll EgPYF p bqr{g)DcFNa PRPB#PPBA(AyYGںbXW Xe %?%[H&SQs:(0 X R!@Jv [|F*¡-*x<*`l3`l,ZxW:qW@x-P%0?-5s^}[RDnGl֓H$*H$<9i'޽JO/# NeSSQ,JjCW5Mu|^ t]o`s&:}ͲT8s>IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/breakline_90dh.png000066400000000000000000000015031360462764600242160ustar00rootroot00000000000000PNG  IHDR! bKGD pHYs+tIME'(>IDATXKAMٚ` *{DJ mD`{B"5hCC*b/ڴF2=d=A!d7Yo>0ԪV V($$@$=xOJ j[xn}xai% ED"v; ._Q wvP. ߏ qp~z!]*C\. f4G4,DJ(\]"x z a#,!L wS , KL!B`L`#3ۃ71 #{"ɰYXB&mfRd~ |i, @D4 HN R"eaF%l|$JfffrU1 c,86GFF>'ĩ{vrͽe:T*f羷_ PwL [|~룣AS$ {yTUEu8U~7Y>~T0uŬm (@${{yTI~?4+VlOQZɻBLdx=5ij pxmyyƊ Jً̀j%HYWy|,h4Vgggdxx8s4eMt]wm-(VޮPcff7z|GiͭdeE%i#q@:BB-"?biii Y_)eViU@t-Y277y55uľ)j,+SiM A|n2;a;Ym D!x2~ޏ==PLqq1 e-5$[񮮮ȍkq%L",#I%Yݑ-x$iWWr!DY#A8̈>jE<`R!gDJYc8p"WxAСPxJHӍ_.KUkjqB2 z7< ,]?R4*kpĿ&'yՄq|Rx# Xt5B{NXZK366(0a6 7X,yj OnN5ޏY$[A Oдuy20`Yܮ]ٙYQOnz9ll N+L 077X\LWUU7NaRI$MwQBe~|X`0P勅9{ Ix`o뢲lKXro:/n~eGhxf}.Vܟ׎fr#!V! q)58ho;F[Nio~4?w/rS.'V5bWaۯ\v˯'L1%e1A(rDP "UTԢjQ:oII[o_݊sK|+{ЇPwMl>wKX¼c"E.Zk#gIo̵-[;=s/?9,d.A֊1clRբtEP-c2u|`?9pylZTA0낂 csPZΙAɾHOqQ@c S\F?'qH)GW hMP:@\@TQ'`A\TCr~:tl}*z{1K8[u2˃zEzӨk0F.} 9r}=h(!$ie4DB7ڽz!< @ܟDxrb \fCVwqĆ L:>ahAAT@b`e$QG<6 82$,*@@ntwx9YLyEZ2sv1j3dnUAt@ ަ:̿G`[n9bեnsxIbA/Se ;?w) ]]||=4ttp!B󇕌wMLkX4 <5P8YSLav%Pw\@^$E5BۆS^Vš-\2B8$$%} {I؎;xlLKP%A g!J6H`Nf]JR5Q?.ڏABShHYu'mpNȒIINKU*RS :iݿD쐏-#a6_K} $@H\}IbҘ mZ6crHh78s'T$aL\SNL:C@4m66*PAmr𽷹Y^AgOH>%_$$˟]ʍ {[sgӚ^j?-_2ջN$ΞP ' æ!Q#b>ܽ|o Ԕ*9])c ۼex+^:#æ][ۤpsam$*j'"1IpgwT帝I&5BDhnnzԨQw睊/96VgK zό?;ʆɄ{J)]sY3c СC,X0?LdHRꫜ8qb-[8X~9=)ze٨TmHZ>bxiMi_=}ؑee%~uS|׷?a3ë3gXkIk;~6/nY /#lnn>̘9˿jե&NMTTTƧN zV^pu]v֬Yl6K}}=֭c>7 $27n\.+wO<ڵkI&Zren޽֦6l0y wP@-`*VXl]]͛7-`00⬿tPXT0T(IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/browsetable.png000066400000000000000000000035211360462764600237510ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIMEDIDATXŗ[lTsnݵ5 م2qb" U"Cj)6*jP"S^$j<… =}}LaM1tD?Gu4p֭o>{xF yySq%h#|r{ߝWxvz$@)HlP(i|7C6au uNu>ۗ{UA~,RQ^^d6ˇ_$xaSaTR"̠:᠅B@ 6lvqa0x)H\)AJ @I2atttߚK;;ӎbږ'On0j?"!ˣ.n8#e1_:i*> mKg&<25r)#|~'TJy2`0H*"5w ɪҐ_(%qRJL bƑ|f0w^qE9d***@4ZwL038:pb4J)4Mojt͛W|J (DA,y2Ch \O2] ]\O??fbb˲Ǯ)%XL&͛7Fvn*{4g}xs܂̯ɤӧOc 'ǔݻwގmlv?[<66IUUN4̙3"[ uXSS{kQ^ b!G?D"2 9wRFEGSNmbqK!Ģ[-td2I.C)磴H$R+W؈q&&&(--ի{~y\f۶y+FGG2,mfP0]5<B%I0\,8hho Bdhii ttt\Ŝ5+S4۷oXvmR*iH$۷oAn]=c7޴/MO_页`\de'?7 Μ%t2Fء5044$%%G'&0j q## < )%RJR(U1 ({hfB$`&=Q2 )%ZkLDJihBBkhhhdٲ|A3BJ.PPOMM ;w$))f o[B6Yz5˨!##u&-ÔRyfB6Ν뤵5cR'N@kMgg'PPVV(yJ!%-O?D^bljx}!|1y@0<4HBR{ wc[j/|מڄc)uVR8;x]iy̻c)΀uE)eN"\FǗ^LPg?})p.C1-)0qJ0dc׎7LzܑHVa à9V˗{BܳG,B!b(8bo8W.ws+6P{o~6Z WqѪD?Bh9fsm\<&^ǧ#l6B|kbW;a!Q2nY`/139.<=@0EEO.MU`Bq9}iyp BZ);;|0NA  Bz8>m drp\&vݘ픔6SE&-`C*֓mt=F x0 (a#˲Fue97/[24d^X Nd BYWs޷d i 'n'ţdDzJ*_6> +)  录9Le䁁jjj m载n7wQUuB[sf@bTU5x<æ߰|HٟuN.1QfL^,F %IЭV)$vii˳O>mc^j,iqX 9mje[[oWM눍 08CxB"ke4ȺJ>ɬs<~㑿x8Өر?= EI6PZ4K6xC/Jli>ÆgֈXw0;W87I dֲ3;\(**2,TTT #a/~:3UkK_W!w/OqNCK,1]L, =;6?vpe$Jw_iq)z~1Ȳn/[6e cr(Imi^נ SlœiI瓿F.hY Vl]G\ptO{\<{9+7Tk  {Xv#=dez?j @4v#žG*גi6.TA@Q 2.n*$ND6`JDQUU_@ kAݮ{YPd L&ʿ>e<IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/buscar.png000066400000000000000000000030451360462764600227200ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŗKl$jiK^BjRN\Km@Fo5\z(M'ǧ\|"`.H b*K,i)b|,e9p83o73BJ7i7^5MBH)R.RJIccchmݱߖh,@4~0O<ù_>-@4ofǮ벷whg b]|\E8(kAC-`]׉F0zbi-YH$'`t:(211dYal0Joo/\a_u}hW ltdc蚂PB@8qq.1'N`mmQH$1I1 :rzt9dZVn&D"7a=Ӣj֨eaYE]l_<"`YqFQC00J5WxW`mJ{6Gaz8KGDzٺ^0 m^ DE5H.A<)p|d2T*e}ea033PePU7npIeaa[nI&3T*גBziNirgj5*iRT(JE"###?sDUU.^8DkQ@VVV@ B!qRYyX}( ,--D"ȈB {@;T) mu/"Ty… /a]vowRAyD^I'_x_g(i cx!ZBҵ;>tF[KNfΙ}136:D f1/n4 O(o>0etwit`)Q[)[;%gRm￟cigG?o.( t-t5T˟u'JG~ad߾^2Ri{/Vq}jjio窾j[7@(cR{z&iX^nls?cɵ߾U>c&@(N~vJ%fs<5X*_nUGs̵uL>بi9Ķ D̑~-|fȚ ޱI-i^G;8UD;H,Ö q-@H7  qX8Vud6y" )'p1'0ovM-mݤ'UjMkF-V& 3:'ȰAVDAubkRW;݃< $@!:ݚ2Ӎ(j5 ^/.$zn0*nUU+z4y.ɓhY{g@^k: hwTXP1j4J!lXDV* r"@C%5 r~W !s!^q]q6!3]Dž7JD3CJ+!U(F]@Qͨ:.rM`߇sB @ )vMTF~^ eovߺeY?uS܂i$D__PX N;F,\ryMGܟ]t_/&gr[=X.ГnH˰do5SRRi<'G$ѬoB֦ ']Erta~]?L>'zFI3<]ob:,pX:puP `ipn4 .U_DJt@ORZK3 +,, PP m+0BQ]/=j;ԔI09{V$e+h<ffti&@*$3TCg^p;@Ni@L =nD ~ZW{!IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/cast.png000066400000000000000000000054061360462764600223760ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME8adtEXtCommentCreated with GIMPW aIDATXýWiTW^UuUot7Ȧ(PFDctmfIFM'1M11jeĸ(*;BR]Ή̙{={{wұp`6&ЎtK%Ҿφ-̱RkO{*"U_dsZ,Z;޾RXƬ#UfiQu T7upŌ5* /GyC$4G W>$qs}G:U{y޹v8ކ*$ 8\?n.&4): M(` yHyW09(WXj^Ŝ}R߱-|&itr_i^ý~:cS3ck_H7/j1Af>=fT4yK>8M26t,€m̺ w>L?süqߏƀvW=#F:)0+Ff qO~ĨQi KouۙBPtږT|7n%VUJ;'+va.x;BEC"W`SfJK $$]p?Cb㿮>-0L,_+NM]8ΚLVe"~PH 5Hҳè2EBw~>;}! )  >a@gκ+uFikm}ǯTs6]' &yvL%~0sM<@Yu Me/1qtgѵ"` MںjvφN(v5Yp-8\pzLlbvPW[k, 34_@/pڎS }6fBQ 9ϢL+NŪW:~/Ȁ1An卲*(|jRO'/ocx%B71"/(\?}F) H\6MGt "`kK6],q֣_Ysi޶O3-Ptֱ\ :Yr졄 <1$++z]!!Fe9-\LL3&.up{էi+Kzw^͙!$tXe(ȵ7:B.Uㇿ`F}_!##ZJCc߯w K`0Pu F_?$Ri 7V1N8Ɠʒ2F2H0.O.G[>yzb&.B'#SYinF&R~aV^('A-P~c+f|23%Iy'ct4s{,52ocFbZm 44FTUG0TQTD$LJ$|$4TԔ~?o*mŵ+ga`p* 2àW͎%5hnoBhFP?L[q= ζCp΀QY!ZIܰA )۱_P:1anFx]HJǣhԳڎw?Y⶝# ,x :Z܍3grMmx{O=a1zE̬؉,:qtU6+b-`!=2$lx=_2[ Tn~؀G6+k5؀GOF5S4j 2,kKLyDgn/|} lڼZ5y 3WMJb3\"‰/^."b2L}}2=VX %ut)6f⼪i?k0vt3 @$Iқx~ڌ?ɢrz9R?:A6Hp?8= > Nh$@%t9W%uأs>Azy~]gN|rKhT@qR;(,qҨٯEJZݔ>/J#"Gl͵Me)`σ^aRT.*Wqqww*g2gIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/cast_grp.png000066400000000000000000000045301360462764600232430ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME  atEXtCommentCreated with GIMPWIDATXíytTǿ7k&3̖BVBH&eK eGXrDkBтQ Ųc@D#kY 1Lf&3dޛwG@T8λ`.r ow~, -pCwP@mI!nvژk^Sxf=6{KG's: 2uvHCр&;kG-{l t܂ʆ99Sbz\<\xp!#qMr)=& ~5NY8P:Dra7/R1@b-ztM#3g|$O.JJؽWiWen/C"=W6|wG{sJФyǃuߪgtqk.kdb0%4"77**qyim'V*0<9oy:ڬjia9FC!a*ո=5 S &r^@`tez$&*L2\5^CՊH-$@l6}smxꏇ ݦ{z|pnv<4amSSqa#?=>m;ؽ4IgS6헍!ՙ Tmה Ӻ)uuvS? e~!Uvxy!Ɣ•7" .fO|`PI!q)gyc)aasѦLexb|H% 8E]qgw $J1DohWi y2lAD^& N M?CrT) ߼n5 =~?WrMr!:s( Ѓˈ 66^4(},Y SDI$4&$X^!׆5L 1Ji XNDkbҘt(A"Q\ODT9NvKYڠISW8}+rH@A깥 Gd8&*,e`o1хjnA<6<>ۤkcΩT$yG+2@ز|wJBGѳmqY]$Ta߷vFDYQ@ȬTzuR+\:ndhTjK,z(&'i--,HOeWPjq2u+@sӎk8/]<'[2gSa.qzCvt 120RlVKauuK&e̊~Tˆ|1:/W[vm^+$?gTpD'<£mFN^XQ<+ɰ +/̃1~bmI}cهqy=>$Wbmt|mmWʟm6$Dj16$;زb rcE®ue]θJˤEnvt ze9ůғj:\-GdggbB<͌qMJ6o;D>+Yv͂م߷U< @WL薜b`w~A/T'Ss=لߞ$叟C} @')sΜ @ZI)eB)yW9J'ISHX06*(i*IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/changeowner.png000066400000000000000000000046671360462764600237540ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME {@ DIDATXíkWyיw{3 qLpLbHJ7"Tq+_2 Y>!Ҵ$&Qdq⤾ݻݙyg9f@B8#0pvG-i2h(Zɘ=fbLG\  {|M[+E1*CiE`5өK^|/]ʥS{o5ϱRf("%(ô=fyeP86mVOJDRR*R rN:mw.crOXu]°K(ƒ=|K8U*5+IO;vOA2h"])%mH",Mcb\ TQq/uǿV;>#Ko,S N:a(4Mɲ c՘Dy`dI1*P8wSuۑoxOFq74zjMJ{C1S@.`凱u!T؎m>sX8O?Ƈ0UN7U^BFjiu]CH+.ֱKu젆n5ڸe[\y7ÎVvGsuFkV4Q !v镐Nay5s`tlayysfjTΣ.~zb0 `t?0A@8clׇqˡw)K1ݥµDR 贃d@Ut=1h{-XCܱ;Gk+Hi(m')ˤ2P*J:*Tѧ0.:j6)M+ظ6֚՝7V0FMe 6t4% ״1Y}UNژ]ezzfy~wl56 r\^:+.B)AʀwUk<4w7\}# ToIg $Mk/OI37gtG?vu[?쉏}bhfc=Wtl_|Wxn6߆,p(xʁe zWN~#[8N[dO>7ta\}jΛ3z\5Z Rī ~;C2)aya/q7{i*CN8~j2_Tq]+_ضcx,/j+^ؽU=Q% BԪ>ͥy{{o%WBzq@)G࣍! F-%=ngB.{a8u};(Murt Vv~&-noyeR#3XP~K7 f?xhR1X3X͛6A3 &'Ժ`,5hu9!J:x֚02siE9k@ɲm[&RfcSݨO,\Jίʹ{B1ƀDqc[L 0&JTQZ+pqd#[nNoq-"jl-WB#-S'n=!2Kcl7 Y_sF'l^VI-S*R(UMJ(Ņ=gC@ϯ/~ Np\};8$`L_ЌF]ҵYKkBp}%`GJƎb诉 ݼwdȔ&N5JgYL%g^jͼ}p^b?˫i( VZ`ZŧXZ|UB~*fo|K.]v02\W\[ 09Qs槗yQ`2RޣOL~fng[ !mOW]CC(?{/O^9RxßHu ;O==k ܴ봅;)bn4w=)_*6̼}W~[ -+3-rJ= .?_)vMf&Sl_rg>#0 .lU6LLtb&uk8--NCZ`ĚX~[{SnC:Ѹ=1g֝s "8 !-Xs״es쮉+PQk*]ʲ5'0idOGo#K{?t;JM?P^k/:c3U㿶ӝh5<?CقoNV\:<^1bkX,U-=k`^<&_=meunc ]_s_j:~n %+ }GJw4ڵ_VW/*:]N@U#QQcςg1J@E?{3 `(|~`%5ߐ N5!sHnax-]g\Xm[ۛgݶX玍5liY7hލ5;!1ؙ} $=m8 Q@*5PՁ ?\W~x0[f_p*tg TbAJ^7``PP{;#$䋑P+K_Ə$q\?GB;9wNah~ @ $FZaRKIh$Q:Eya&.] c)MalTfπ+PPoԆ1πg$sH>O m UIQ#:c  022i 4AzGj(VW_?T0R qP554Kgde2&l˂CD3CnPh'Ӵfg<9ioご|~IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/clearlayers.png000066400000000000000000000034701360462764600237510ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME -:k(IDATXkPT]]AME(hMAlLN&v4Τ^ҴN&f闘3:)+ƘbbqqpE]A 휷y{4S1$!aeY6% (ZJ'&9J^r gm>G+h eҴ$GJAXgB_GɊfDUT<B4 BkpWKiDGl3mH ?:\Qɝ nRĤh`RH@ !Ey)Qu}-}ʯvt,b jQa{e·JI62HD\qx0e:JtFokVÍJIxM_o?IH\ Q8̄.T`Z%Y*!YOD B ]11N${IHaWHqƳf/F8aqZ~[~WMDs(!0Eq-.cI~g JÚ@"ZEؼd]oql Gt2f,b|}=h07}:V8-M)a~Z}{7o0jg$Z`X1Ps~S~`3#u3/"K(l(f #Y(ǞVaw-M+B3zu{v5lyyA `}3=0>Oks4>MO!=*r1sӎWD"&\N<0 4[fOK.1_IU9VY: vy+@Iϟ)?6;Dt*eg'l:MW $ϊ#]U5`PܽF{Vj;ό~7lqv"Μdta e'TU~ *++JBeEZMDB],8O;ŁUY:uRZ6|>ǵb5 EQX`?%/\Lg|;s%,<]TS1f-6WZ~==C@-w,/© *#+wj\}"ȊmxoTa22619fm _\[fg,y0#JN v'8)f¡HZ+]]/k:æ|}ҿ,Pn-} o +`W3L%}>BD4WIO}tL?4G- Pc~^)  P˥v'Țe8ښZU;Kh豅1/OSeaק(d- 8.GfEJ$Lz}Ǧ ƖKoQL,9foA }[_$ص6͚!uxZw2kn2*כu6V 0W| {dcpsiF'mtջYh:*2QLF֋uyιQ8 g~㻪7l ni5A>Kt*j%?Y4mt<@Bc<.fRd,>TVlt? `hH7-Vˑnv~"IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/clearobjsel.png000066400000000000000000000025131360462764600237250ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIMEJu}IDATXýkhW%nM/6hDgitlb!]KdC tLTźnU,VtmmYS}s!y6YS8s9ϟ9$ʕ_~+j|b P HLEUcz\䔎tKB /,@z"PjJ«2_D|kA*J|c^\X|⦠EmR !!4Ӳ1M۶ASSq*R溜*L}NWgURǴDKgsR"@^4X)C(MdžW9 imlFIe`CO)mgo[y9%,]mYH$RBHg @>СC !J|&qcݬؼN_ںujbtm¶S \'ORZ_,wXQҁR8#p\`K MO ٓG}vWb1[[#3,7 xux@Ggv²,,lC._F 1q57?!4ˡC4TUM ضY]YÅF~jl w$l^/UUsYOQt)Kojft;Ǻ%m,@\^/}>GJ_MB0 䢣2G[77SOG\ )ڷ*EXjVEȓVdHR*$ZKd=LJMv}r2sܽ;9[o2<-rgH[ʺʱG@7'c #ϿP{. O^pwgΨI "G`R~EL;!dd7Whþ-" "x I޽E5(m 6* y y/)@"n,J"m)`68!:p]"B2t|vc<*# "ܺ mܸ9=1Z BK, SSS`6O;Pb>.C$|'jRV35eY vtZE۲-!'}7 X3VURr||\]Qnpe1wV$sf'|H 0 KQZRMk@VT:e>k {,/PSlq,Sxya~Z?o4J)*;6f jwkrԁv-a\~6 x4'=8{+?O7?yľ|I"IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/codigosql.png000066400000000000000000000030751360462764600234300ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME  !6~IDATXo\ϙ'㌓`C@@.BU% T")/hiS@TM%BHpi%cLq<Ď{fm/gc[::\oߛqرl> ,Bk1 sm=O°(_^LNcD.oxF)$߹ g9}MZi灮'0Qno]ЄÓob:tlv {`}4•|3k_0eYd2?ZjC`ҚuqiX~˧ZcMk!-0J) o{esεz{{]7,mL—a_4H"j}:lҚ\xo["ߜʗAV@d]}~lFߠ}{'؝hBDTgv>2?_[?=ᯎDx`Dlu ;A$* 4dk9xPsGDV@J `kµ $HO>2{ךzܹsUC&q0'0. 4JhM8y%J{+}pg zׇϡ^P6fAiLii槮2;O9 D5Oð_ONU0 ,4)HK" Uݍ6%PlvIH9`[F) eǁ2 ҲhTBZ>1" s xW7vԷ@}H i 6ʲJ(LF)TJԃ')kD !"tJ$,% cF)4H2Ъ+Z+ ܔ^9t@b%Y uHRVeF(MTԕg_-2(QB>Ӑ}<|gζ,GTF f._{v?¸F21 hM:X\;NlumC##L1^?0GJ} fYIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/codigoxml.png000066400000000000000000000033311360462764600234240ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME  E;YIDATX{lT3^o&Ċh4@HFM[*hQHRM[(% "mcH#YN(II )r$PCl^{ڬ4g|}g{3;d+0SUo=W0כNOl۶-;a:b4vv_=>!x˅iI!R\-4ɢE4399Irvl߮0Nkg[[T Xh1xbMfo<c YylΚi%@8xk__ءЫ[^Ra"%-nы.+!ݖt10e[59~>6|PW;%`ʥL ;I OunŜ ȹ$BJ1崴` ^"߄ʖ;PRRʲbB \$B&չ Ftӣ)`+]*V }nC3`nKQ$x<Uz'|ذ X>0˗/'r$r$?>9d>Mp:-w [v.*@с%a+.H0iQ\YY9k~$$+c RBpiEQ?0@UUմ\Y1‹|f~ $Nm  +jW/ߚLV{sa7x=2{ݑ$fL7x;{1:J`O~;ٗ9mmm񴚇oh9pu|׾_4(Μ9êU3%H]o~F] ,^d a;G6=/v(݀*J%%kMTr|oq:sS'`0 !&]al=1X&O;LT,kQv˩o`cX#IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/colar.png000066400000000000000000000024461360462764600225450ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATX]Ugޒl&v$tpYQJZx ү 1ϠT"EJ*Զ+6M6Mn63<^L2d9<9^%"f\|f>=W}C .!N\)ڍTb oK'VF{3kW nez0p]qzniw;_ʹ-(ŵ>8ډEӎ)޼!x <P(iJifo9d=m}aܐD4WO5휥yc'?FW T*ҏZ6,L`ߐʂU*%̙s8Ńh60;[Ĵ,N.L)1I(,--QnZy|ju^J%x$X^t:dYVWW"i% Yٳg"'$H$ÌQ0"@8%677iZS\.3;[G9BX,bvb=\.K8$_1J ߺn`($ ԝAbFF#4GYr`MRlSJBRK0HbP 찷70=ϑDBs&:L;}T ^{ҰA&ՖJJ@ok^AP(FGGlpp;IDATX]lUv]F_4!5Y1hf5P"h1c&MC[􁐬_yP L֚BؗFM B*jj̽>Щ[ҩTx$g33wd2*˭.BB h@!I{L:HuE/(D'M!_t]׬ZZLܕ&`ٻK@Y\,-o۫dI&i1q3 h9sE-rt{lڑj1}}t\N+/h=RU0l42|˃g(|~1R$ɭSs&2\{#ZVJh/bFme}/gwӯELKR 3tupk·Q?XZ8p "Xf+`aZ+`ri 5m` m.L@C6<%Po'01M`i I6mY y+Ɉ%ۂckY뱡C@hC-^:||+p+;*RbJ=DP\>&h[ǽZܻ߼R3_lsUC㫞ZS;>XqӎֈҠ&$K1#_:޾Ҏk֝Fpg\ \^'r5J+ LFqlH, U c~Jj' ;qrׂs*>J|E(*qs 'd,(JRqH ""+ !1eB3!oYID|)BZ(8###@]K_=1'c>9·*a]KZ:^~b }Oae&JZ4m~>99Jc#7'fbl oBG91RRO9׃b+eYIZ#\aݗcXZGqӵ$zscʃBx3)0pvV@M̀֔1!oS 8=Y`6S1# y<"6./JIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/collation.png000066400000000000000000000026531360462764600234310ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs+tIME uZ8IDATXŗ]hWwv#fJŇ4Q}Xk @ UE(EhķQl!( !j%mhMܝ}03lJb\29{{G!EQaW_]q!BΝkx<͕~)K\}Va| +Bnn.^!G1 ϶;w 0E&;ˊ+hhhU @ccON={BӴy޽ҙ 0gϞٳg $s"=== _\ߎ?OUӧ[* z{{ i à:8eeek׮q1:::*!)//gTUUqINeqmGKK panݺE[[cZ=J?SSS~%(PvD4ɤj>|͛u;wPVViR)Ra9uo޼!L[[G޽{V*vt:H)bLOOɅ hnnFuٲe p)%\~Occ#MMMRi&"};NfpsV B@/Z:3٧h',ׯ΁q5sB!._l|o~ GGG-LBd XlFc6em6RJ]Ͷ{.ir16z||x<.5[233ý{Xs*D! p׮]x-O:2O|Uȑ#|>S7o`^ cQ}*˕Uddǎ|mCzΚ)YIhǏg'|O00gȖ)%L2\Ȗ>=Kd S`ƍ 1%0(h4p_e_aII 9k 1J6 iڵ^AOt005w 枖 5)IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/collation_grp.png000066400000000000000000000027311360462764600242760ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs+tIMEJfIDATXõMhg|dw&5l nk[DY?M/b".P[Ash/졞rJ@[R*$!6q(۰n;3O,1m4ifxgwƩS>|gt]Yڐ\.jQ|Fi wuFFF>qƷ9rJzVZE6U"DM@)%J) 0 rkH;퍍4xKrq0 <\R}ּq(5)<`Դ,P? V\Iuu5{%ncccLOO3>>N__X-[088Ȏ;d2R)FFF8p6l`߾}444p!|>[_hm8eYԭXQ߶mV^Ҳwrefgg<| "`'Oݻ9w+$ R߉D e-pK8Ʋ,l4M6nȭ[ 9(ziJ;K|~ZٳǃHڵ*p333W躮"}Wl~!-cЁǏK^ ?@U.6DDx›. ur fE@mf4Mˉ_Q#b͚5\JiiML$Ok+ǾO?}slB[uuu"B*N esS.]h/^^ʒ@ċ/vuuQܻ>YD2W X `ڶBiчR#0{N29%P74Z˫3L@:#I|0Ci6BSU,/M?=Úznj\.IBivZ2ף"b(,-KBi)|`6mc[y²S 0id2ɹ(.b}IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/column.png000066400000000000000000000031461360462764600227400ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŗk\e9;t E텙4PRw! !jKvic LԵ[kͰM`!@d !U)im{̜3a.={B7yΜ^fHDE6Bhg=VGr{^;KZh CA>7ʹ{(lˊm9;:HU ]t-7 y[V B\; 6n{ nYm 7ſ|ll8A+݆sOW(Պ w:҇T,9H~+r*7lA@‰`f0+J83SpHwӕO!4ćbb3Jt_VrKTŷ x)03 "Y QF9MqXT#-֒3f oYu. ɉcCm+pHPv0\AADKxFIe8`f-]7lVĬo;'Bv;F(N1AD "X~M\*7ƥ{D4u؛F^U&‚j$mGPN8tB_]ZjίAϬk[Yh!Ax9I:]QWZ:pj!`b(e""ǡy R4FAm Ȩr/}OϬA`̈́ v =ث`MgB2Q~w W,AӾpJin1ݎTn+ɼ z{̛͚9H`d/yu/x{CTkR_j`FG@T{Ҁ89|3/ҒފU]z( Q@ .Zllkv흙ݹ-B/N:hFќ|?gAzܪ)Bm}̱v'wR W~qz}taOҳ +^j0zbnjNHn6Hk4>HF:zld0[Gc =rrUI:(DBJ _ȑ3-d1t,U`qP-)%N}tl5X=pQ3y:u]F:%2'k;wxᨼS_[;FjgX&zbZKtľ; !nFXW8;%9;Vƃo}п"|x KP1w]s3,C1F,IB+ ߹GgǗ_IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/compactview.png000066400000000000000000000014031360462764600237560ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME'OIDATX;Aƿ>B  Q<Z\`b:m=\X\qJZ,EL$)|n;;w<Xvٙ7gfi6H$%X;WqHAĉH&&#@:$^~BD=!3#X]}zZ"Gs8fWߖFwB{w@[b*]D^!ޔLEryA7,  ´w4p"xUq`xbưjh $IڥTժ眓 Anl BeZv^ְwHO;It:#1}ٲL;OKS<~z| @ \nŜQ/IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/conexaobd.png000066400000000000000000000033541360462764600234060ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME #V0yIDATX[Lg.k\ 6d FtER/Jeۇ>T>U[)v>FQAJz&+6 6me\:Q7q[Iљ9滜|փ)vgg ü(o!7xڵ;?~V[;vz`PY`rr27xѳ } QbnnӢ(qj+W 4?~s;0VJT(^/.\0kH䇽n?2| *qWgt0 ]AQrfggq޽M~w)|n x?/.jmKP ;pa20441,J$S}}}АuuU<9sY}%0/kY!"aygϞhkPx=WM;::#mG_b'nfY ~yD0??_`CR!R b Ce8qW^!\@5[nd2l6L&wBSv`cc].^y lR sss܄aŦb  }t:3pxb``yj"t8e! (ba`@QvvҨT*xq1 ]o B`8~v3GARa؀bbyr͆ Bl6ZZZ@z=dD"ŕ h4aZ"ȷNrR$t]nO0KKKPv Bn ϗ xfN 뺽jCE$ `H$](|>?| z6~ܹG&&&Y!IR=Ej੅PEe߼yS~Q=ғ@U*-Jeٞ]ӧ"JAEp^$ITUhooGgg'l6+ ,ǿeI (F4l6'ӧNqri===x!bf.;7u]tuuGgu{;eE. ,xX,b&V `qq@`ON'%";eiaL&xb`0>@S.WVEn6d2qJ:F6r,UD"u8$ݩVHReUeD)۠t-`I#drEl7VKhU7z_WAhM ‘M#633m^Є050 iKuW B51y–4FC?2(% IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/config.png000066400000000000000000000041071360462764600227060ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXV{PT}{.\K@Ay"hV3u&ԴujҘ6 d ccD\ELf:hZk >o]}{_{onfALaGzf|;ߞs~YeKE  WXQSSYϦw}zpб[6 e={[Tj 鶖MiiztM"im7}=ﯽx:L//jbr 37vޮɋQy@yy{C}/oqjB!*)3?ERm7$&08+l4vm>y&/r<B(d^РZtUQ\|dYDžx :QG+P(_tO '(dZJ8aYc2h,x^IX CeB=&pܖ;fho}45-ftqzZ-4 D^1*De(8P4u>BeY$Ɋ_۰d>uYɦk6NMMveCWoYJ՜ a46l?P)q bMkM[^z,p83fK&0qߔӝhM*oZN'F#<n@zj(51ԺDCo_Ď?X\.n%VS|ݻv̖vKArY5$kK0p{vO=[2:}Xj$鋊9N5}o>1睁=Tlz9%%Y۝NLƐ 5;! "iNwowaU>/2ıbҗvqm{F:<`,f[i?|l"P܉EK~ SL:\CNsBs8m+VZDJ m7Cj+kgLG?|0٪SZRdk!޽!hIF(ކO4U (! 5F[ۍº:>j?1*xxeIa fij< 4oíw +hIy108:;8);v5!leA@ @0Ͷ2U8 rs4f}Q2|>(H$u\꾰j.TTT}r$ 8XD瓿C|d8AņW dYB=xAW\\+555y/%9R{ g2)~xݣ@o52n Oo)@EV%EM˖$Dp{mmmS?DNb[Vii)A)\ (RDR1(9s)Μg^k5sHDp7uW/xsqv:k?8g ->ӽY"8}>_Sg>g⦥ X ZΘ;'DO+xZA (ϜZX4XRZ7ZA+Rš'prghY@1Yn}J=\ ǺPXƥ)Xǥb̵#дis'zP78<"y(bbAf ĬB5! hK?رsg MG APH+>.PL܇ƆU䧞Yֶp*N{ ?N 80!_(ryb,߮X3W;l>p[Ol~¥IL *:SZ0++,vR JM~u5iiY<i?TS|߃y<o џ6oȉc?TWךƫc9)M 2ǍI#CVZr0 @nzryUi"9k]ye.ȤSсفYDBm% Da/$&R "RLD RH;E˺6pꏇ6g;{O2! ܄~L"3l{օG ~wrݽuu.!JIdc5/QauhtmVďhNU*nJRK>g@| p-NƢիZ/H酦*""Dd+•e,!Fx<' QeNOԃ"b+RP5H\pK(W| pRG5`I_cJ2IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/constraint.png000066400000000000000000000032131360462764600236220ustar00rootroot00000000000000PNG  IHDR szzsBIT|dBIDATXsTUǿwNҷ;ktHЀ hʒOS֤4> >X5%fE :AQB;[ol`!I{nbgVꜪ{|WuvtwjL%^ꋿ}$kg~^ CڇmǺN<:Ic缾X8FϸOvtwjC>;-(UD[vtwӅW^{E*+7iYzf§ǒض@[G8zi閧ůA C04߁]0[,< q7utŸ^K--Mvp^+ic 9oGCSےx@[G1p!iϞfD@,DK8dd[J-P<|!TC`|Ufw㘻s[wBH(tRb>~#;>6'g {q%Q9(PaNDvs nv}~h?} L=QpFc&EgGܜ3p{;&IAETp~Awm b4++)pTanaT};@DXLʵƦJݚd dT7kH3طۅ\}}ShO`] &xZGfbQbM Nܽ'®TC(ʃsBm7bmU$rՖC1P]iNDCa;a*VO^g[u$-2? PUPlq:B gm,f?]Noo*`FVk9?zp7dYC*$k()P_WՕiC1 Pf)mr:V_R`DÝS*(@9dQ@nG%"#ܪ08@Ot&P;2<t8jH*2aV Xp * WyxCDӳwdh趟żSPvRjuG"siQ{zӪ9n ߖ@N"hwbɊ*rwXa.)*f"Ғ" ^Oozumtߗ3$@P@Oll<~% M EWR,ch8w{..KW9Fic:[k'bnki:MYٞK|/?~gkn<xN@2DAbf:+U*&rةamƧ'r=7B@QBNB dDd'E+hΛ_0@@-øf1/ s,n5~cHiCRY$h ekq]!nnOÍ1(n׏+?Fx~2M|"IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/constraint_ck.png000066400000000000000000000037271360462764600243110ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 7[%dIDATX[l;3cė8NBǗ/!$Vp)PvEB}K>>VjE˥ta]Kf@ 쒐;qNݞL@>uI3>_u~{謹*>$޹>}5uēL;g,,B N*WϜm9qp5{J8穯7}KrF ^88?p[P?]kèZX1@ޓ'oTo.\4D 6d@|cKаd#ΉF}Qxްc:'g0 /8JMfWW"߼^ڰPt`T棱LM/@b 1lYD|c}Tl/Ew ">OC8"=O͹<w{Xw#:恵VJ]$88cMan>Q9(P&&"nrnN}sV sߩ#`w{eLE(N1g{pPAG@k߬l6ܼ  <X bPU (I5SVadl *]0B8t#'5RA_F\ Bfc1P,P0=<癘a,6w\ /xbKRM_u '0Xj13׉(.0C'ƎM(u:t7nhee٩F&蹻Žt{) "LnH$LzTs*e3q$$6V;֭; $w+G򚮡H`2r;'g0bDb9'䙳 H"GiFV6UqDRVh>suMkqtE#F9q0=Ǧ;0 EQ3M M(.4^A"Ւ|phb0j4-|jtRݯjLYJ0 L$"䚲5޿$'e3WK;`u#-l'|>tqrBA' D(^ c*#٨G{G7.IY>xUagu*ㅼ s[Q>jJ$*"IL,^b 0ԉH ESӇrR޿Y\+.qzϚ-yzRc _F=vWmWG׍\| fPdkVØ꽊{?yO.ߑ5yh(9ҏjtt[.f%FfV{J?Jy(}c7okq10KI+j Eo߿>My6i!Okn/ >X%Bw8}ټU@2(ptC()ZZ,ZvXe,KT(#F+>__N:@ uMHdxQK m": ]lzO֘&0؞i۝W y@Z22CH1o㰕P=Im鰕.`)f?fdIz?_GfOkc=>i! .ꏮXl|v- k׸Km~\0@|E0@ DuRv$xaG(;_͏cLh!~{j<rzh+9-iɼtK4uМ軂@c婰H˞ %,fQti%&u5/> hK_IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/constraint_ex.png000066400000000000000000000037361360462764600243300ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME7mIzkIDATX{lSǿ{؎v$vl'!uH @@([@}E]Q!*U$ǤJQ!ڟ4x'](XRȓ׏{+#~{ȏ=;d }?Ax( *A/<:#'G۷##36 tխO6!SoU;\5xE{=8=TV;{ MbX$x$%ص~yӉBQ J |)m7ÝC :T ]&fH`(0ʌ,[[8! U+W6"8~ %ȧ ip ִ<<-E|VU0A)E 2l(G)Xw2,t{X6n޳Pzڪt>d` :D2%xs8!khݸQE@Noܲ%lܼg;r»./`Li~̳y|1 0fZ(uh}MM`icj3&=(%e)'S`bj&&O- F#v|765n |t9JhЂr n)ɋQh .ˍ\ع~ BNW]F\#3FH;E91FͣjoxZנR+|pAv Bpt4^LƺJPJKpƦ!R1ZAޜlZFB@z ѩq\tEDN~i>`lko"ЗމٹhQ5gfm?i@&-A3T`k`f!G} Ҷ }]pE~7d$ (%`b^rA!gbC`R`LcgP wݮo鋄FmZj5,$*T ]E/aց,Bތtltzk$| -!B;=BV@)G./Q FXOe! "c9b ;:%rS;>q:R94 Ff)-E!^F!PɁΗTt ovJu >? Q+QS‘JeԗZ!0 F(ct`2 yv{/x(#Ϧ@)Zl504ܠA݌\6x2LA)z,GhkTn|^߅R'\nIm7:F*2s9))*߀f@ q6o[xSk8AZDWhkD 7&03A6ܹZ%PUPHĀC΃x ,dF`~vx1 &lbe5F)4ס\B (bEI C+ gK3΃pp ׯ9^pC8t4w^rXOfpk6%0ye sZ*2B0Uӗ!%ywQ>Yٶm@,&S;~d/T*g2 @Xt*zD=LC[*FsH"$A5YJ㉘<8'O ۜf!̓R (@Tfk &+C4jwBׁ0̳H)1#PĔP߻vBuo[=Ó&yJej|,+VOam@4FBV 8syA83P`~272 ;&㣣2Qê+"SU2 h2Z[$$Fj=x^Hf:av:xoyeHO(v"u p'$}@t2 ˳WE% Ej64̀r@U,,@R%2dƔR@hf)ZGN gj6W`GV>dиA p aPSlUU2v$جT~G?Ȥ78ec톦b<- 4 |A5 4`nn POYcYq5qo5-QN`.U0 ѸsfB)MVrg@ar""sw~Bفij`6 s1? ÄU` >d2i )+٫F>ov*c*BytM.|[Ko]Nƻ{QVި`yegGdI04j.^{/E쨨nv{RŞg(p`h n? :ne%wMӈfZ,0תx/e,/Gzw kv mſc}KziRۚn8 (|f&wKi>k>؟yb;ҚjzW3MAн6s_lz1'>7AIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/constraint_pk.png000066400000000000000000000036021360462764600243160ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME tKIDATX[L~لSH8(B%$]'@˶]h^L7դlڤbvJ iQM4KCJ( B8Cmw܅ qҐd'zɯ9|{/>ΌsdxғAO#1][vIO9{}@<tULMOzE'|-VOn$| W{9\㳋8B쒃ye#Skxo &v#:vĕQ(N«q2LsڰpUnk33 m/v}mGNg?}FҶw*noivKJKq 0ڑmv1躁DBN KVBr:UٙɯhG`xiSj*rA!OE"86'R8 8= 0N.075a`x=̫sK1$e+g6" Qabj-(sU3==FUUZ ^WSP8m+ꪶ%pw !ȲE4!ݜ $kt!سhRϵˆa 5:9nm7܉TRE"R"`$ D>ߴap(ă!dkj[]YDCdEVR~;:L&C5{J`eտV{ MBUbPhfEL*7G͉c3#VŢ+?&_t3ҿ D \Up@ C #O ]hh 3  ',r ~v)X-fpbZD axnx걜2Z \ =xgcYE C[1x0˳ :@ .LXމp8B?r7b0apؚnr|3KܸIk @ڳcKc#24w/{?4b}~*I9ȆhLTU4tCt| G={2%+P_"U=%#WQ!jƐ1ko\ ߟ0S.2FVuHHd=Sowq=[QϿdv)IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/constraint_uq.png000066400000000000000000000037161360462764600243370ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME   [IDATXoTƟ{xfYMEس!zķ K>܋LU"Bl|_ވ`rf'!/kk`}ۚk8ˆζRQP5p"p e*sD޷Ob`;tgw0\[GQk|Y ,Ŝ5`]-;M_K|OÒŕ pBp e bu٬UWJ 8#LNcKc-l 3z3".!P b N * 7Eqs"Lˋhjthj'.& BMv`=UU.8cy@ r7Ř`6PIa({; LY^?f751%/x_nD,>黇)($8Umb:a{Kd _|MuOY06>48LtޏEp"l,#hRBrXѹ Im(̌Jwv VP^kN±H`*;|c Ng˕O$65r׃`H"IPDFED~< di {K и1-"%%wofu-c۷z=$qN#brpNPzؼ)U2Y4|ӹOķmǵumFёvsȤa+51N?wauPH|P@Q`dd%N d׽GGn%.W5YK@8/AY0Er9`az2B$V(053 ™ߖ{{{!<*rygGɾ˿Rׁ+* C%1ԑc0TF&CU4 Zhk"f``^Y8uK#%pb(PtydUV&'FR%x,?.~fSqJndZ!64sX|dzO6З2 NOFS&ɚƣw~=x굸3)X)yfb2TUDL󿑏o[L\XZկn*@.RS嗜oSm&$]UV)s5 ,XmͲ8[0h4ժ޽Fmm rM|y c>} d]Ͽ!YÝIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/consttrigger.png000066400000000000000000000047461360462764600241640ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME ";9 fIDATXVipU~;۽MYnIcHAR:h-j;ZԢUv:8:2Y:VDEQ($! KBo{{sssHhmT;9s~|<kU@1:p4{n?B1WuCO#kϴG;yg*8XIq@1E.i  bzMe';]R\RARRb/F\hɠ?kk[.Y3PODF ,\Jx RRAFH BWޯ>6lGBjc쓊\yK52N"0/;!ǔ"]5ADWΰqkAqb#;9=W#-QE8P9fN4;$n%}W ӱaåWTJN ejķ LIG L?"*4^0H.L:zUHZBzTvwݫ⥯qgBofL*U);Xre7㉟|LMq;ݛ©H`A#nH#4Li0.X}Ho;}~^7}NY4վ?l {/|Ā.|43Z#<ݍP]MFw A(Z7;>5+$=Us^>zLwfX67~-ոAbF9{-yĪiuĴy %}:+ qpb C!,L[)&sE"asnx8ôl[|a̘BK[/ 3srÝ Ckf`XUVE&&`94 .\G;_j @قO6n۔_\{/ &0!Ӊm}q%޽K[d`&|a0!o4"CSd'YQio&t/Z^,.CM}ֵ"֢DٮT3Q _\=60h?oˡW(e9&z C=rGI,--5Ùe=I8!6";:*̽~E?LΟ;!2q YPo6du r^{m+χUlvtqYPX84#m-fTH@EѓO7}zPfx>ysL0Ҝ PU p Vd8!K`dRJ`L @3=mE.*j bJژYaPx8}MS\BT{Qeg8ʙ[j|᮱vhWaB1A/>U^ZZ% g ""M%b9C8d@"MH&bB\tbSoowq@DMi &b|}<ɞZUuT뜏@بPPaaԔ4&j_g=g~`wQg6" oУo$P>iUR@xaS*: SmWt^xcYv^zAc-1o B(Ǧq`2j]!U߅ˈ00 !_ ±̝|rh3XF9{*#1sy[wncrEd4*M#;5SmD ř`H(`G 8aRR d%l=PJB4@)b,"U 5 Oc&'"9JB^BEp $qP=Њ1O+FoMjJi\c/OnHw0r3,' $-Xr}Io k$0g[BǾ#IHЎ7WZR5hht0#_9}n$uK Rg(ǂEτߵq7Zgm%ٓ,fAV1TW'kϗxy1̈́?0MUCfu3 ]JgzEMe;<dۡOPx}byiջ⪪|)T/ Jn܆2ҀӚ9?ŒJ>ڳ82)V DR(֔:|ڹ?v3JXVbyAWZqEOWWŧ["8Ni?Ŗ  ._i3Yl->C.a`:YL!S4giVElna\#˰ .ZKc$A %L#g'bğˎ46Q͠iXEܳv4)ejٙ8Trj圁O;ښp-}pC ۣT4ц20tԅ¶lxwsn/uZ_RX8HQK{z²#ed\m+Q*|3k14%|0%Lˎ$RwѠT8X?#;^Jè׏3>]ײ8pW-di0סĘ"J"޻b1F} "dV&R GrQ8YuvhfwVo-^j `Z=sH%׻FPd;PE+v8㪪| dl4d8k檷ӳ,V;7~S9}6\8uQuR,+W.|b$YW?;'wB)Kh`ͺɿv@IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/conversion.png000066400000000000000000000046551360462764600236360ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME8 i -IDATXW{TUUs=\uC2- kf\>tCib+۰NR;F+4 aK^rq\ oo}}~߷0!dk.4[,0`?/:tH5 +yyy`qޅݸ P{\Ȯ(%cCtgݏ{mwnEe"ZZZJvNG=r~RUUcǎu) $CWojv2$I e1Omo;VvgnU2Ua?j6<'DDs be<,v!DL=X!>>?8F@@ٌ DDD`ӦMbADDf̘pQ?u >W'r}Cqw___^ !!DJ̚5 hllDhh(6l؀K.hjj޽{܌6f};d͢??0Dݺ;y?C 3M3Q3~YtJ <>3Gtt4G-KD37ы m7\X}U7ĉ/T/f3JJJpe "TWW(& EEEk dCz {C۽ޭCgs+v3wpaʕٳyfl߾+VƍCdd@\\80}xL^܎s&?5T'aqq̙Q[ dddx>Q7`T 94'rCCi߲R.&sOWK(h…XvȑҮ7yENn@|w@pfltfa\solq:޽{? `҈ `0@#_isF&{󻣹ܚ~nDH׻w[[lٲ%d2-:xg^;# q/v+c>5~IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/conversion_grp.png000066400000000000000000000041751360462764600245030ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME#Lj>IDATXõklsf~k15h%ҊVUTH 5*B@Vj.iKG+ -u %&J0m7kދח?6r: }OFM)5%k6dL&F!HԚ  EDxvޒEY*U2'[=}{y۷V\ ݎF+/_L-IDGH XM^^^%B3Cl9+j9&PJR0FKDS:0tݏ_ J_h41FnvLQ__'}h S:Ѥ( =ȈxEAUUUhhh@MM 8F[U{68]NDP@p |r n{hZ H]]z^ݎomhZ Fc!GR|X£ݏbbj^Gwww(sIzjܺu =Bii)][Cmh/ÙB5;`D l&s!ݻ9V^ 7}?tc9S- mzjIxXV ZT5S;P(FVUQJ1ܕԐ1&RjOifcp8޿J,=xqJ}NQmP__/QJ zw̙3G>|}ݺu:Jiى'^Z,XŇ}F1~yTy3RnuBR:;;QZZx<۷ocΝ¡Ci&~WMM͇".\nllP ݽ{6 -Euu5a( 0CZ,5opO{x~£ǽ>t:l6HJh4TVV"77~@p&):[;ҭ9iZX,pQTTB8` gkGF1Hc?sfNIXx>i@l젔""#rvttq\K~1vJ(LPRR2\`P񠣣D(򧥥- fŽ{ى0pM#)) PccMMM:5U<+Eβ5/<_:-LHOOGuu5dY!/^Dqqq.;k];s~ Bc`=H$<~f0:Db|~o7}Yڃ-\;fKvuuu A`,~|}ҟ[o_c<;ffǎ k֬ 55unW={31]1q y8ޒkvؿ`Ƚs3;&z elb2όh7jIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/convrelnn.png000066400000000000000000000033201360462764600234410ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME %PIDATXýWkl=zf׏fM y;B]lʒT4DjVPhVU"#BF(bLƎڨ˟6ABbn{Mz=;wZ{~u90ܩSN_"@!bGccAdPz 4_veU켯СCϟ9.]1 QRrFF(**DUzYFA( @kk{H( %3Ѯ]UWGJKS4%!?~l H)ߋB9009rܷoh8Bĉ0 m#s3g^ǥK !\biVڃӟ߮S7rlffݴiRs۶qMdgg]]]/l 'C4{ue@444DUUUc"" TW_Gh&&&ܹscK?+=dZet$\iiiXv-|z'g9ߏ[1si4f{hS?k VW4?f?z|0H$|r455* ~QE\ 6Bqi>+SgFXF`2Ms6&S!@vJN>dD4MMɜs(16T#cK7d1&3bZJi6+`{PIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/copiar.png000066400000000000000000000022031360462764600227110ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXWME}=c1VD"pK!!!,}%K9!pD@!a!#D$ъHeǎw^=3cgVq_ܪUu͘Z5daI^N_\{ͷw.__$V.j6r$p.`uu/-h,Dߓxn8?">GB,p![<Ox" Ύy׻}6s s盟"PVQV JROFa*^d@JNcT,0{&pG1SJJ,,h*yhA<6|r%yEǁeз5E@;5ggDFn r+躍T[0T\6p]&MH)c%ؔ2zafSD^ԏȓ@T*\x y4 yeeY>Cu8t di6Ӷt6q'8#10F!ngM%VCt&VVVbJ$@ J%0?V\.tѾX,M"ܶS{XLf60P(¶ʦ,NPJVb0%0^p1vJ P@1;k!4u j&mBs>! (s!y&=)5OB87Koܟb?8Ҡ ڋBx^GA|>#g* xƵS5|<1 $; 1<σyv\z|bY'+cH)1~{Op B _r=#BO>dp}uT#޻qV I*TrRH"8`[י>5)G:s3gF("EBډSN30i!PJ!DJnURJ|_u]mhh_o˞bR M[ byMiZ5^$J) .m&!De%`*9_ g溂[X9+VS)Ρ'HY^Wa9ٙ ~Ebox!'r <ɬ@JYS9F?JU=KG:M*0"%::Yn/Q9Yaӷ_ R ,yfq=}t`qbcPJudrTB7Yx h($y5Y&/㣿^W^!38H@0(W_,&֖B36 &ī<\Gm,RJb8H@ C%ۏBpm"ZM<4a3)y"M>0;iSP1Ʌ  hS^1@SKϔݞFNER'R/j)1o䑟;TX??WG.2LoSwO&ѴcSt J]AMM->qq$ӌMHs0aBt$|=-!6בA&ro0LR8d~?_~̏Upe~"ɌOs=lh=WW܅fvq_7/_uE,-F.*咺[nN({6]ܚcw{\:8m;588C>ɔϻܰ871Wf`&Y}NI@2Phqkd:WPDb sE,||pФ:j2uBA xv|lò=s64UZNgw[Jib[N&, Xba^ dei033KMVFhO47&hM2?*`6mcYB˲,b²T*m\/,@)jb{*n.'RDQvm~c=NU!BMCM<3V\[|>?f[b'a FRlD_c0L$&$bDD#b41?B@L)?{gawB- ܙ|9g.?@oo[M:ǧXԉJY1X@ .̴\Ν/]7 ZvnZ$rxdxt׵Ŷohx ,2)dS SNfn\:L=vJS2⨞ m$t`,ra'6,Ŋ{Z 4Djw@PY7*2-߸ s&!8}VM " }8flE(B!_7 A:vņ p΁A5AykJRS_G`jw:f;QPgMjY|~tGN^ESX/*ixsԂ3 RN"|| `6+*u)! -XJQu4xR<?~_?6 r 3NH`Fhj P^dQWϛ_^LfC#魧xh>H͖D&³Wvdsx˂daS Č_IR3yTY*LE!2py 0![E x X5l1_sСS===' A0"(2Z9Y1%"'М m/n /[*gheG"%*j])LcWkXT"Wga؂5{^ٶK F};00szoɢ?u3[\>_z_D0 D 1/|\8JARSpw:֪rVEa(`Qպ#ǽ]TA%Kc__* s q`O<|[[F8ͼUXOBuWUE4?NGIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/database.png000066400000000000000000000033261360462764600232070ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME9yn~VIDATXk]Ukǝ;0<,X_u1*Iu$5MPBlcZP"F4>@*&4mam--ҹܹs^~8NLک~u}9';w/~!KY>߉lδpc8ЇB wm?unn5A LLNs`طpݎWqv@ <Oaб(ߛ)ncU6& ?r<:#mf$c;?ψ]"6xvv~>ZVUp Zy`i&Nqld?Q<cDDDIjH1sFEcbu+:Ow?]wa~&Lde6c0IU]EPMN>14kΖ`#p1"PUM^+Vm8aPa[.JS'<`)tu?2}JP[@lԢ f[!̐_0cu.#|\)OAӪ[FTQ`F yf>A}e7\ ׽ju ]Q9$UFP EIJS 3)"i@iee4 Hy :^-Dq"6.c%L#hX-dBO\bX Q@5r}خT231v'ճ3NtIwi4CW3UyԆc^w3L#Ohccd jRz׿} ~/7x m}1)R!AP*d\\3ޱso ?wC]=MC.|sL&C6[L.㞯|~to_hmuيưuTv*-T^fRS/Q,E疥)_bjl6{QEG===sPU?JsWMAf{h]EӺW+{& $RK&7,/IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/delcascade.png000066400000000000000000000041101360462764600235030ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME oIDATXõyl\Gǿ3]mǍs@ "C(J!E (Tъ@HUjPP(=JJ Aqۉ]3k;N%ޛ};| RJW= fxێyە7/ݣ .],8&8}~#sSŇ{#X޺Bif;%똜8u7 4M:}zf_mòm۠1J)HZ~`ow?؛8Ck9)Dݖ羾z15TzN@0040#j]7 7.8c~Pqn @J?;@;J+Q\V{i7DKҊ*jC,oϾ7}CQ5ArubEuQpDV6z}2v /h •KqϏg^T9ܳ KPYcVƪ$R"Hu}[w흦zҖ`W(*)ŵ}7" a/5JmB 3Ic~: e՗g1Ro@ѽ96H֢l= Tr8TTT !y3ᚮP*ٶ=/@!rνs澶u-^J[o#:j-[V?DV~|mQQqIb$1v5] u bL}i5aou]a`2EavY $[H0F"u *9'ZR2>~dKRJ`FDUq,z 6h#ԼZ$ (fߎ2E , :UUKOtmW  E , }g+M3c A=r#0:| Blca~ _1Ea ciN5Bbm:3  sDJ%uщG# QHec͍EEh"Az.SsGt6KoF\d2OTc)F aq{[{Ϯ[4ضCp,Pijh)Ё i:X;ҫ]{~UՔlWcASѻΜrS5,܊JKQ q ھ_8:T| ̀;GO쉧uH̆s>8D6_dtl$;\0#14(=x|j7c(M[#/E" ,߻A @%UUU\sϥ:2Ɲs$S0 9mag,$%yt\7QUURϥ~1>19~aS;~;'zr8J(aE  \BRE1EAyJJ2+hsal\޳+RҼz6pT Æ^a$OLuVP6t]2iRJKU }1v19G`XlL^%%Xu=Ữ iEFp-;ׁ\"9G:;:ZnhnlislT^(uڽ{ER{?sUDIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/delcol.png000066400000000000000000000016221360462764600227020ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME`(IDATXWN@v EsV zʹOPESO9qST!&bSP ^o/8&驖Fl3fbA gggoJ'BȊeY!H׳-El6oeǙ&0,"mcmHܤbT* ԳL )%`}}xIq`f' Ccm8bccC?NOop]k8qxqhjHu|}330 0a(ιs>ZsP @\ZΎ.4KޤDxyy^__#c{WBH)AA\6Fc :me뫌sn0y0nJj@ 0ưk)s$ !:yh oߋ0,Lfe[[[X1ժ@So<NP, H)wAz( TUC#) gLT~?U3PmR Xe0ޞx'mtI5g ,]dm|+@y dMBBH[V$ljoƳRJuPJ Җ!x==8 +k?Q-nwM- (9QJ ],=Kxv|'tbB%MCbIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/delcols.png000066400000000000000000000026721360462764600230730ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME !0زGIDATXklUi+Nyt+mE4W @l4MZH0F1)44*O$D"(&1*!%Jhb_tb[]W'9{3̅%d?hmm}pa$Ihij3۹<⚦5?~Ĝn%ICM4jY:Y*l||ػwxrMӖ8z{{2`ֻE0P T*d^[/kkk @4qwb1ge|N( $u<lFUU5tZ>NsFfJ-LiJenvLG ih) @$a ( ,D|9`@ `H$bs2E(ftww[A-U0 ASQQa˥,˄|jjj,$Q]]mIB!KE"i峫kNjjjL DQ@mm5.˲Yq @C Ϲ؞<<+UU-p]mUd2gc:ćIMXǴ:<fx5 I.#B)B}}7gyaG_dEX^^>˲̍uK >p_ANsPUZu(4YNch=nXHtw^zN9/z d4rzeBh.kPv  8:;;-"RI2ݯD.:b]`V™b/SQUMQA7zb t&'c|[x%&JVCrk %$O;x ^WrO^[*~BL@ B/8e #K7$"r"?#9Q@Bb$cߌwz`> E>JzrB_ %t)@LccraD3aԄ(Q:f2ؚ _r(^MC]:|>bUFХACJ iP uLcJE^c}Ä{#wLL[vߕ%eD 70p퇎gݽ&CK$(8 0%^Wi 6l. oeY;:V__pE*:AE y7ϣ;rwV*%uCr7U#N\\%B}O7K|UDs;n,|ɓ6O%Ltu6Blp ~?Sœ1cN6D]a>waH ֺL'i׵0?G.fd{AJ؊[vS+~4IP’ NY n'K/ Gߏi̺pMǂ6#@4`Tw_떥8?칉W"4I~_ꃛ71V(#o?44o2Pgoy/)b4#m˜i\| p`Ξz4\5|̝ğ $roJGf'Z$n7miRr勈Q+sP }$$|[/3cpʜE(##cؙ'OѨo`nxHF~—OTa`ɂ͎g GqR( c+X촻%ٱM{ҩT@5OL{b*(@rX8TP, ](0.͂ QmlpaN&1<c 擔VIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/delrow.png000066400000000000000000000016141360462764600227350ustar00rootroot00000000000000PNG  IHDR szz pHYs B(x>IDATXWN1=~$)HU*/ؗ/-ۮB͊e?%(IQ0wv$WJ}{||r2H)!Dg /)廃/SZ˛$IK)Օ޾L)\\F 0IR h4 $IfV && "gKKKf}:  y<PTT*,f&YOOX_Gn!t6q!cmBbj984c'''j&t:j&<>Hlzvv$IL :n6(@AZuFRa1znc= 04]0 d1~q]R09G^M͜ l"[~ܯ$"mOݮSg@'@k`}}ĥRy C#J M +++cOf;~0tN߁v=z&|߇R]~Ysb,{OC)"]ԉ 0@!pkkk19X ܵYW[v0j@(̀{`o"c]'_W'.c{SEHMpwZVO@(6 A)u )B8g]mK!56 Y!ħҙBp?u ObX 0* 6R̭R_ƜIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/delrows.png000066400000000000000000000026071360462764600231230ustar00rootroot00000000000000PNG  IHDR szz pHYs B(x9IDATXklSeYmn0Q0AT_th1?h ^"ĘHD2/#\1usnsN@{n O{{yDrCKK˳&U1###UUQUEQgt4-`0iZJWUD unܸzr<9AU&>t %PPP@81%M(**ұkhP}>MMMMpf l6SVVI՟*3 B|7K1ɓg;HΣGSPZL_+)!;i9h4{ &իWvwwSUU㮮.n/nUU rc8^Gqt:oR0$ өcYHEN|U=o~=E x7m;366pGRD `a•~prۿ(po5Bp|p*M*t׭}efpE/[ 8Ծ 4Eѷ s'ņRWWg _z|KWKϩ3~+KaZb[RYu!̤F#2.Ȇ ^\G 9j) >4M3HٙRB~d SW1fVKɂs`NpSe@}h.Vx˷8/~?vT`c(0 D $oM*q 3 cXPlxD ,IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/depsrefs.png000066400000000000000000000032111360462764600232470ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD R pHYs  tIME#8r IDATXVilTUλont)D[$PwD$h$c Պ$l XhR(+BLgt:[?vxS&s=;gCQFF<˙ŵ$X7@L[ `Pa dwKW a)z*]Y"aס*ƺfp5B$׃a|G> ı#JJB"6B*50ca4@*&ݻbTz2:TdLyzS:~BZ`C6Ս:LXuNg֬+/ ; ) rn[' ؐ[pС7JKKWӖ@1$'^|0ڈQĚ|4u]27$76'e*@ "_L^ EQ@7t] f(BLD,I.PBP8%6|>\|#7nD8Fyy>+B,pآ:vp(n;VXXv&"U%-[6lSç)a9yd$B2{9sO;YP@Җu%u$u@:NRۀh߼(RF)%yp6 `ffF{]@kUb*jx]'Z}㍸܋(QRИ ?|bMg~M|5?6TT&'fk@Dj"B#6x뺛+հ`cL&C&!<K%~b9EGx< ?qa/ TJ`t/%2:o8,YeֺhQߵv֭ `hڱa{i% =2 ]| 6DK*SW F`bqvNSMMMSnQKU ީ"_=۟WQd"cr\sū<]7.// 6,NRPā._ezyb%g Hc! `^D2[ N ; ;ȓHd%efIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/desbloqtodosobjetos.png000066400000000000000000000027021360462764600255300ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME - aBIDATXý[lTE3vKe (Q PB@Ĉry'$C5H Քh4`ƒ }@.Z" D-mB{9sf>vtol%'6|fAOO#"=#"|瓧W6=,A11FL+:O29uxnM0h:@4'ʖE3;4˪5NŌ #! 4'`$8`LeG")^Q_T=1OI qӦ}̽'֌ ^5'NtB4.m#CKE5ݒʯRЇU&}%5˱SMsrKH! :}A2s<2nj_FO3bS)#pJE«t4@k۲GmpxBRJU˓Ҁ % D1:؃pJR RJmH*0A@WsU~9'PM"ҡt>]@mp_(0ތgBGp[bbn=vtP- =?'c׺XJ<2M8Gb<an|s¥Cis\s&#bWqU>t>_jkj1Ae4 s1m5K+j iWr"~_ݗ38v^zy~;׍;`oذkQ(*B H"6w(RqtJr%̚9I+wSZ?P(3aBG*͛`Nm۶isT:q\r/, 8951Y1y#GhI7IwckRS:q7,=tGެKئg1si;*,[J@( 6Yl8d&l\Ok=0:Qm|ߙqO12R0CY_UwH9>I&M*̐RMHǀmݺ?[kkk!DPrnx93M\@3]eS`FA.\zC@ER3{X:!ikk+:J/[|ygԍXаl8$ԥM4ױ.4֤Nǥ=v=#K◇B2G8qdUՉq;QIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/desfazer.png000066400000000000000000000031011360462764600232350ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŖ}lUw?9޾]vu2d"8%$3ˢs &h2b|&fFq-.dt3h񦡬RFKJi^./K|'߹w{~#Ӭ*|32o.ln:DGca~2G`YfX{-q">cv8ǖ~!9'д'#p++d4roRY ]7%;3X 8. Վw>vP9AD|J_}vTϯ }5If6 qs{1v.jD]{ѥO-k^ ӠYT1Tf#>Wsq<g`oD6  Q&\0jC` 죈SK}27h&}qZI֦Mo^@OM/ ULo|/\A>S~7jE3=bml)|>cG^6Ԣ&& &j,pP Ac" 6̟Ϗu{ G_^xE"*~04H f CbD?e2{[ꐕ`cD?|xASDjwA3h09qOAYv=\WlkwNزY!XwdWŞ߸܂'Ѕ{?:{/cu}VSV5Ț {HJ%7|X놭e^|]ک"vdew<.1|KgPn©X7xC>BBXU3v|6* 5pu-311Η2_]v&!T%Vuf}MǿngG*ڀqmf[d8/e@¨I@#-Ϟ9 fJۅrv~BdUjf vvy̓?[|#mܨI]≄ 36 @&[#cgSඈX0{i "e$FYi:"B@8Hz@(+g}j,A<J/*lD""P9y"D>лp~4ՖW#H<̏&[E\(I$¹|}m!71b́DŽLnԨvn_V3gڦ#uT*FG:N*fU59 Og.}ՕQ$s͝t P87Wՠ0v]* D`**85w5q-u,}b1į^Jhu?5XU]Sx+ᕷQY{3gH&q"A- tRqqo5P$}-,=P3@~YxnGXtS@P T`JaIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/design.png000066400000000000000000000031271360462764600227130ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 8*7?IDATXíhw_+Itui MkLǒH9W6O˨V_(4p d*  tnium켶zrr AP]ˊ=+﫱FWN>ݻ"R~W8U9~8Jyrqر/u-ٯ4%SP `ddvz1{xi;Tj(ʾ?Qj|Hi' YEZT??E1}LD&Pa)f`дi'.F+PU"}=+lK˻i"Q6l~BKE5kMsl$kj ~*ق> j@DP>ktk j~iܥ_ax#-7Kl03EȤFYBTԋu`cwg\TN\"aך5u?awofɏP6D(`}Xf4𹊧ξؙ0K ~̯qp]/^"p'QJfJ4n{~T++6݆x']FwL&>DPisCX[~͗ހKLĨ8^9kR3=wt8qVd2IRLP({{~Gk"W 8NH#v×I ]4wTz{{u``_#LJd2 |^nɷ P%"ZAUdh%7ڡCX{ӬN_lXD j=[>.WcGcy(qvDQjŨ`$@ԢjJ%lPjz<ߕ0ƈٻTn-r{onW@IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/diff.png000066400000000000000000000042311360462764600223470ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 8Ay&IDATXåpT?l I@ (b-PH:j)(k-Ak:Tg Ik [BF*dl&}?@XC93wޛy|'_|1Y[ͨLIZj}7kfŊfL1| Ebق҃`ݻ3瑂qrT0\\z)sOPkgch()|.ի^˲R)5ĈRe۷o/)++{u]97J !$Բ͛7O+yOG @gw,jrTt!`x"ǁf^ \=14?ކIֿB:08][ P/&«@k֚$Z]%E+OKb\8TC4-2`Ab鮋$GZuAy@GGnjʪd[p8տf͚GR_fAk}֭[̫[WIpgx)'*AWס8琰m;떐uŤSN3:; H$G.0wMfuW7#Or_C p7]Kf7⼺#}L6WL%H, \T,T~j i9V.۹q-W͡?u~ߓrdlY 9oBXuL/,A|3qTfߪ61XRӻ|deePw=M((c@%Az@H1`D;NB2{>3 4nn 4@QyywBIen|g֚/ 0nc'I;~X_b@CcL~W='Sf!A{&n/l9E990Ξʓ'O(81N1A'RHd/ b7=6JͭDgw.9ƽ1I68(o_wkYk+=[ X)`W, PGHu>0 ]n'qP+1"xzIuW G^!Pg>h"}6oJJ&8/]VRf79{p8Q[R %ԅ453soQ6 |) c@SqC)8C&(s_CW>Pck <`IAQs{g6?[v1*+v)-\Æ\3›Igip}dXymڂ%sLE0IH$Ô؎ͷ],_tf뗌 $畆-Wӥ<L"'1 MTFO.6 :Of4Гb"9 F0pFAEup8kA|D c ziDotj/ſ?/13Ln}jцM.__#GJ#,T+i;Ic<2?Vs|Ps[vn(\ {>ǽ74~YR4>tƥ̘b}EI^kcDwi߱)|Xx3OV -*mRhW!\WKQZhW藖LFǑ] dhg{9^Ol醏°(?ӧ\;nCIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/disablesql.png000066400000000000000000000036111360462764600235630ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 7+IDATX[lT3ŻxbmlC( ZJEj%QHI'"*}hx@P^Z&"<@rK. .c;fll뽜=LO|f>71~Y]׏隦!Ķm,mi~SS!49rT?}"!>ؾ}{H4uR?f?`jee",^/a$"H<~hVJa't\l|Ü?&m{t1ÆohG87LiԬi61'͉,\pҐL B]wk=qm#&y^v ِ?sH ɛ_DY{ X5ڟֱl$?q>Rtct)rq?-x4hkoGMdYz_saL{?L{9b t)q!$7/L.(a d@N+ݸǗ74$6.^U3mH4:hOH׷ qLِH_XgZs© Z5u\P 9`vgC?-_\gqLEǥ78r `K> 844s^iTTNO!mMJcm8Lj:xp4?<7xW(DäQqJ59U|RYIAw7xqŵؼznܸ[(It6} M;B22x%_zBpuXԄ@sicHiat,0_AyFBf{;/2ϰA~?.h?/q,s:rϘ W|[xJ ҵkI?zΝd77$`8..b7QDPJCυE B+Ϝ˿<H Z:DSN6`4[aEٲRR(eR[U6X!f8TWflq%[O~X Gvo*En4'O2( YE{#5PWWcSZ}'quu Az/8$\|oSJ_@Lϥ?Gg5kGUuu0ve,!:;)Q֣X>z0@@Z[R|*sRV԰.(ED*ԆFaJHbL)B!J)[[qN'~7ߤO):-~?cq(E/HvҸ?Lϫ+W8,..Bܖrr@鎎yRP(:F#f3naV+!`Y a!2fffr~ܖ6"?]WWw3 `dYV?0 D½{nː$  aPx {YW 1+*/}W.{&S(phe'(jX,htw{{;8C:`@CC&''h{X/%0Ė}0ҾᡖD$p =(蟁}aaaj"H&fccc|Nd2ـ]VkϣPN:c1FӉBa _IiM@:=l6/,--}'^\.@JuwZ,$D?0~69tמ3NM59OR+WV(Z[4`gYhZ?Ƀf]ye$C9aH5lAS2i)IJw:sﯬx/G WQ[b }ܖJ BhI&QɲBHhh2lɗWjk}tB)tA 9b4~RX3ǽвT 'L;V)u8pIQ^g67gtua~H[;?f{7n ?.M44;=4q ds{ !* Bg&e}IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/dl_binary.png000077500000000000000000000030131360462764600234020ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME "@}IDATXKldSkƃa< AXH@I`&A EY@B)f,؀d3BbRHx-H3m}oU}=lrҭOU5?r/Nn AD*c"F10@P7/\Uxs/M: (?aG ENq3v#lfLd,2k!}T]3wNsTQ`泷pik4i.Dc IIko[_?x?_5l;1rpHm4 J2T \{/q}-+YɧuD3:LR%ΑR "4UyGZ*@FL8XjmEvoC2gqgyi'}sy66#Xc0Fe($HIUcqLڻ+{,JOYNV@U%y׿K0;fGT5(::oW"fu_ۇffViE)cU> ŭz_D*hTCѴ*À4F!S W"f2-%BS_B$%#NFB)(Db߹LU 8YksMBX+,tq@JUk| %Ef}w'cqiVkťU~| 2*'"(ll~1 rb-Y98qཀྵlBz; icpH`R++TGC~"EC:96(^(bJ y"/1֤~Un}vȠHCuw7JX' C(5 7ON!dE|P! jg11bE\i)swmY`<(Ԃ&)_75ŴvM )PyVH.#oFh-dKFnѯo*IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/dl_source.png000077500000000000000000000024231360462764600234220ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME &U(IDATXoTE?3w/{..[؄RJ D/0h|47$4XRZ*n)k^DNr29wf{|/<]x_;ԩSON~u{/&2!2`#1Bdm."9`[j}+Ɠw:x!GK#i}llFS ohyc7m) Iv]Ӣ؊ZUVXV쐊;YG^@"syD@d+c1"H(w<3l]Vs_؊Ej8"RSL:گ+D&{X;[g]r)666X\\4Tj5R[n1>>NDښ0J%|g߾}71>2 c8z(f|>LܿyE(c,Bض޽{iZض# !Y^^fvv0 QJ|LD5JJVFyDQGc J)ha<ò,|gbb ڲ16^W d-ns[˲`ffz:Zk2zFF044DP ta0L-mRt:MXLhh `Wv")E<͛IwpΝα.5c] m۔eΟ?:\UN>Çfj5JRr֚Jm/A)3(bjjFA.CDu]Ñ#Gp' a266v޽{|]R\.G&I|˲PJaX,Q{aݻw9qĥ5KKKl6.nW]̀yxꪜp]~Cg`fH)aY֕K)˲Dc <(m {*i:$ t*|y}5DYDTe|Uf'<87)IJJ "@$z ib*FGX0jUJU=33LDhFۇ,DqL0vHL2 OpfiDoÊAD0 ^5;:sH.KbHx8]~={2TQ.auL&k*]ss3`;rY^6ZlD#KizNos/_u()[[[Q__CL. 4 FAi<מ]'y,3g[ǎg_۫=_T1NDuhkk+R5d(@c 9OA `/ 5PZ2'G/T[c ˲KZ "E(4#+h]]l](2n8HhiTgm#͂Hg=xF&##ÉFFju9uEJ_'3CH]?v翍2H||"$PIA|)e5 h1\jBb T\.L&Su u: "QI " @}!x- 腀(5.k5}'q%YkaMOO4>>nAxXߺ*(CC|ʭZ"ONNnhɨBhwwwmBh܁L&\b\ͦr_,[ .IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/domain_grp.png000066400000000000000000000034711360462764600235630ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME+ᡀIDATXõ_Lǿ3on >l0v0`BIZ~pl9iH6*Z[AʖZ ̓Շ*MJl +HHvTY}IjEUҪG1 ;noog J3 1Ei-U5la#w{9 ۲zBYC}\tZ]oд'[[ZFv%ejY[R0(p]ݷws.R^,4p=/7DŽ` ug;;_njnnRB:$!5͢~eu<-]ohSӯ dgfImyr R8|:Joy^f`LQ`0Y" Thi;}ƑȧCaJ{Z7=oM$`z/D"|KKY]P@E\ysJV[d.,/o@(%5aswaL`q'&H|(B߃4MFQt v X_? -D7]n)%@=)DR,MYoYߕ;|@_Gdi 5؝S6eǑ r挜.%aX~$m;I==VS{{4ˑ>;BcݾxI(FBHTߙ@_o7quTuw}kkyB1l۶\H 4Mtww-U! BXt!嶶judl؎պ3Ơk:rbEd*\rnWc^ ~vrRH}B (HA%rFJhCT@ι5YpvP!H#jҀ0̕p]wuXc LQ!(Xw<#T* i5vðn})/+ׯ_0}ܨdFʖI:.(yhIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/donate.png000066400000000000000000000026101360462764600227100ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 41IDATXõ[hUߙٙmw7&qӴ"l5آ(zCgAG/yyG>VE+mX*Ufdvz3kۍi;sqlCT 1/HdEtfcKkm-h"džv`3ɱ4`c0/,]VȐCP]@|JBDXn=^3(̮vK;V`rSA(XXz V FGX#/c3A ijD9N 0fI/+c D3@<&!j1`n ZO#q yĤ(RLAlNGMyDgs颏# Vp ,0?5X:܏&ܫ&DutWCT~W@X-$90 b4:I|]?[_Q Xn9S06xட]3C8n, @7G7]GC8&I:AYQ/l D IslX,*A4bx__P=wdQkpqfƾ:OnE9$u_.κa IF^¨=hGNBTV#ͣv@zUΠMΌEmF4.v@܄xLAyvA4tH0WP"+_WDޡݸoq6JP9ttxE]x8r#~)Q}'v>/$;F3]ѝ^D`..B!5mBOrg3*Ewcw-_go q6aD/& y4)Pm|"aq_m*mByLt4͢UQ$i0_=au ?з /z9y`Q 'eUy*ۑ'D@ĀK_4p_.gORVUIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/duplicate.png000066400000000000000000000026211360462764600234120ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 1(6IDATXYlTU3P:)Rj RbA*!FbB&@ 1(DA4bb hA6J @ S.Lgnogf2m.ɽ3s} ߛlP[kk4ڕWOWՓn6oT6R_ZZZB5`'v(4{!Q#"p;bͪO4>`#i=IKwy?(]S %B xlĜi (p]uhpGvwx<8(9Fuhi/13V#L[# eWJQXXa=PJa6FBF$3mK@wN6@\uw/p< ߰Ww(WGu HC{5YY7Qiɠa9m'Cihh@i]XTTU)ÐH;k|Q3Ywb1X]3 8Sw@ L W&v7t t`jddn6ȿS9z0 ˫1u4>9޷)yBGՁ)A lb*BBnyU*ƾCfeӨ~cS@Ȋ^˒|E&[=EsQMǤcd0'ȡ, |Y{= T]Y!:a\ڙ_BR$q:n)7&O)ei\͌\ EEE!zZ0%os)XsyvP801SĤd9:_Hj du${HӷSw+/`2!B$|,-$*[8ԩiɞ8zxo>#8X 7n]%3ȲGbjNϸ!Dnح?libYea&tR,x^R6fTpGV >O6ZH8vE=uGx1{1s]X4t]܊RqjΝA v% \˥T SL6'FE2Tv;8:RJQJqEp.DQ~>w&/ӟaH)D"a6M$n.8qvȀttF9Y{ U &N]uR|/BM E=|Ђy-_`F +o~fj= ފu}{]疏FmIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/duprow.png000066400000000000000000000016771360462764600227720ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME:_LIDATX=hI3Zs9-ƒ9&UW\gĄ)ܦ LT 8STSqU9.vlݝwFRc7 ߻t|b8EQy&i>FQtceei&ZawwWqS(4 C{{{v][[[j~~Cڟnh8>BOC8B(J)v_DZYVQ,-Xmi{ssc.Z i( LNN1{1a4ǍM:}3gxRʞ8b_>̀~:]ɀ 6b@Rf7^9b: `vv!O/ο3N&r٬l648!keJoTU8SSSnt/PMѰ5 *9X hPPVϞdZ 10Rt( !߷_'[ B~#;NnB3:}hL+G$]FRZsF4.J)|?L~2UP.-r~k/[ hn 9}zϛ{&N@2G'yи W_/' Nu][K_[2s@ҫ uRh!q/?BOaɌ]?5& sA<+:XqnCvy`rO(!{?@@1Ӥ|L}IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/editar.png000066400000000000000000000026071360462764600227140ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŗ[leN vR(m4- )5*j%!DAD#F/<܈B5BM. ,ڢ[rPM[le;;;nf{$K&s{0#LSnw@˼Y]]MӤLR8Nڱ8i}"mÎ;^ j]CCCiJLBѸߑRxD" 2(cYi"@ulFr/,iNAŲm ׽YYb1Ҁ\r6lN@23+(C.BYɜlL\@ijmp8q.G@ Y0@/g d6s?sU$s`hh"p/,mq`;/˷}Vߓ>4O^jkkȌ(3fNM-YP,Vl,+@ 3-[Jĉ ͆Z[ (ےb H̊.WdކOҹ5=@B:"&/{8| hn à( Tæ!czu߾yíS9$h.uG!?ۉb&%S#t4FpIљU9)%m*"@QEAUUEAA"au}a[z7iY.s&a)b Cۻw0M~***B8Hq`z !PUUU(GyeUZS˕.bCWdz[_ϖvƹ:sq(Fq۶, )e*bM4 3~@ @ii)@cUU8鶏ă2DQF/_)}a^(ز~a)=bYB+%~e^G-~SXؒb:~!zR\}'fa/C7 B ~ds=1xrBg6SYl( %%~N{5NGyce9G5G=T>H8\8ȅT躎Q¿k.-Yz ?=LYEMW4VnI,҅e)e, PeO[{Еv*4mJ@BH-0@9u60祔aB4Dy};XܒH`$=L9w}oFp8(b1 qxFܲpW4=*;jyv{u͞0Ќj\."@$|>G}ʥίظQ^a8P*ñnMl{a`@r̄]]].|˚2z-u,'^~z~?a yd 7IokYy?c.p.ZĪwQrOuuupY@ s)50"gV%:a`}}}|[a>BN>3HB@aӺmd׋c^ O ̃Ad@ D[[H:MĴmMѤ inMJlLiŪ(VQfADFw=q"M׷^u?Tz"C~I{˩3NO_뮷οq4@ 7\uS@*m-IN~Cֆ@$)|;a+w\ ۄS66oxB K(C&/}&7/ J[٪ܚ+eE".%f%¤nJ{#"pv}g}aTڲ7%ъt9?DA𔃧l\mh@ t:G0Erk.6{b7{U!$o-fFi_v,c'!2^TGIfg{fi^Rwn0~6cVLƝ2<ϧ?v~ATںaZd1u ZlJy7 o|=߽G|# 8Bk"FQ#IH3JI90u3} @yR 7C^Uykʪ5uy6n:<}^[y٤x<Π{ )L44 (ǻl}n9Ic~w^2Js̰? Yy]\V[1?2gPGkE2TN@O~iwp g%WDkEw`3LB4R@el"O_|bޤxpM})u vps9ldkA@Jхd4ѫa*&Wq:ö޹ԆB!*هtZq|mL?JKq5qצ|@k1*[F|v`@h!ω9aG=50 vܼ }F ƈSs]X|5ukf1B7@k(Z}~yCqUpt0{LY՟%)!\OS((.[n=+V]ĶmCx&P!?z {*S'M)WV|Q4y}LW=ևB <ۇg | P1Z /wn=*-3kL'0]n`0އӨ:՘ZL& x+hR0?'ȱB~_?x.7~Kdy"BxuOߌcx ,ZuubW=R|T 1d|);HQtp+*oeJ])P\V qr(u%PW7C/aDt?U ?87?wSݽTϜEl&8f8L, QR $l[nLM xSX!RѠ@=ǭEإ?Ձ6eE,C6"hjFIHuu<4A\Gq,FOe"}"VTJF)&ڶNN }$QLy) И,N4R΢$ O%( #+Vp׺ɟ߼x|e NA; 9kD&Z++::l?|+Ϊz"mXcϾ(lWW_]-ϘZ E?nH~`={?ly%?yj7oKM'MIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/eventtrigger_grp.png000066400000000000000000000034201360462764600250130ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME ()IDATXWkPT~srՅrYtQ76&JT&dlN3iҦ3:vZMFcc$-ZcFLU-].,׳?ֶ(j|s?}9Pߨ7e7os2QU_&>L ,˶A2/roHuo nhy*v~LM YSҾg6=t"p0o+EegO+&aC6P4CƠ| %hv4{`ynC ;v-5"O(4Ce24C;zjL\,\BzŜ9g#p7FS!RhzWQԖ*ҜQy Ԅ:qE9p31`}a}JwzVԕ̗Ph+#a:@ >m(tC@0~ĚHb|4Wp ș }Xa{{1mRhߴ,G]0G/ȨxnX5M_y_8!d'$}UN[T$@Q{ MMD`Ŋc*T oEWO(-}xd29s?5~g]F ۟(S8i=d"/! E@ |j?d=r11qҖ5O4rrprvꗇk͈3YS1,xnwxdžmc e͍/nKx:B@LCݧҲn), ET>/h)@'Lș!qt<|.w@–A U̳%'P华aiC&բR-lS!N?INi^i)GUt>@! M'{G|ayگaCak-JP]ŰUDW?.GNf>0 LSKe=zy)wN@И[O:"L)y讗1\w u4bGx,.,EtVlLP"ǥ޷平]vPBwu).!pǾ5n<&7~ݺw, =H8vzNBEhb‰?U! N"gŔ}{G $ 10f׻`ZdI3U<֨{ohɼ)xaXy# 4 0Ay[ [Б}CݧWdzOy6Q2K=jkA'&HH\ #MШY5Wn!K{wcˡHIM?QDaV?0{WaP4Ik@`Ѕv??u)゛?k>Rr`<}'Ca0Q3@(-K |Oӕis.=gMVp_F("G@Ti$;<648ɥlx>Q"IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/excluir.png000066400000000000000000000037451360462764600231230ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<wIDATXMG?gzfwg֟ډBF|%,8q D8GH|p(""$8:]{3=_Uƛ]{7!`?zU]~^JC0e{ _Wҭ:v;?|g*wi+K??ixOqj ++++=Nh&m5Q7nWL=jqCW?iA$( * ۹ES~}W_|*87掝Y,--^\\ -v텵/pSGnQfK@g_XvtPd̼lCmt:mt;=B{Cqc<0ufS) c,8f sov [Ȗ( љ[B<~agg fơ{p+ߝ(r$)Y?7s'xR{νn3G>/]5Oǣ=cqZbT oA;yURcB.w;HƏEkfnj@>0VF6o;1 ׯ/ -s @3co|,m JcX6BPJ9X Z H)3-E $)3Hdi9}e;ytWJ*#Z(^ֳop4ʪQ5/,,aժհl0Z?:pڎG_ 7LƚZ AFHiH8v$ARTJZ!BR(U8c H) q +ѰZ Jkɇyu"eP2g& C$ fVJYkm)\ ! z[W B@YiT0 mȎ=^yF$(f"Q%<7D([SSx xLYRvur-yZDĹ2l!IrIk]Z;ZZfK)e*F[ !{y 0(M4 uuި7zΞy|د`uuy}DQUGQGiʮ*n)5JY=u]v]p0N\ p4&Cy`9|*2cʶjqtռ덨ZJX(Yv<3Q9ե* @Eݳ{.08q dpĉ*ft4<RZwZ j~qbbbyy7 )a0fi@aG c( 祔"IuJq(#3~?R91$ c %P3ki?Kn eeg0e1i-)ʅDt $ZK)f56$CWk_m*<@D]GZ=p!=tѐߡ|b !7 DeF?5wvۍjGQ^}챟͞9sf@z=@DUͩ͝[H5bis^"3/R<SZ_+uV9uYIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/exibirlimpag.png000066400000000000000000000017211360462764600241140ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME.y!iTXtCommentCreated with The GIMPm$IDATXOhU?Ifg+MS/^ B\{ W=Ul)k!RZDJ -HB+";Cv6;@(12όFшs90\.,4@\nOsUt /ݦq0 rU6:C}-Μ=ݪmam۷RW~Kjh~;KܷdGNW IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/exportar.png000066400000000000000000000041011360462764600232770ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME$ IDATXå}pTƟܯ&a $# H " KJ3v)E( c;uT8JQt(b-PPB&D!MIf{=dC>3wsyy_`7&*qc[kNC<>Fyi|Ցi ?~Vk;r=T׋•`I)m:a٢wqCWgn7FHr销 z_gB&nG X][[;o͚5O;qF,pc cFz+w5m۶Ùu{v,XQp2݋sʋBx}/0h1 SϺ7-B)%ǁm#+JkSJV %!PJ W0|9}4%BD`#+fi y;K4mláP(߸qvqSsp]nj8n[߭얶o$9rx&$5ޱ/\8O+(Tb1d2y&"XG`lۆi;wF-mò,ض 9 !( ۥBJǞ}K[>_NNs;kMDd;D?AEAcc#a@z01n~<ˋ, C&J o@ҙȗk@ֳ\w U U.M/uq,IA4xb$@(ecr[ cMlLc$5آn3~Ե3]ӹ*9HTY_% x, #OҖN8.0*PFT<tE:Ң7hEy|nIA(?O/:+ǩhkkC*B2D"@o}Wly -~Kߓ8?)jY~y]K$#..ip7)CԕLdE c9@4(2TjL~y<t]3c1' Et9S&W I6\2=R yh47ey JJH&a"p:HpۦfRڀkuobh!GJ0ͻP%d.œ! kT t[ě_X[=B"8Vt~Rkge:.rń@.liRO}ShҐ+qh]ס:'(Q ILA~$,M7jǞ_u9UNB-`_ttE(jC dX%,:98OJ] o8lH1 u Qu3Ύa@k6M_O1w,|pŅ،Ӌ+cRJIV1y0  g7wY+8jժ ҍH$x1F rOsUACS@IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/exportdata.png000066400000000000000000000036111360462764600236130ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 6,ULIDATXTg?6{a,20 AjƀiTlD#mфHQ`m ըAZ"݊`ofefva[z7}yߜ/̙3Oɲ|$ Q, 4f{  .@Ǐ/A۶=+V`f( **64MkZMٙlr9Z[[=i~g2~L&C[[OMMqĉ `Y%``0*ϳj2vƝe\b+%XIe]|``bb4=e2Ϝt:x:v\;{8O\cH@ WdYСCKGFFa7FE5~M} }ƪ @2IJ%&rqX,XH$"'} I[nucEQ< Ȳa@"s_#Ұ~roqv DŽTjNLAw0,.r%?Bf~`fdA!oL ٯ?vwچWa\V@ @gg͊:q%$yf'c|S_FèQFl7^FMLE۷!ZfSEQmiݏ?κ>~4o _Ul征Gk6CfZ$ Xr4۸o߾/BSd˶m4MJ$f5 0d]QP(67S\^M~1880$+h*R.\Ljkd7ʩ3@e8IB9)- uɽIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/extension.png000066400000000000000000000044611360462764600234600ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME4vۮIDATXmp}InJH@PĊNTFuFhԡhѩPGQ;Z:JBLT`} Md@^on޽ra$@;oݙww>?!DizIuڈy NM94*c;l[ ܘWl#|!]GAhp{mCV>1ov j6S9^{8S(ʍ$.- "4 v{<9P1[{Z>]9nuر |ǫH&nra%*l@J t1'o?I= 14Z};u;𞺋%7̹K4dG8(D!Q %(<ӌG(&A&5J4#gwV;_?B=x5\{̭UzؖH)!BB~+Rex+.i3Uc[4G o[xDE⺊yBJ`,R~ƵB__$3ĜAl΢CxZ0u)6x PJ)ʇ9/P9eh%`w>h(A%TEb N\fPu A` "2v/p7戎4w²? @jzND%nh7P x tp(ecFN== ^ ̞O't$ʀl' U"Da(gkd3gb ]V<;y B D ~WrNeN7c!4$\t:ͩ]a i&00 !A(-/{JX^?!o6ӧ" \M+gVYgÆ ϛM(Dࡄ Ce㟡╗wbl.rXA8}{xɺw߭bڲeKcn [nM(%j,\09v 7.!:JBPZZʊZlu]144S~zzowq@%@:{MD:PP(D0 a6@{a}}+#sQ}+e#d_DQBpP(D<GJI0<u],%%%H$@ww7[l9(uod% Q|w!ca0<<̫;#O+`Zj,,(^lnnަz3 `{7J9lz;Db$Y 2 @6m4!}ڥS'V%? 񚚚3]ҹ$Q6qƾ{&bŊBxD"z}}bxӧVR+)0#J"`Xv#GU]]}pP1@Dο')**:}}qjoڵ9r_$=߾eIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/extension_grp.png000066400000000000000000000046731360462764600243350ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME iMF HIDATXõ{pT?clȋ"B H@U*!bQ+>(hm:ZТq˴*JĪ`fhPC^ ƀ!A!Yql3ޙs;7T˷bJGZ Sm;K?swsV[Uunl~.WLBn=_Li` PʅSU9{ǂsK*nh)ȆiO~0UQUSZުHHTʓCB^ylX~C~`Bi EQʛaW^KKilKM@9֟>< 躳Rp7 oݍZPAPѢ;cbR&&Q ^@ildkՔo=/eŰxm*6eEWBLA+VNw[#{rr˄Y\jhɩj^LDFF1Ũϩ'kPHa謅 WO:N0ȽD<|&UU&f- WU Kavw Ȟpم3r *:a@UAi"*4l MAI-aH&e<+;k%/{ջVcHEQP$;o*.L;ƢH$x9->O:)n SԜy w<4!E~OW' yS򳏃ҳHS50j4P!&A+ Nlzokv $ 4rBw"c'&EjAVDTSt{]ga $x[4ĢHX0/$֍n!G ;X0..-gjl}v+ђLF)7#b bH5!¹)6UuVRr ͻ;jnwɺsU %By>hun  W %hj$ -iİ6` :3^~V3"s3b%,0o4fUUzD'ŪU ւڴ9gatABS_EP;nۚC(]D?bDv)8-RGLL͛Vzߏ w;§0}tۿ"s'*c mfz wF{v^Ad= ݍpi)_d\UC vkW{s(}>+WÊN-۾um[j8Q)cץh̛DTU>pMlxA"q 3&bPd(aC~---Y *Q(ԉH5A0D-K ',6>:O 1MX9n d3ѱdffRXXxɓ{;;;'`hf=BO "GBMh`ٙngkɏB{SZpn[,X`xZZZ;뢲¤Hf%?È  yD4bl*yRj""1XiZD|b zR)#H)p2^ܿ˥+nʞ^AŇinf{T^JcHAbX0E$!Bq:h%:;;!C#++z:t F] eO`u4av֣NEM5'$TMG<ȹG ;o%%ypm! R!NguEE)e˖p8HIICJɫ a\EA9Xlԍ7={f9@<WHlllz۸koҥmZ^^>q׮]S m6ףxTIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/fade.png000066400000000000000000000030011360462764600223300ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 5TIDATXk]Uk}}LvI+ %5J$w,Bi1BQJBK" 4 (|JRةV ("(MEZytt;δ>\9Y{rݍoc<`C%#"p G`VWCĴ#n +KҢD_eC`c9YS2s]9oƍ&"`(l'?~pL}ttt,TT|ƥIbm[g,fPdխN3ƲuM-͗s2sC|\4OQ%!qI|/\z+|@fznrTRiM|m-__Í,0ڋsn3@n} {.OtǪw g,rN9<֕;%O)Rohp֊u51;Um<vh{>KWF`*$Ms_hc8kMHia0$&p7{6|߾P;?;7r8KD ?IY2sI7`:K%INR‰Rb/h8"5M4Ϲ3_K]R&JJ :yP" EFFMYE;4@;L%%b2ל)SpM??N8XkY0Oe=!\x @ORb-WR9]9R*={jsN^U$)3!W@XYHD&l U Hi ?UT2 jdifNT^XUPhLU<+QCIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/fadein.png000066400000000000000000000022061360462764600226650ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 5 KWUIDATX]UUk}2wtr(')*A!Ï$2s(|/!'z >%"ڋЀhكFNu{o8w3:י.0d[9( ZMLtL6Ygׁ9j%`-a'йCGvqGpK?+ )'a0D&\)ڗwDfMӋTָF)R_a*a5f\jq{.ȗW g# ʶP<a*ըBr׆ޢGQ(gWx""YQXh)w"rRIRɌEAxʑѹlonD[[["H|_WWW3/0ap 4qz{{-MMM >D+xBK-رBkJ6b>E0 Avr , 9Ƿ>UVl? 8u6l8* X[gri[۟]Tnz10t3̺y'i\]nndyŐcF+ɅYҲ_XvM 뎏H Dfz=~u[I%9#MO6uk~$Ki b20j=5_&D XCc-%˪?7lY؛b>{ C}(顄B*`q 8Ŝ9skrݧ/.}o_)Jj  ` 4,ɠ9G>')UoHj>^/q6Đ!mS_S< s ˒^.V* t?Ph!|_Nwa$8B>@x^ss;>Z{`uǫ`w13x.actdj/,ٸ⥋jJSR-0aW=9可@1v;ܰjm zSr-c M&{.Bjb'UMg-twYm,0 J)R>R nlfW_ݛH) NZ Z4"|wO97UX6mZPUUeJ 025ZksO/ȝ[ڃ ZkWN߂+*_|ä+76b+,֦'hy qܿD"Q򯊸OPm p;W"Uv54`f2KՅ!f&ÚF?XX8R}@i;'NPw(Ix bou5TU%N0M Sn+ɀ ܸΆGFʿ>.v^TY"Ml[בؚƂm+ {#^qbobybGGӬٺGU7۪GKh(躼[vUQN֬ pYܸxB>0pV`7G2{8PZZ>՞s_HOU*1J\LDouuDV䁛|Q`|cT QIjSãDBߏ9]7r~#7D-Duwv+ƛ:;ah7@ۅ5 p_PUR<#!D^R.caD04&B0d=4N'7F";l04mP@1Yr_0gҨ DDtHdC2LcAlɪ\a7 @MU+m$RKDQ n7ӃKl zI/Fy OCׁwѧѸ ŶY缐N^JȧӈB!?ţ!ۻnń n[5F<>AS0I 6z6!ՁX`(J|X ̟d7-4|8U@Ձp79dzQUZ29eޕe~z2{&2=^c%jAx`,"˫.׋!kĭ,s6Ɯ]dc2y;#Q83-ܦD8 |?iܒR<¼HҘ߈1gsvj291,< Ҵ]U9 vvQ[MMpؼHTWDm%׋_<| 8Nbk@CoȎEƈu5  ...-4\8==-eY5Vx|YӴR! 60cݓ(_ ‹yrF EQye _jogggDoo/ Q*~$IL>xXXX`xL'''D4\H*K !c8<<1111Ȭ%J)]cB~Bf$ (;ܭøýCc@$aʴ3&(0 kuO$AEŘJ .L&9 ` !loWmjj.UUEP@*v YQ%( 0D;.޾Kp/u,v] !XYYW/+`4ưWWW122⻝YUnNv?:#TzncR㭷xN/ߥV&~AD"Uč|_f2Z\\tK麾@P<ad[~]ADB9zP3,4\]dIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/fixobject.png000066400000000000000000000025211360462764600234140ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME LIDATXŗoTU}L>봅BPB %$A$ _c+F[BlB;eg:sm^t'䬽 +9b ->T1 D,GK^Nw m!$ɤHEx4GE+?9t͗UD"qȑ#Be/0 'A@x@q#Eޗ))B`HdtXE]U<;&u5BC'/PʌRbW5,w/ٹ՜D Iq^ KV !\("2.aPZ]2 ׂ-PU7&SE-E5 è&3$eR3`1YX,vLJ!"H#5 "b 77^||yPWFt D7(¢C&,:cZ  DN<X3jk< :ÏS*ilV3R  RD1([ Y0 #!ZOe Lj_|{v5q2Xr D0")0\:h@UGQ`eQlrHi:~lzլ})ĽCU}ίW0G:62P6{7Vϟҿ%;y͝1y 9 3@޺=> oNTe ׸52'3 rN u}_ﹽ}{~%5X^O&~Q13{`yv9OgϽPݐۖF\49qpc|\ 0's=աGbA=|LBEuSd ]/@}^#oucGKUͫ|)Uh/lI@C$-r"_k 9 Jt?x"Ai[ ٣\d_5H#scn@kX}ܐ3nP(/݆xp GLԟʅĜ3У>нZSoK6_L}1~[ds)n0ged@Uuh6Êgbu;qy?^pt|ZXwA`H5Ce  ~#+ԇvw7&, ac5~ X(( ApHۥ$'_x7 y$~@9O0_ I YpxpoFTNmlu]bP @LaA11ZF)Aߣ!{f[Q!f- Y22`Vm)v)f@0 #8e?Gw0\Hk H!b!P 420*Ѷx9$dMQY"@3U{=cf&<^zt 2<x#5֓d8vIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/flag_cuba.png000066400000000000000000000021411360462764600233400ustar00rootroot00000000000000PNG  IHDR szz(IDATXMh]E3i VZM+j].ątJQE`VD, _WU\JLƪ$55yqq?}fM;0;9s3p}\P(fLS24ہ(*yznk8A)P.DQ@F)E;0ю- }Ո}P 3l_ U&uT$t$;]K"{RV o,Y6E~ PJDʔ<٥) |(@ge(E<MXD+jnG~ם:J\JQ֑_6v=hW&t(fB m|5C,.9КKG8 ' Q4RɷxbV:2p@H!^k`mcU'h2=KO<)E:N AߏVvΝO~`tϓܺ}+;W0|59sypǻn<^}Z; aqL13Dk\V̊_t ͥNuKepǶ핅feLIg$+}+^KZ]~Rt01` ^n~ЧƓv\Ofu!Jʽb3Z Դt9V(eݮІ;rtgCVtVG%Ү mB/p€+T4|RUXi,K1>e4wcFZ MnW->s(P&Bd޸-k~ p@9IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/flag_ecuador.png000066400000000000000000000022071360462764600240530ustar00rootroot00000000000000PNG  IHDR szzNIDATX헽TU;waʲqׄ@QC"5F1@M6ɪ! ;}-ι=;]%$_Yhb{[: 3g0 Dq] ҉r}:jrTsL'?%@Wss+QHXW z{<7UGp $9Ǔ@-ti>F#bpk1ip!a  rj&QHІogZD:QXjjXX'ݏǎ~oͥ9<ԫ+)D"!F>-T WVj q /plu_a{ `%mPMm(XbJ2 ?M0t^#: RVϹW=^6@<I&0OFxNp~0 miOQ~(C c U((KB N IC@@I''{}>WwRֶ~HNZ}4[ ^~qICĹ{^M yC;Xnoƥ^˷OajcXt0~O$qʤֹ8:0 ^"7]+g Y!bt ! L %/5L9".|1⯺b sŵ#{,;r,/~_U V 0SEP'B"< Gsx2Ͻ)c7Ǧ`FCݒ $+58W ЀT/^ߜyYCy%6Z]z"Hd 2 lEѻNh'vf؆z_,J3lvooBffdy9"**;S:~쒑OS9LH9w/=͚Y@U+U"-1zlwSz>iKp*"UG6*Rf#H`Vw4X3wF@s%1O#5bYH ߯pXfm %*@/b:#IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/flag_france.png000066400000000000000000000016071360462764600236720ustar00rootroot00000000000000PNG  IHDR szzNIDATX햽E[=?EH Y DHDdHD<F~$D"!B`{gqPU==?ȉ{9*xCYWW+9עãk|5v*,ÀU 3]t=&<%< z?>Xw@Ο 3 Ʒ_<m4_½u ӦO>s,ưO`3q DN a *`Kh WC$f$k 7] | )cu]RR.wmxU)O,X"mٟjA*"e9,Ku/\3&B7?db ' w D"-cj90T JE|̉Xd{VC]rj z: bL‚Z nd>5ݫº܄119;4;=zSשfVtS&geYͶ03tRbBZtfTLUP$Y,D\f T P˗S Td0s `yS#A R$3II9'7Fti7lUPOM%P'<c$ aQ{vCлdZ#ݤd3= {:>` +@8R993KoJՐU/6!n",,v_*&Ax* ;#7ÎѭV+RL{mù4@ƑWf:^<Ja}8o3SJjIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/flag_poland.png000066400000000000000000000014571360462764600237140ustar00rootroot00000000000000PNG  IHDR szzIDATXAzDji쉓p-p#.р-e'nu=UnfMߧiI#^ze/}f믿\eak xk\0 +R l~M%\ M~Xݝ mk,$k R{ur@ `qE$Zy8➎Ϛ7`<`'ۇ滶+@'{Ywvf;, P:KgKZk+b{g{qD{~۲)")%=5W5KYX/XIP$q#Arኚ4oXƜh`(,mV=!,' pa1@@^@>@,<@3~}bnP+ A=LV<".pHtuڍH MA-] %{AG#j!3<ČY0T?UnɃOm# ~P߬=Ӓʀ6LMB[Cm:;W>=1&˵fZVN)#'bkRgZBYVKj {rL{tD؞$3vu洬 †q7(}0Vʹyjr4n^q{7gusvڃ_Cͫ}O xf/L6>؀ /b%HIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/flag_russia.png000066400000000000000000000013051360462764600237350ustar00rootroot00000000000000PNG  IHDR szzIDATX=o0;Qnl';eЬ(?5!k:t%K1E:)M di0$Qj vJEDև'f9f6P?UEDi=>3sq\/83*f6B%T QdDDrN93j J}oFDv|1C׾v?tL]./{`*u(SILƫ,p}]@fz " hHzJꈘ` DzbiA3s$H5D@1(M"!ރbF[l!'ߑ N#ue2"0MO?ٞxKeXSBy_|3{?"4"hQ-1yyS{31o|=H BY: E'Vdf4 ӈ{US:f)Hi;hȵ.| Զ<0s)j=K,;`q:=OIq"c0͈`AIVEBd<54RJk1˰^ bUdB so kH<)xA!JQm~z_v'58he: *3&[Ĭ1f 1cXXpXmKwq_wC3x?݀k7?X4 *=yyZ;@3xmxU¥+e[sH=@?oy͈VvRlwo!Ab,*({fҪF(: |9Ϝ:#I4-v)d`WU#!̌۷a}b@uO=,a|k5-xv=*Xl>9S@E`޷.)"s^su=l{EQP=9\0up$#> 2& ~!MAEZ9@R%2霁<LSH<̺>\dpi`0`41AlA' "Xx#y?brN^IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/foreigndatawrapper.png000066400000000000000000000044671360462764600253360ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME )IDATXkUo&w/(2VAhj4ҤM4MkF7RU28  0 3s{W(8ښ+g${o,\ܼ9F+K =_"kE#}!S u6Q a6qʑt[B3οCx<l.t]8Az5HǑ124%Yr9.l)%(ly"_3ڞ] ͷFZ"?b #l(JQB0%YŲEq\WR~u]בRRSuKf$:ܼ9o.d_cnZG4)P#Kww/KQW~v8l۶QJqmy5iko!Y_'A9z '{xO<Žy!Xp =un|f + igچ&⒊q=ŪsG ک6^]K0!"=l+%V6O ,ihh᷏h"MxHG\Ñ>QIE|r @zғ`D!Zv"(FEɽTU{%)Tq{`^J gboX +x}qz(>ͣEլO! wj7gf4u ulݛb΍QS\m7,a`hv3X\d?FByyh;&%;>7xB)5ڥȲ7xB7Ok?8ApHue{.':2"`CqU/@ 9&zE--[sYS8ثL&C6%S(hmkǎ7+8W G! @GRP%'یBxgV'Owd&fjLr.^&CFI}2GXOߺ8:Jer O-؇Lr+rBRR b;\ `ю O,]Afd28҅5ZrKP"w@%'q@|g >uء^b1kpP(R(8ʺ*@K%̣N_j+{hup d%$|*J D"UrBI.#:MWD;"^g8w]xޅ^|Q}n:;ϲz^}msAtvÔvj=E4Ŕe&A[_\zyXm۹,_9Bdx2M".s=A z#'ofZ|NzbuWVx˖Kp$Bvvi5|ksb"j-vT/f/}&FS0{Ӌ_xqWM9/M/aJE%Qߺ:hc'Nrr" ]=KǨy yXh6ja+=M,WDζ ab4&q 鎙jH"Ĩx4inXV=:bx[vl|Lv檗ur̲\@E]++cbJB"fJȄ=,[NӐHBCukUvcT?@HN/_>LU9(3Տ')Y?S Y xRt z#w^`x@jFIu^{{[6yԱL!0lZ5[;X!rgB:!n-+8&q% ܸ'x;ܯdYd2{a D& h2N?hI71*x<~uh۶F4'Ni>322u xɺx<mJ8uT\q~tv AԔ2]d25kt388@ͳZXXl(٦jnBl>]n/Rq.ۍ;GtcSdժɍ{ؙe߁~mMQ,klK|OM>z~q_^uwO!eN AQA$yw6OdWp8֦8oKKK Rh#Y_i_c}  /qޕPqyyﳻ7mmhrU2 RJ2mg+4jGCAeZ;QN8ԃyt&7$B)%RJ,TX!B?h@Oz/R(uAٍa.NLi1W.^GJ8(:nWJ\KޞEQaUKb[bmI;yZS K^ m4"TIt`lrՐXi;ﮐN);Dԝ+cߩP,ٻ-2},//3zy?<M V+ˏg^sphzCt:<φۼnJR&<"]:Uuݷ^q X;ݘdrzhYa`&'hNga)1).ʭW"pXlRk!"ꁸ" 3 `J@X44ָdŚT*@p¿WIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/foreignserver_grp.png000066400000000000000000000024711360462764600251730ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME%+3IDATXõOhWofH@T-CAbKEݞzެО%)ZC1VQ&ݍI&;3=Ԥ&J5<}#(&@~+݊3gΜvn@ P<{]|f24SԦL&MMLg 8\łfc8---)/IH䍞xI447EQv4͒V'Oh47A&SLL{z:V /0 (,L(x<\\>UWW{t]e:55ѣG1 B@t!Nױ \G*BʵH333cCCCbG~BpS$122rJ,..`=65h/'c$!˂LAȮY҂."넖 gY/K24:¯3[AOONWBXpsϪeA4P(D&%I0Sy5mAB˫y=-A%5kX~܎$IrLшY],>#N5J=Vk&*0EK, %K{[ \2 ~g‘2n ෯ o7a$!h\`RFUHMM7ba, v_RΖ͋/7v}܌<#~]9Ujm;w2$/mnyucBiׁj$ҏO@sE!ȈkysH7>lּeQ˲xQ:ZʲEA_yJ|^q]Xy5i=`Ŗw7G͂{QJ \݁-h fաw4A:BԃWEʪGQj (u;GhNe(Yh&_~\/+ͷaf.'8T$ʶh@(P҅3ؾK<#t}fj $cl޴Ml[3(`r ͼ9Dc9Js\,!O[@ܠ'B($q\.GÌIES`(SBYwj V9gSY U~5w#,ϣo=]g0<;>`4ϯ 7^gVK1ضΝSCĢ$RY E7" 24" |B4YYq|ŏ?0 9!یs$I g $Qr83|+-XDh4J$;uTD 19##r }^`}szB]mwsݙׇn[$'̹3._]uݚQ|k}C6f !4q\M5ޡC(Vc[+MuMɒV*Li^^;ځ4 =ȼc=T;}}%WB$0e=v>%4er?ttvvRYYm9rDk6(j@ƯR&'&vuub >W>IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/funcao.png000066400000000000000000000045651360462764600227240ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org<IDATX{pTǿqI6]Ġ!D4 ("QlՊT>f:NZ_v*E@F"$}fwsw$E3sf,BZKgH!r8#rk_R}ceeQ$3J;T }*VL'.(d@cz}s'#. &Ȝf$yd֭Lݚ `-pU\q`Oz}KfL]g9djyߕok˲~1oWW}Iy'[eCMFwiqK~݌2"Hb;2ၳ}Z.U\DePTaA|oxww|zӏΉ(5TJ7[m> FB&*gEN+V#R0[\ !P^dw5W܂h863d`\"v}788߂E|D,'q0J!sBhק6]}ᖖ7bh qPJ!0vfOwAl¸+cmΠbiE8v(in]rj{;rT`Rc}cf FYA*\Xlc{_?8ŋZY  SaH91[$N?l@947էhiUMNÚR  0<OiKؿeC52VιeU˫ntw%pBQSSyWw^0bѭ6T@8BK+g=WT:oWټ*uyMM)Tpl>6YDQF T/w>Zn9=]f7o]躎`(ـ>ر/7L]>'H<'Y(,U IbqDQ5 Nvulq+2th]ӑ4 =APB0gV |Ih*VF_> 7TJ pv ht8l.])޷RJ %IC1k::qR̄w;&#SH [`"jH\@갘L2u]9']8?4]@(8tOYj>ׂy3%.;.p/"Y() CF6Bo |иMٍz-%Bt!ƽH%3EwƦ^dV%7/@4jֶßALUI+GxsS}cy*sęV Ͳ̙uuZk/߳ۖ/;'$[h;rtp?^!dA@`6˰ی8g |uvWHiݍ.S*d`$MhHebXw ѡh?=Q1 MQ^\={j|8asSXln%K6i>ùr%&F d&iW>0 Ntvz2E?H|osV**6[OB'߻OHl2TT|깧6ϖ `;|[= WPnmo/ZOŭT!:jՆzUwF$UUoYh | Z0j4̓Ɋ)_W+1). Bmᗕ:'IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/function.png000066400000000000000000000046601360462764600232720ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs : :dJtIME;-z۴q 0IDATXýypU?˞bXTE@ j E@T\X(*[v:NgZǢRAԢba1l`$$?r s9{?bk@ H:ye+ԅqc1c&%Ck_Hs5U7thMC yt߽EL9p1t khcNh:v-Ӟ\_j裏- (±#}xz/g訫7^1`ɟ>row^,}{r}.׽[+L,/7w FB:\w6Hq y-aR^kZ+ʿzl寜-wjCŗwĢQ ,>-P!zE&~E(ء<_hn̺p¸+ǍHWqH!ЅdҤy7y  `y=CQ$PUcv5յSJWm4)pU+dfȿ(]߱ԙK-JYJ1}yl^ 9h%)²,Zx=Nյ!;|pGr7XE #0=N‘8B5[8uXcSEZ[.ցq su +IdJZ$I::TU7!l/\pU.6ldfn)xumw#4yMk޺mGR;yUXI:BhotM7͝k,e+ZSLcIV@[xnȔeOx,T7tb%Rvz*= C73SPhm BJON*~x"DͱcЁJ6umHOK3؞Mw0}F1^7PWї Om 5=<Ų!P5/+N޳JUFH ̔]v<$q@s0 !rYچܲ_O?wEs9NcTn23M}׮]/e,KvФ6~:܏4=xD4kSuIz!p蒦f+C+a`_~_o;[ښ6&+Hp ]tMg;"V#0t !Ŗ[]]  i~7KVIOkk *v 8]4)=W#u]׌2|_i`a7Y"6z n.ec= |~&-D-*m8aelPoTL_jr7LϨdJkz ._t~?vх_Wp9={YKx3WM_?$޴mgSKk'O3 }0xu{7þgHMf/y~rтG%V|<2}#J5g+= <抩 !GmwV^?EM_Z^x)gۦ<} B{.߀e>V'Q3g/97 Z N`/ҲfEBȺK6TZԔo6G74Lӳ`*Ԟ7pf̘uo?eXV]ݑ/6v$O3la, ۢ{,Ɇ,[_Ja#x$< $l &NK!`?w\CD ۟.[9B~Nɣ2IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/function_grp.png000066400000000000000000000046241360462764600241420ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs : :dJtIMExp IDATXíkpTyun6lv7 @.\ctEVA[ t~im*Z+Z-*N-8ĊhErܓ${f{N?2f_sg^-wlTd%<.m1"sG?x%1'5-*(QR?7߯?~w+`ݕo$}y`SV-!d!P,ohjR7>Z2l};/FSnA`9΋4p,#B# vət\*w/AEQҪeeΪ @"H!kRS,!$ l,S0d6B,G)xG)pȤ}=b0Wa ȊQ٬p8E)vC^jD"!AGtZ*+˞(fx}h$yX/.]}OfEJ`Џ#Jc<Y"u/Q^e2VxC qvb|DzHZ026[ gi z\^D#"P`^yt\sEn76k~"3 P@u9gFd> `=0 i//[%,/ #OB@"=guՑ*F2Gǻsd7)ޡrU+,%ZR,X@9+e+;~ 7S^=tRj8I[oL݃uA%J``Pe) 㽏F%>~cnym&D#87Ʉ#?9MrZмj#k^TQf-G9d<+tM[jl18iXyv^m&6,\@*O?ahBځk%T3rr'bkR |/D]]l ø>tr㊎/%0 NrCCCE'lN4n馫c'(<t!^333CWWapa,6mv]Dd ]?z۷o `޽X͛ioog~~h4J*d2ɶmۈb<䓴:k[ѤѡId-W ";wb1t]G)]1 04 qp]qطosLHmC=a D -Ar޾.B+E<ϻ(q(**&BuV4McįhIuPK(V|$PА+Z7duB.3M, BaRbJRa&VbppK( %7=Q~9q iD"H)/iF9~xC2MD"AYYop̣,Hl(_Rɱ1$h)e hB@P@4RL>_&Ņ5@" 깬 l6|={l||t'OL&ijj4Mr244wY?B]dD BR(Ϲ[VCo:h[[[muaʕLLL hkkczz4QJ>RJR9r˜.8} ƴ-omd6}=1|gsϟ+l6Z SSS LĶm4ͬ߰` N|sb@J, P?7~)iKzI>q8F%ɠ©QXB,HQT_/%I&z0~swy ia`YS^^N$!F0'(;@>R|4$1 kmH$?S}q˲,#DGGRJ9vBG33 ?oq2-WD .l3q pE~w|ypp0077*uggg,k׮}?x@0 eY<^/vݷ9swW4M!_0nі cޞćƷK*d2FMMd3gμL`Y 1vG7w=|CF*+BU㓳fJ] a3BRI"IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/genericsql_grp.png000066400000000000000000000035361360462764600244520ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME&IDATXŗ]lwfvیK\ 44&Pmb \ Ux@*jKHSa ڐƂ!Rn .6_Yww<㙝}0vL.̜?΅cAccj|u] ?L>y訬(vXfx@gtEe%H)RB|!0Q^ʧڰYr:̊37LlZh4BEUaNgYF)[)Tf-Z}BA䟶l220;ށK3̟>ޡa^źUH)+}Z1Ν?rIu<! "s\iEQhKS :eh"BS`n~\)PEuO:^QaE'6dJ` ۷wޟ]|;wf4MCa?a~o֮^*AUEI"ГHAB`j]]]{~Z[[VWW*pp)^F(B4OhƜt]'q%]]]T0 dӦMuHH$B0D4eŋV0Ml6ӧYv-t'NtRBO8fw3E%x{^9ߘUNYT"tb("-`l۶m-eCCipBijj|{YV (qeqyNfQ~dS3"8=˲*Ɍ3qsn=\3o>nߵs9tIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/grade.png000066400000000000000000000012351360462764600225220ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME $!tEXtCommentCreated with The GIMPd%nIDATX햿nA]sL{y  "DD"i(h"D tԉ웡} ŠJPx5,*quUO7 ''Z?ãWq?<}d m`0{{7n64~,MPE%**UeلӦ\`4Px+ YyKւ1̩*TUEt]M\E͸:@YsAe$x`%c&l$Ѧ\`<? vD]vKǚy咫dY6}0 UTEUlCĤi*.:@ubWۢ8CeYuśuVY$I|֔烥K!@pxacӌCR?%fzD@ǩ(~xt0mةsVlkVlkVߨةb[صb[صb[صb[صbۨ/~QnUUV[Q/jg`IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/help.png000066400000000000000000000043141360462764600223710ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs+nIDATXŗ{pU{snnn޹ G^"D (Luv3:cgӇm+}MhV)vE ZÃ$JBBrܳw8$i359wo}kK^Jn]ّaFCq#6z_qxHCCmh[mO1Y+披Y>AXke<z h·!\(OՌ_"8ap$MǟY^:9|O>[O8ΆXm}UOIX~7i<ۍ4$!R )/Zk,(d-WS:'X_},>V|hSep'{K!Lba`)1 iHCr)dҨ,+Jpɖk['>@.7ܒn=ʞaibYnpmƤIe0${E\[15ˊ3}sCC-L V˛vT2di PQ GnV:}aZ?A(V V$lݛr .^eûGw47߼zÐyL,Ϫٜj'.IIa8]0rM x]meʻm<8Ri;@LO(  3? ,ebY&4ؽ#4pk 4Z6[^],9K'A<s4 [q|?5; s{Mi \|?$!m\ttssʢk-n^[C1N 7I0xy,,ٮA)1KI, ƕ>!ŎhU45d*,$4ncY N"`͒TZs?ek֠¥!*K Z/ gN_n=Wrf*2 NsRJc8 4?2@m<\tkO nhg0iN`%1lO$ Ȝ̴Td7H!RLc8Ջ(PJa6u^1;NoLR 3S-HM( @ χ8I).+I/+82DWedR/G X8/Թ@ "UfRӍJ)"):{yGHy"CݱWt.MhLB<c4⟲ce=)HH5<thMɲX;'5^>֏Ra$va|FC~Ebu47Ԇ /uMuBיS{4VXXұDMV([9SwI۶d>c|?XWN՝pS">1ĄM"amlN=ZSFia.}wl8KMMhN3\ܪ, M=(ZH"kJs&a;>h&a+D%l]]JV`W}%훪7҄j`sH)q[fZ 7.%h` /5շ63 8 fW[FUK .+ 8o(@v'<#a,([+*0>a_k:v=>>gYHx|ƧW~^<ʩ~Z O0# 'K/\8s0?hSw{p_t-D ~Aov;7,~k+W^QˣH^w~Cd0,]k]%1*&\J1bB9F[u,@$FD h:Cg0}SKM2<6Ixu% ס$mo,7Xwyj!x-|O;J<^^[n]m>Zx\9FP[~_5+RU@k @ULe==Jxk1%%1W9$.eqڛXseW/MI!*%{w1Q9ߑxT @-n۾ܢǞ^E|Pc-1W1ڻl]ΎL2 D@~@`%dK]Uu/kSw)Ύow7pzSkgǽ?D׶huR;^|~eq BP?>zΤ0)$R w"fLր%$mM|vrl6TOg͝l{鰍}Ҹkw~|ڇqi.vqWtl/O|s56Rp =O[Oax<20z*J%Pk2QJ+)" #cSɌGGk-1Zn[㧛cN؏vޟCvjB/P>ozZk;}i6?;^{ S Z"@恑3i E?izN|~ɐ R nX!\GJu>u.L_ۿN{O|m>{7RUQ708_n>>H$GJTHR@a!#Ց2$0@F9=ʡA-l2 :\{^9+ O,u$T/6mݖZ*Ks"`9>0Li S% ",/$$搈$b Q8J"X,Xr&i&c/ hWpS›~'z?GI|D,u u_|ԧ/.euYy,_r*qGa-;2gN}9:rAJ 33*:gǘx\%*k8}#s]GMu~/0 r'Kwݼj|ߐ9o"7B `7ds>{">}s I," &b{ov9T'nZJY2kmݖ`?6 rܽjl֬h,홡4o?9Y`"HrGp{ņ.XڰۮiU0,בh!Χ&ܰr.W-i!ӟVcg-i썥 v6ښ!(}sП&8$,07)XLɬJI\B;hltUTe$KYk{vZFkK`Ύy`o]龻yT`b]dm|ýQJL[4\Dghg B0=>=<#s92ERpUDEJEDEk-Y^?45y+6T7K-uir7oJKҒ8 Ĝh2{i,伔%ϕ} ;1֢$:"8()97B.L}/S);( mQyDaq{=ɒW~auQ`41cX]]^ S2pvs#P#DOA2\$"ގ*NYp=mz&y%U'[CS>?_-jau 3<;`hmBärA;#y8B(R!J BᚎzbxLf7AJ 613gBqPZ\GqE{7,'<6*[x8%cRhҺHru #EXk-FO]GD?PK =YRG2&4w|׎#- @beH 73$eP3(}߀Kh*p Ҹ'DM3 1BCU k.#W>ڱ!&-msȻ$%a*?X@؋'C=ҙ($ "?px (/L`cbik5e1zz2ˑA|mh^a~xI?Ӆ(r11&.o=Z;,[ >1Hz2Troώ/^DrB`w:;'k,o,+TqҒ_ՙ㪰h"Aך(![X*p_N1_8}3`٫b:/ rX)ToqFMwcS O_LηP-#!=#0kʹ1(d؁]>oed=zB*Qf'ߛQRJ2tbjq1XqޙF &oEYBRPqYBQPXcuP45&Za_^/Pxڠ${#5>5ݷ xMp ry`/2€3[;n"tn0`Ƙ !0fF UsiU1)%fϡ>z#O,81oug[_:™qds>wE<qؼdgH)Z)xU`<(Ƙp|[Xysgqyd=R3;J>ٳ!w|KEP`E|5w~]<8"i@ O -u!6fzgh}^RV9ORWݷ. F}{.1I+y`m_@P[8ޔw;Ohyc O:I#%乥9C k6:RMMZ94$&'?C&uJl4 OP9>O@gw:T%`DA8 zA)@k]Ba̩O}U)YRc/rb|&wӳ.e=GNb-:wQm,bIᥣ9nj^vIT3pnCib*3V 9_s?́1rgݣeW T%ab*ǂ*˙?*2X l0oMcǟm7H:wcWʅ&ȉMY>v|lVWpt Lad~O0Ldu) @(Z<͚e-GT[yGI/39b?{Ec3tlǟeb۝Ƴtռ҄=ӣOyM*OA ^$svr!IY£o Ksa+ŋW:ׅޘ#Ig<9P("6ɵXd ;!}?;=Ѯ3F;zDžT ;NQ!X,o˒xeTTP.t# s.5H: W1EuyR43*)zk246֗dFOOG,r71 "67|ʒF6X2GѝWYe-ŋ(jDFU7 { Ñ713wB[ φ=7#YpxQT-زW5RV/kc \֦jJQai-X7㴱 N{:šgZ'FS{' չPsEAwO([yMnE-ZįmYVfZK{K--TWP pMX|mdwFƧ{`wws';/7ҿ[O Lqy@uFJk_hZnTr҉4ԖPEMeIH<8?4Mgpch?;LscG8`l*_Dp17H7CxE6+[ 4",ϻ|V=KɩtށPEP^Hl.:T~w$BUP \UXwJָN,)ݒ$qNX˵js&79Sg W#_X= $,X3]m-|o}xa}~CgIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/ignore.png000066400000000000000000000023421360462764600227230ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME ҽoIDATX՗]h\E3dwݤۦkڊBk}P >E⃠Pć胂7B߄(I0RE%ijם&fV;ݙ9s̅سntr 5*Te:8> (,ZrJD \1==scǞw޻kљ-Q_-ȍJ@UIm`D?`Ⱥtz(%_j:]AI}?/SG?xji_#Uc+SqP3b g |iO %f^S.)c]O7ڵ\Ee It `zr-QڼH&jɝ@r8 =BB$:R[+jaHR]B: bDPJ8CEm`Oi^vj[Z9‰ rD۽V+/Sz$Wks^q][⃟Ǎ]Uy_bk&G$_X# %)?uN=m!vj.G+ 0Ċ`՟"ƐC *;I`K0@zhs{ O*`{zۘ/sϵՁ&H7u ?14ց;rlyB)V(p.`N&1<]a!jv޽КYJ)XG>QX*2CCԬE>~_:q^6s9g"~,{EkD |~X,l6K,hY 8:w8Dk$pAPhcr~mٲ~x *3g>|L&C4Zk=aƘZ9sN[Doۑ?ya>]_ecmУ#L4t<-E~Ci]g[? >N Z׽3a_zte_%cZ0SկB8'8ꕹㇲ}E~Ћ;'kueP.o,pe_D5 k}TkJqUoTYJpIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/import.png000066400000000000000000000040411360462764600227500ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME.IDATXíyU{ߛfp:03 H[+KYRX(PlEFM@Ә[6$VlDk(պ@\Ҁ:a70f{s`fԡx/9G5J=dךkϾZ9T릗7~[kw,p Z9٩κc Ƌ4mް7n[Vv= x|YUÂn;y2ؼRR"/VفN/]bẻd"IDHwvJqQQ֊#J/X<ә' J*$DF.MW֣uכԎ)86q82"ԄE(@9q ߝbox|!AZbDvmh ו%AѠr8OhwT=b.Xf%6HGOx*N(Á N}Y|'EA[Ǡ3zy'۟u/b(R s910%B8G} X.q |'q2PJHwS{̪RUJa A`5+!;JlQ[@2L>B20'q Gvn[{*RDa.^8D#Hb !o\3X|??C5dxso'JkF~| bŊ[Gdjĸ$0B[[Bt !\q <5뢵3*5cܩx7y29Dqz|2~s! 772񸮋8x(52hH^{Z{#f SÄ$H2jx<8hpB+pB!(Ď*Qy? ׼Ӗw~K^f1@; yv#[{F#{GQ9*V3_UOUIj95_ߜ6< DQD*D"{L zl8(^k3| [ QQ}o-wh=1DQt&le"t a\RKLa?wGt8E?{0xn3y P(&ieFN.ɿD)MJ,NY=Cۖ>ȚS`ijnڲoӪ9 @AO76qL}I$h.|2qՕnz6V,qUmYںZ8*f/R@{k_> sN.?06i͖- W ]gzq]h"WUWPZQBA?V^JNCoo/k TlzJe`$P#!C\%cbGG k[ӏ}SLQA ggpvӰ*UEh`11CJq`oY6mL&mE#:h?O|qmemN_9  U I~.,)>*V\LOԭݔ 3nmO˟]D01cG㍼KbOR*˒\xd}Ӌ.A` /5}c;}V^w8qQ3g@Gzdw.)x+vC:޺u);l6(c $Ar]&ɰ$Hc2emFK^@IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/imprimir.png000066400000000000000000000022541360462764600232720ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<>IDATXŗKO[Gg﵍Gm!@%vjW컩uHu%73@Ъ Hi*F6M\&Ǝ }t{/66Gȣys~sΙIO'3L/Gqy8HH\(LQgr*|L|U0na񸺿@_c@D}esT;]OCc1Z p!FXYYбPw̹oP۾k߸"4 0 $A x U*@(R\a! " 0ni7j_Vc/'ll694 !:5W*5pn0 B{b3k2"Rc `[ H`aaiBpnu!Dͭ>tc<1/`@ ihvYMHeNUSՋiW.JilK)kJ;Gi֔~mc 8 ]f jH<=LJZH>d'.m%{$gt&$t<<|M"&q>=9n{9?%pጽYiT=ru:z7MomfznC<]Nϧ p"vvqZx*̇ E!pFq}_Am1DxKUjyA(sHqԸz#)=QL9*lӾIVome[36 rA#sqcuN.^0Pu4"q beaY8|SNWqt y‚R O~ A``0<>DBJU&`˅lmG LS3z>叧W eHLMzC>?R!~Ņ:1hrDT!lHcfT30 E/LJpܦNDU;bp r$*zf4}UbkشO:]J@D҇dRϿP82s>xڠKNFm(kFbWU[>]yB2)}ョzש F@2ڔeũhsUX>gÿx3ᵞw/㱗n\)ZTXFA-CH߽_vT>wQqWh2H-kr]Z=|Q ˿5.wf*mrmLy=1orM I2r)S:as}'1X:u[ӻ"@F5ҍ'Nv&\#(Nw%Sc?.Y4Dz9G)M@P$Z {'9Zo[=4p2@4]dָ.)K25fqnR/><^ "yHdJV1"EtʬvYdfD,k6o=[J#CU?)X ]>m]mpkEwSlDـ F3s H?G`ġѧFIˉ*;:GaJmƼ/yCfT*vp[>_CY#C_m+04:~' l8WCV6*)0S(Č+'u˙pv|>RJao\Z4ʗksrDv|@4G)a3WߊDmHk1axQj$oĎG,؞9$SER"5/8;csY=6xn`(e[VjL쳶do%ݧevǮ66FBjBL+s3ym*9 [vh0ʪ!O@y#zJ?N o\퐂1d<&b—\M0oن[zr\G<Hf&,h6=ZXvq]@.W~IteٱdDɠŽKh!AS?~y??zFflw#:Ժ4yn6@2!AR}Sck9~q.X ~piƪ %N:ohAס=-1U*MyIqa"0/l#-)wK~&X+$^ir>%_$.`Zx08pYg/v'|~bD0x,@`Y$r@D(E? IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/jumptotable.png000066400000000000000000000030271360462764600237670ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 4+1IDATXklkol48jxJ4B|"P+T 6mPPE*J(E 4DJQ R$u8ƛk6(#i4Ws܁do7[!Y׽슎Dpt+& ooxJ-޹8T׮L2M4E d?'9>p??)ǩ<_ry[<.@{ ~qbc/ qK׿DI GLQ e/jvZx߸`E<79}T>W)ϙT.cB 投}p`W#t%,\ʺ?oowks4LA$H$uAŜf#m/L #J|3Min]Ed]uEQ"v]wHR0 x^R)ɤ7n7oV SoXEQ>T cΝؘ8( 4M!1D"]ֳB[oU-(pGKp/V!DEm㠹s TS MӖ@UU!i À뺕灁7ɜS%S@'˂8PU|RJ]חSB0.8研"L"LfZe`B3CCC" -#4"BJsp!R3)˲˲|Pqga0 |Re!sض;vPEQ,\IJ---Z(B6렔BUU!N:Uojs^ֆ[1VqmB!a-JN-7|377VAWWzj0P[9۶qy˲et]0<߶m0 4N< ])d}A)=3NK)æiHssi&Ŷm(R`xqxx؋/L[='.)G(mHӘccclzzy饗L*l޻w/49ŊOtsՕj8Ϋ_}-[x1qpΡ( "F{W*T}>+ U&!DY`j%1Jb[!!PUiBJJS0:: !Lӄ녦id@^QEi7M3.\ׅ8aB!pq5qGJI*O?1!zu|>|gi92\EGG900#G6vwwe#Gh333of6]‪r8~84MB\ Pe aYRzk}4\x^O$"R7 uL !0;;;D:`!a||b}Yi*(${EQP__Vh>dp]{GJFKq6}bnnN[_O>) CCCw655mmmFkk+BUUD"?x&i|>UUqܹ뺻k,eYJ0Tggg/_ Á۷nF)ݴgöm\pA\r3g XKKsm:tP^xRĉ$I @F__WBdf '2s2 ͕ZYr%}}}~~?@@ ҥKc26nH0'!\SlϞ=B!*++1\re{QQQAmm-wfժU[ ȅ CUUՔx!(((`͚5T|RLo@YY?ѹr%3\W D50::ٳgxAs5~:"RGYA,_}}̜ecϟOuu5N+q rmƂA(&IIN LwWugʿ4k wɀs8)sg,ԉ0̭ dΜ8&@'is2^q\xnuH܁uQ:7]ibsV Lիihh`Æ ?~!>>qEVx_22zE~ ^ޡ]̙LKK &K.@? ՆdLeӦ 6>f0㢥6&Hw ވN.IB 2FPdt]{`6<@h {M l2KʊBIi4S}4+##a+)>v.sKiU`$iXc`0xś,12< dMLa,F#B%G5|'M)(F$sCcH@$|鴴w~s/>9YdF8;`D82pOwz }{Ϯ(zGS=}44dkl߹ӣu.$2wW/6vB@ٜT dd 0 pIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/language_grp.png000066400000000000000000000027101360462764600240720ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME&gvHIDATXŗ]leJih6'mfDE5@ 'x ;#E F<(;o&Kbބ70:"n+tuY`i'(+Y;ۃu.%*#Gwvv+R8mcYmS.kdّcǎ]l@lRܹsoViaSUFR!PJU?[ZZR### u]r'\VOOYchI-*fIW0"48Tr\.]1 ]"k-YXoI"Po:tz M*2K<XRJ5m۪dxphݠSt$: <rqZqar>u-,6; yB4) t]G8r\WP#vh5  WK6%HPr/ !bQ@ <ǏL&)mˎ eQ̙38qD"M;yfL>*Yu4~)9Ư-S;ւBq `=PJ).\@*b``9Ld="ŘNzڡN c=ivhA6oL*"LP)E__X,266j;>\gݜ!e))jnn`0H4Eu1>>~Rnx<NӤR)_ᬲC :רPJ_׀ZMPJqv"_ZPpٛ ȯŎB = ]ΎګY>bvB$ԩSU ʎ}!VgG\4jkk.M`Y6m;XHp8|5Bww/۶m+3;o5QfB<ε2&~ c/EJIk̢ G| r9L䞁s׳1;~.֮vd2LӬ~ c+2~||}]v 麎iLLL055E2qrmעcCpG$5GkvgCJI٫sdhӘf8e\.CʕC(uz{K,Χѥ_%3>Kba&g mݺ[Q-]o1=w_TZU飣5 ڀj;joK/l?E3{޽sOSK;񱏾jxIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/last_session.png000066400000000000000000000031401360462764600241430ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs+tIME :EPIDATXmWgyٝ}e}ZRDw6bWbh EihTEcMIJiFӐBi,Zj(,`JPREvgs{0;&~&sg9\2rnS*? XQlK{J$>=+k?supI&%hlnVGPYJ~ޭ/2\ƍL\NɌ1)]I❍c N8UּCDe*k4D)at$KEzjFp`ݏb!|;R)Dx?Ub;{oga")Pn6e_&xι"}jŧ6` 3d'VB)5{P ."5!cÏu6F" ɐN B[l=D$eQ{hu&)p~|#?9]T Ǯ] ^$(&p.ץƬٵNLv~ $64,VDQl \R@7,X;PP(>ιd̈k(q*Ծ;}GMTFV}O>pū}/ʋ SY\MQ$ `Rκ"3<89P2 _qUD퍿JY?9s 瘮e!Q"Hx3 ADX+_IOu-oypWvN p;GѶDA- mTTT008Hϡ. S)3 b Xövn PZ>' VXE h9, 5G `ZbcA1 |VdD@dyHsƟ3 FY++:UՕXS2S9@ BadxE!ܹ)EQP}v~ļZ,)K#B% J@cTտʭ7-zZkx*F OXBdsV :$_gO{$-e4EAI3:Bfa%`1oNW$"ْ=d)HLFqE̫6+WsxO~Rʒȁ!`BiM4dҦf(> ~PKGghɸs>A$~ Y{}0F)U$Zk"R1rL6 6hc4Jꎩ&3ORLX1(,n3zk Se haQQ N(BQ2dJL-cZO)+wVAc86/q/mYIE-%HǗ6$Fi>C,,Үw@$gcƲIW  &HLG@Q0o5l(OJW sQzý~÷?O}o{c MeXDǎic7-6ܧdu3tl/RJR:2!^xq|󟉗d2)L.X.tve+S"heY4ד?. }if,C _yNKsbeTUU8}מ;w#0K4y)g2jƍO҉`e xz<`6FP]XƦJd.L_M+V4 ] jv0;G2J8N*Fod*>Jwr3%z&+Y1XγR؎ƤI`O&e=f `1"R| Ӳ,ؓt.4X~K^OcÄR$ƨX;xAjj|fͶm<0k[g^ʈ C}D ]xiɠ;eXuGFGx4_wKN]#蟕 /={[kU4(I&::VL&=Rr~^9=SBB0]g#Jwn͞=9zJ?0.dr&XY  5D"aRI8;wᑑ]Ho8es_wӢ$xפ>{䩭}}}D"Ʀc;W0e7^wҷ`u9uvmԜ`.{w߿o\M2D)Uw4@ccK,>b(G𑃯]SCZli떖VYYYI?dT*x>Y;BR%KqFwxd߷n~d@3 ]]$ՑNq]7R!behjlba0PX, ۶=I羽Owȝ}/~jphXNkk;htul! 3>MkK`H$BY4~뭣#B=Oh~n:a,moڰH`]k#so`,Vvon.K attu>lu3xƒrcĒ`㛞l>sJBȐzeR2)=5mc0Z)%m;&NcYJCҖ!8B.<> IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/layers.png000066400000000000000000000023551360462764600227430ustar00rootroot00000000000000PNG  IHDR szzIDATxmLSgt0-q.dTH7E`,K-d1e[mYd/Ρ&`MX&|ZZ*}ymAyOr?<=?FNrX|[!sUeQ~~Z6)pVҟ]Zd#vѽII䉔̒V&!q WX.6WB"J{61?>I%Œ-ikƯNz(:k( KCj\Ļ<)(|{6r!o}eBmw>vYRZ[Ӱ 7DTS)Tg?8*y+GMSuMtQ=Ax@ ?^i Hg">+0]^Lе_JS5Ȗ 0V rAo3Š{tzU"?DF\(3S %5#gtcYSsF!1 ,=Q,^ݑ7fK|[P'A]V\0ߗϟoqg^R3.7Uqk')r ,8qe`2x0(ڇi\Vo, 䴿~7Us0S'o`Kd)/m=Xs ⯥ڰIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/limpartexto.png000066400000000000000000000032221360462764600240060ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIIDATX}l]u9vm׭vٱ=̈dVS6j1bD F 2@c1D]]DCW>޶❔tv7wrr9s~})d}hf7G0G%![mk\&ov#7=Ef.ҕKf?r(FIEqaV3p`Wx1;ssM|9X39*kVz=-R8 4|[]F 7Ϛ/)>i2 M3|һnֺ#t={㧓sNJCS2TUٜ;0;;϶N|;5n33N:V!b+`Az%2N.cs僖K7ߺ^=@_p8PU}aN4# Njʆ_[ƞ9X` d jCti=|0gt^6}a~ )a޲(pbZ[?0mQ48"}8knV/~8GmaLκ6īx p.SRD|ܶ]XXdsA\#0jYȸ x wcz!>nE1 f'}4F t VZglvӈeǰ9°!OQ }/f@Ѱ<Ѹ@ SJ&Pѳ~-A,^(.1j̥6mLq5\*GR3T5F %nHArvXMW=V.9Ok`W3qCUAdtuAHbh94JV3yylG_5 ӉHV줒 2AJʋ<^1 f&uRrz x+#uCB":ER(*qT#GR(e5k~oZ pZN45EN(Jd8 ۸sl2Ֆ6&}l:B`|(_;0Z):^OZҾﱹy O&F<9T̩hO)ywm)h.B)Qk` Xt!bjS\1k]@!49)IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/loadcsv.png000066400000000000000000000024121360462764600230710ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs B(xtIME #IDATXMlE3c7nT4"FJT[BXn*qʉ#PzIzp#jPSorz)D.u։Z_pNw7Fz}o>4!'ܹQ2+:R Ag,s+{~hccvz(bc4MsF?B)M&<}!`)N1Yz^v,]lcc9 !뱹}._luPG(  T*eR| >Q!9O0~= Ǚx9J؂z y1Py$>NJɣG~)paaE+W^%S*RdB`AkR Ir9( t0pm96jX|>P.9::"RG-h4{HKRҟFiww$fN8X̿7\j|0r,q'"a>ʰIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/loadrecent.png000066400000000000000000000026111360462764600235570ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX͗MEU3_l5QA AEoAPoHE/ *B'?UWW]lWW=g2IHC3]]ޫW5JD8vGƘ4@)Zk_8~@GW,b}cLy+zccc a#v`jMaO2w歑v<,O?; "I^w:_s3/1a wm ^tB^|h`I*R$-O!@ظ4F;E#? Ch466qJAUyec6<QX`jj 7 Ѝ66 Al.#koBy'i@qfр4BKM2mo}q&v@~65 cԬc|>ǶJ2BV嗶=q H{(Π<;j C?] 4cZ|7l8+]쯧w@X|w?}Ŕ΢vIۛ%CuRCb3 eĘ^b!=Q PセKC,YZt:?M0&6 L[݋o'ui`ܹ Y0,F' Iڛ` TJ18ob-H:H_{mwwއC5ܝ8]DpEOZXX(98SCJJD9uY]20{|wdn8s=fdH8wJmkRʃ331 qƵmb`ö+**^KϰKJrxɹh'qiQs]qmm}W/8Wd0v3(),EdB 9jl@WZ0@AgG3ݍ;OooMknA:}XN^Z\3/4PY.A# Qhx?;5'or/1n|7o@/tݤWSiJ)% ""4w2D{VJ)+dg5vh%Q/#R ĤZ%ԊuztHP5G \ >x EsshD{htf`s/_xhzUtg?Gnqhv6 24/h(d +N+Zh#MM2 ~ԑܱ>h>'3"3}T'׀)vqx${Ht6m !wHXxA;hA EG^`R0QNp\g> lEDDSZ D b b(_1*&`y <5Y*kOq!xUC @/ 5 I*B='XʉE*ʷ=מjC×6뢵 ^"Kkup-0fTbcnXf섉U[OZo L}rʇyeCݓ)"'y2Wuz]敖XD\6}%LFkϹ2TN+Ԑ j~yrgO-[5f\ OD< 8DDg..OμI:.ó|ng*\>u(--/(,=kw C݅YSGDK$=׆DǽgvO[2|xF1-ߝ((* mH~Auo_7zc;;jM]Zu:_sQP[gvfWu>t"Y@JGʁ.G醺G"f^~5SLYޮ;^wUz XQKfzxa@NѴ5{aoîR7nhX\.⋫2e`0D"iػng< uSL71+?y˦[l%'2~!xO?ع3λ\LljX}6 uoJ,E(3_ ?_  3~kGg=|ιvTϸȰWT|Kr v`"0 (ZVU)R@D'X'X V4xFaL#R@NE(%vSbRhk(hƙ>QcNjp6"P* L`AY*j~6w-<ݹ1$,H@kg)MApљ\(sͿ)T."#QWZW=j@h-QEHfȩC'byYr5WֱI3/#0QD):|"I|ɦUqH"R {eq..5jEVgW#Њ11 %yc" yv%NJڷvRC~~y '(}ҽa՜X9!ZI۾օsy;}['A3kuSіXMX՗װfzc#^$ Aֲ3'Rׅdj9LdbCxru[Tl .˯?Ҷt:&~fL:^]ǻvaɄ[>sz7úX,D@Lh7DUuSg^p-K{SGӷ/l E͏sՐ c$ =nYnR(ͬ 1nt`׷VtrPZ!Lȑ $a&'8?Z}v@ȥƒ #J4rDD5J #oKd2駖v[˞ZĺP8'8\nxw˧+叾<ΔKuJ]r8o?~؁d2*g,F'! #@qWtݶ7yf*Ο3SƖ9kRJ*2|wz?zִq̙ڵ0v1Y* fyD> ^ovfL)S0*RQIyuCe+h}poaiM?:U|UO&S|Z'9'C5X=rխ+P&MRzr-0ғkj[=LPWZ9{p<*ec&0y=$M)>TRtkT6WEO\%Gd'*IQD"pN[ϫYTcʼ%R޴z6-"D(dRyftBO X9\IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/modificado.png000066400000000000000000000022231360462764600235340ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME 71ơOIDATX[lTE3.QЅ@1@0jH$}`KyPW} 51%A&$@,Z4noKnw{9gf|[K_򽜹|͜@}}}kVRZRq]% ,1b&`(tB 6)Ej|<jܷo16=dIyۨgj&7!vaR`U*ȧAOM;%q.̘dOvmX r99.z*H>΁\݌$،? &Fka<7Bmxs5hg*Å WǝRT:*jkvO\jOSs ;N\HOؖe,x^r!JUm ]_s᭏048 ?oVjFFёx<"Gd sAR)N~"Hh,K[EEŗpQJY8G)eiZc1Fj^׾y v_=?v:c;_WiYY`)p/P'}ʲ`W|FSB@BkΗBm<{2zsy?zVa*';T#P*˵4^ D`'eQOJ,Q+@ KSe& IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/moreactions.png000066400000000000000000000021041360462764600237570ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs+tIME $7GdIDATXMh$E{LldW11 a?$.zpObr 9C#$`N4x6\O6U Iz2$M؃TwuQoQp"]P;*{ӗiyyrGFF޷m۲.@X⢧ lۦOy,1D"{U.\03XZZjt ¢}ݲZwc `fQӼ߀[au@YTm"mUZ{s~9qH)y^[[{L&"7%"쀈}jrr*zMYz$, .`ɓr68홓BdL&-0O!^vg?Ɂ|> 7m SSSDĭ@J ^]2!fh00Ьy5}Uc,@14j瀔C}A pDr!U]cFk0pఆAgK⿊YX5 i(۝_u 4kIXժJ)&z)'GgWA>xc{{Re˲&h]+_tttщ'DO_ oςDFgffJ :'WG.0+t ]<Ԗ8D@@Nz ItDS}eQꊅTnnOEY\3IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/moverbaixo.png000066400000000000000000000030351360462764600236130ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATX[lUNKJY "Tåb4!7M$H4hTFE\6(-!@ @v^v3awm‹'Lf~w3a67e_lI6$IS|rxE]E>dBٻ(+wC?E"Db}dlc=GG%[T-2<#w[Wj.^kB<7ބ%,HHA"$lx:ǠB0fd`&!Lş slrot&jj Y KI IDLXa 37@\xm0 ]ngΝEnNRR'AM0hoKݏU0,Zi8X2LK0hM'K?bͪPH`U7@3<"5\ť$f|Z`KۥrΞY3gBWE3D?UDaj%=XI 7_"杞_+)ȇfDR  a(#0/BwA pgcl|AYq35C5,Q XB$f%@ щ&fs 0ߤkuPTXEQpgQa'O3XD'|7x΀p++EQ''ϝƚ'VuH^ctݫDv<֬CV洤/=!;.k^#aq?H""{YOh@Џ@/lp9z9Ra{9ΐ@e!+˅/oŔi(3fjt]=+q0Ɋ=HrHG2YwtPSz]`0>^I50BVX(+m Rԍ7gF "rJ林>gY*ۯb? `0 xI`_BeYj@ 2QjoÄjEb1P%ݽtȿ;1gf 3& ;r.,%˦ӄ15lѣ2+y: #` Έr#ryLlp@-*B? ;IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/movercima.png000066400000000000000000000025461360462764600234300ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATX[le˴ݶEWmR(^H,-jR/T|jccԀʃQ<(bX V!6Jji3;LJ4KR‹'g},13ng?x]^Ӂ?;0 u<|@uVd_i%ږ4CYr:Bh>rysQ_E<Ҵrj݆aZۡ6U}|ZOo7fO(o2Og‚Bn? 1SUG0c4!$%%aZbFuJVq>]|Mc" !!5_AtGD C}hj@QQ)}SǾPLD:(37 ") .,0|\mhFo`C!\ bp$"F0c}#BzK"gֲMlDd -%6gg#Wl{T-HE\cO}w߅++Xg{g"q$bw;In?^ii;&skvtnZ[N bS&0@LȊ+֮(w^,Fs܌=  T !eS @$d2I_^S6r `G YCQx/ SJbw߿MG?08%hjmxUal_u̘'13Ʀ.)X #kڔ 5ى\O&׻둑¡Nh9`)۳r^oPU rn Ub[;x0; ނAiqAD`̬-NeNf3 `97f0  "DXavWǷe\?' :A8i̬{N<`bGM8]с8S5@̕&p͋WWQ|L477/ Z}߁3IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/moverprimeiro.png000066400000000000000000000030271360462764600243400ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATXŖ{PTeƟ]UqULXQLK3dfxC2䘩cjՌe*Ӽ7H24&r嶻pp`]gηsyJI Uݍgk{[GK:88lCA > ػw?~Кm3dUht!)y*3s6jF϶36a ѮeױFƵ[P{fV:['jQ*IGUXR [w*M`I,A!B)[qצ5[TAEK+;9 o4! :?]-, ڢ좧D߱s>w,&61X,BsRYsZ:yp:jM{’UAqؙYN}vFbx)U$ѨoAʏY=rfeLagT~/ϙAw*p!Weptp[io%$w`{ 26dl^S߀'@Դv}ةjs0קN g]o.X.z{J9RC@f;vduihnrsLoϝݻ=}a9P\K P?sG@h l/ȵě4XJK6,%8! sf}0Aeaxm->}qUism!cۑ<} r4돟o Y W*l{}[Ljy9w{h*ܦV6rv(:wj5Zc V1%UVTY=91^"ܳ]g~._;q99d7AO7*C=wl['_fi}2WPla,3r wO9K^4 yS[VY>4@ Kqn6յë,0f@ei:Y R<ɘ[Wj jV&L\=Bn*cLs޻J]c0]&T}pˈv@G(G SjkɍIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/movetolayer.png000066400000000000000000000032441360462764600240100ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME  +T~H1IDATXklSΥqH;i@.[!B6zQm0e-lRMJkUҦnetZ5L[mj;1$Ar)@ImB &7>} XJst.ys9Q?&!,>6m[_ п `sqǷH0-h,'nyeCwc>gZͥ@fgl  g!!fx|tp8r$WJbMv% OOB|!xKyIA3~:-.w.$0ny$n~tKA@Sv.$4Rs-;o">{wWz|98N:}˷@S${`O3W7 !ҿvO/!ß[o#LEx⛕$W gkRHΑtGQ2,FZ\l̈́F4YZƴupЯs;Jpab(ށR*#[p& B ,Q? 8bcn gnÏwxy{K2ucK2us&0U<>%?~wK%.W^XJ0\@.ڟƚ< п{Lh%U7+0iZaZ{ڵЀk K_<m/D(,`$帤l}"M3B._q̿B/W$D.z8Xڻkڅ{)^b.M_2HRhx<Ɗ5躉e B[C H @]룗V5Y2#kٸj 1fL3Э8zaOV'wc,Add ]OPSŴV(Ǐ~6rr[BȒd9PxhDO)ڂitS#3ۍ1w\7c,"۹,y@r,j<|Ũv I(ai$89ɐvK.rbW|ـd~oV-z\8|q]-  zK6Pw3pO$2d?fTy]JdĹ+:(%#+c-oOR@Tg0$R!'ūtlŇQ؏[0?k/p{~j8<@5NᏔts*SQeo~q 䨥f"'ɭT$ 8`r#f) h gaŒijuQٳT.x{!O޷ й;ƖuWGH$,!I5uezؗR=KB*$WpS|7 Êj[@`$A1hI1AF`BcIPʫLLtvq=ϽpXldJv9;;{:k~s7^r sWXԹ+&gfʇ3.6]8j.#{zO?wknUb?0/h-sl˷eA@0q}zn۝@ ܹ뷬`kMiꈈ""(XQJj9jdߝ=Kwuv– >M7֢՛>Q(NoPuAD<D1FK?i/^s|GaSm spqjEgXVEu1Yhq©,F:q"ÐisM P ɀL߿I B~v/i:NHV5M#ĩ!*2j1vϓfi_FLl hSi$FP9H}|p,@g]q&<%?DA\H-UP? cB`oII<8ElC0EN XxJs{$IpTF!UF){ 0zy&&~ C 3 q= ADEDq1doMt-;7*m `f\Ěbݲ24Uk0hBDK "$&IR::z˛e ,ij;A;%Ͳaf˻,*hTP80o#ubUK814V}])q Xr<*̵=aq\lQ* ҳzcD@ (VQlst;Cgd Ͻ5OVT̟7}o2zh7ͻUDCJ.Q (!J,(E3ȸg_/i1#V2y/Wi߸^&CUB[#1 vb8+[\I:01B5LgnX͊iՑ]ԏDAd`/X{酗?wGo$Hڪ$`5 @2;[窙 q\C\JJqd~fZ[j#F-褽c/ bDx½ޙ ٴFqA"XX4 3U|&5p\$xqAY9T)-Vb*~8js͟u+GG4tx]T>F] 9ugHS1iNJ= VCQŸGd28ZOjaNn Hl}~GyUKI)YYxDqn*mD=$c Q xH(2"JЈSj(r>qc-Uhts`WE Cލ/tRnXАOߩzSaJӯHR%ZAUMsmP/IIq+%O\XrGo\[hfb[Pk64xBU%rjj1VŤn$V8v7 lb Tjʯy~Qж׷02$r6s|1f2qMV6"Nn&H%[ FLv*g&NWWy/ik@ ^(-Jj`sWLzj9wV< wE[.།Rj9d?G['wzE9{k9Zkq,S;(rszkGӸ|&-G{_Cp\(*t'*,\H H3f>9FA._fԩ. /beutua܉onnV=d"M@|1zڴPK^{aLBB??}ES.7mC%W)}ܚt„zSqWV "f5kMM|J)9q|IT2uk?$t\]A^^vOK ŋAc&ibFQRrz< hϷks9=qDd^q4鮫ܴpi6oF^f1v\\˲w] d<˲PkjNɤ qt?pXܹ 'O9}=*Czhe476~\UFfNή,M%X1(ܶm=ʱcH$΋z0Hƍ(reO/_X 2"•+Wb:u:֭Cͥm Y\ 3"B4eժU\ 8fYlقJ&q?~DF>PGD>{{Oՙ3^/gREl5==QQA-V67P2"p\[k>~l8]]YӼ^=|(#*Nyվ";y'O>ԒmmxKJ̿ d 'wLmQrP R}z>c^84޿ EDRj@ χ="2 ]qqjt/( @pz?U D^I'_x_g(i cx!ZBҵ;>tF[KNfΙ}136:D f1/n4 O(o>0etwit`)Q[)[;%gRm￟cigG?o.( t-t5T˟u'JG~ad߾^2Ri{/Vq}jjio窾j[7@(cR{z&iX^nls?cɵ߾U>c&@(N~vJ%fs<5X*_nUGs̵uL>بi9Ķ D̑~-|fȚ ޱI-i^G;8UD;H,Ö q-@H7  qX8Vud6y" )'p1'0ovM-mݤ'UjMkF-V& 3:'ȰAVDAubkRW;݃< $@!:ݚ2Ӎ(j5 ^/.$zn0*nUU+z4y.ɓhY{g@^k: hwTXP1j4J!lXDV* r"@C%5 r~W !s!^q]q6!3]Dž7JD3CJ+!U(F]@Qͨ:.rM`߇sB @ )vMTF~^ eovߺeY?uS܂i$D__PX N;F,\ryMGܟ]t_/&gr[=X.ГnH˰do5SRRi<'G$ѬoB֦ ']Erta~]?L>'zFI3<]ob:,pX:puP `ipn4 .U_DJt@ORZK3 +,, PP m+0BQ]/=j;ԔI09{V$e+h<ffti&@*$3TCg^p;@Ni@L =nD ~ZW{!IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/msgbox_info.png000066400000000000000000000043001360462764600237460ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs+tIME:HNMIDATX͗{?眙ݻ, /V+T&MkLm&6Ѧ6k5?1j}4"j,XD%-tdqe,]u}Μ?f]6HMv_fr|{;C\7lhfXg(oO.f[Lv=mzK[H@pGy\hU"1X4 $)v6?S&Ekm_zӣH%Ժ4|w /HSq~ʁ&o# m! iYE<|7 j*@x~$}vd)0Z*E.,೾|b'݃;I~oO[  ~Ɵyu :rh?RI!R ,1\Xm׮na#Oye'F"2玧oDaW\ռѻ ږ=Gyw83:e)" M8LYqhQPFR ۶bׁ"Ajqժ:546Sz }>@}kWT{ +%}MѲhvŝmˋ~jSg<7+E8h*f[y%nܺReYe ,D$yY s{c'9 XyP,t% 8(pƑ.8?Χ}4U~e|{_feyK" (0%,.˛+iXTJA8ĚsUk"B `hiq@JXjv*l"'li% bfp4.c@kC1j+0ƴbe. Dbٳ̙v o.8iyNLA`0U`o,S RJo@7%i,ET*Հ?}r ,syl2 !R{C)fN=<,ԜD C^I绀 !Bz!@UTpUn[O > G|eq9#@/A@MghkPB ޳AR>AHQ Km"wu=K;8Ek6ƇtpJvJhW?$R;M,Y`,1ɺYɺ8{&P]Y̒eLNy.Iv:M;n!:]u4qYͺhW{jh-W6?uu]cOfqˇ#S,8w76{k?;K*}~3vp.뫡5׷SWUP|'OekǓ=;W㭛ZrfRYzr"u.${Fcj&T*ő U%4XPgKw7;g@B "@j E-޴ʺx~}Jt^~dY`ʏ1@@(u bM[~dĶ4UM+ļ!09ft"A{~GH׀IM ~?4p/# Q#Eцk"K6rPFȈD'1dffHbw'5= Η8U |uB^A5?R@ڿv>찁0UuIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/msgbox_quest.png000066400000000000000000000041501360462764600241570ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŖkpU{sMnBKB! Ԑ(#$hZ)E-qZTcVamm;hvV>#jA1@Mȃ9g9&̀5̙k-|J ._ܼHHqWAnV93³"@񑱮k:6?v>٤`ΒGoW:7\^Szy]e<2Q:<{{ /kVU(|W{%eOC Jg*!0'^qٗverYks47.GV\URWSJt(?ew7"@ 9R4,(cQ(=vow|.in +W|+/;dˎēJJH)B Z&0ƋX"57L1Uő7<5ƶN Ca(R҃!Fkpu] _xNOǔ2TWdgdO7[[;h-e ՕKФ8%sK w%Yѡ|c _4'lJ M,S! 4)*Ȧ-';haYQ뫭 Ǹώz/n^검eԺIÐ!:zK.` (כ/𸯕 &/.}%ED)K.)gV8!8pysWGqWiKё1Y= DJ(V.w"o(^r[#y xZtF8̈́RXXƒJ+N[ s@WHZ7S#|~dEULNtDANJcI7*WP wNp/uIJ,&*3H 3,".A,7NO0cϑ}XBI BDlY8/B}u1G>SS Xo)\ZK}M {]RC{ uxcXsƹ]weYcƒ!?67V?~GM?=8 Z @ [-m ߮-hkUG2[[6Dέ뎵{30z j3}\ Ƿ/QyҒye_ Z ıpH_4ssOط #09 >D PLT o@̷A`d0 dMrxD'?] fIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/new_big.png000066400000000000000000000042331360462764600230530ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs+tIME/${ק(IDATxKo^,8N LE| t+ tmW.n. 7ʼnCI{p(2IQAQ /yIya)KYREN| DZ4 a1i$ IiJqL$8p1ιѼ(F 'ZL!")A-ϟwa~h4Vj!rٖKӔ4Mޏl(\v|yU1E:FQ&M/^~Χ 3i0|Gq}}c D{~zќ kG5Fu!x&i矀(ӧlll `AUG +ccc#=āZ&:byr?  cZ Ð^cÐ$In(YH~akN;cz9A$BġjBuclߍ1"&Ir2w1憲E+3V^#VHP PF 7_*ms L8s"AdHh.A}C``"0@c& n XbL%i" O50go":Ni؟X#6@>Y@eYbL #f hd 1 ,^*q-,.Pee1*ʈ/A: W}eQ2מ#H$B} $NP=B*@π E|0:MKEgtyEǓ_>.d!+x~/[A 2ڟ`H9=pLbΉ\:7J8PgAs;x?p >1*z=;1Gk _:~P4(x3^X,@Qkc#DvMk~i3cxvp#^Q[c@mnҰ{ /"~:?Y3C}AYXmT60!CiJCGi ۷XkݽVM'Yŕ[+އ [xw8Pj4EȻj0drzz.v`05(/jG 0MZ-nopɓ'ܻw(JEQ|Q "+(y#A @6gggxﯕ㩲H~Ahc"(bԎ]u`r,0M:, ikO@^|dRV5Ez 0ĪVYNQE-ȸ@Y]_*? gBh;dUgcf&XJ}uk:.P `M;ɳ07s (R2;7#@[->/eJǓ:C fM- %v||YZ:qc<3m 0pxxfR2SuiB\`ww^'.L3C>*XktzcxW(uIPPoR]?FKCignTJ&QYAEV 'ZgsiMlҶnE9/g`^6 ̫EI󤻿8(Q gd>^vH)y]QVoYI@~rh+w@"5@m.0atF_gl6GH>u"K {]a~oxbը,jgܳh4Å;NjV`EzUU]=h9u&5Z_HݻeYv5Ip8nooիW,e)KYRԐr49QIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/newtab.png000066400000000000000000000014341360462764600227210ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATXˏE?~켖5^!e9/xO0FXnɲllkt J2LDWK-lum,I0 --J(^B÷r k;%*_'l( "#8?KQ^a"irduKZ\w^l*`I)BE1=.+;/~~ @^gu)hmiy0QUn?S Y6~eѸno@QaSx1m  O3O(׭ &1  B[l}(7;IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/novo.png000066400000000000000000000017601360462764600224240ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATXŗKO[G3sm .L %Rd n*Tj.*FAjC"5ܙŵøT=hf4s,_l'n`m[g/B;`}}\.1c' Cs}w<^x;LOoWxqζj_s)Q߬D"0 cY7!45)H caNj9GXnӅq"lr>VjD0fTm<еJD[< =$>֜#{/U@K8|1ཏUX#u[^csg zb&F 3yƂ zUFdoKqas/@RhBbj9<1jKԣJpݝ_/n 7AFSWrY?]W8i1iqs^E/Ӷ9&P? 2ŋHarfqL9B$7 œ=,7K/@Z ¬LUi&@ו۞ ig"@Jeh):FH<6660f0q4da^jee%bJR8I A՜3![RC0Ҭ,*H*Qz䁻[Y2F譌,UM(cNU\.Ag

44 ^@4%B<#RF&YB1$C xI7AZ@ll,P pU/#edb{m#LT@Lj `Rs:00H 8TFQÓs|Eä{sNa>=N/('/@Fpv8u"wc"9/9DD4][]]ߵ?$I Ool |=e*ܜ]RZHDeHmIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/objmetadata.png000066400000000000000000000026371360462764600237220ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIMEuL,IDATXíV]le~y1`l2LEMޘ`01!^CM0$\!q*Dbx &&sDG CԱvk2e[WM=y<9/!9rdmaaY!y>ZkvڰXg}ʇFcy%!]]];;;-3'cGOm3 \h_Gpn_K|tK^ r*;k-&,)A Bcu`@.gdly>2Г+A2D0@"B8+4G\oGGG(' sZ @MM^"Wz{{8ΙM\|?9.ze,YXΩZb4[~gam88s1 XXx mEqTZTD"T-]֕0bqOj<.gj`O@*A1ǏZPZ 0^7* 8u8_o(590JԮ@2 [׸y JiHiH(l\_Uy3&HT") T T  2*brTWiMȔILň#I`8EƖU9< WvS_\}@ޕlI  (-(-ǥ+7Ѵfq` 4,& ~'NAdJg1L`AXVU{/q2xa]]&l4``Clqb7Һ`7L`(O0$eDDJ+aAk Kf)LjBJ Bk ;FJ0&u1)H9C6R} 4GU Cksf`DT{]M)ŀOusOI.^pDtKR&46P:Et6Vq\B̻ČbtP(< R-L'µI#,`~V*3rvdx$hЬz[lZ|.tww2l`_D/8~`b`x, oYS6{?Z;aY !BD UWWGBD$'?x{?i603$04n_mwot99d}M{0bϡtވk^x<.Jj#QhM+[[6jpϦ޷_&|ql”XZVJf˃+uUI{mn{5~, L(ґo>=gCIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/objselect.png000066400000000000000000000042471360462764600234200ustar00rootroot00000000000000PNG  IHDR szzsBIT|d^IDATX͖l[ǿNL֩ I[!-AMnLӤ`eBbRX Bۘ6uu"M)LMeWmc;Ѧ4ؑ޹Ws)HD"rԂÇ !_>AضmB{1CGumBP<σR 0d066QrRy#5#GB+ۡ*4MimAE(ۍR! !/b?8|pP 2 .'JvM+죫ܿ>e| Μ9˲ּKeuj5z g;/&J&oOڥ84P5]R]mk~s1<<ݍYĥJ]u_ZoEY8^9^vҪޣH%HWBT6C~EQ011+l``8%X'O~cOL&-JPUb|tx###f5M[0zf!":;;d`0b/ZD", ؊~3R~__O?-}GGSpT*I 2N:d2~ٳ'k׮=o>0P(`6<>S\p}]ןo[\oO*to7ND"ѳqF^EB@A}}=z{{qڵulVFXcǎڴiS]t:!mۆٹhq URttt@$W^|A---n{rxUe(ku]:ugϞ޷~J6E( B,Bjw/bsNStAg]]dI3~.{-|~)r>!S;nZ|_MT=xk^"M8~έ 9'n ǟCPP=d7O0MF֜4N_m*ᵲU`E.Jw8ҼBg35P*0`%bLXcq+*^T nЏl>4g{hu†5 ӎh O3ja-_=k ~{@+<+jQZQ%=eV;g䝗}пn|LXnfU~vQz8ӥA;biogع?x:SjTZ7*V2 ԈrE;eZt|~578FfQc\Kx/qp{Ɠ~u5ƹCԋ94̣Q¾~S)J{wH++Zꆰҡ-̜da#\k,RG&4R7|2]Qwxү},T.VBb1RT*NEbqd脦V,x`ۂ]}^ %n=p敫7^oۏq}ŧFY-RA.;]R& ej@0OfԪJsoF5mmϔof9uFL"CR{sX E=3q- qDd6[F"e~k]so;(.N,X]Ò6F\`WOƷb]!3&C$񍋵+TZ* Kk͝a NDQ  J&( ogfvGjv$,{&ac\$.O1.iK=pl[;0Fj.M=eu>:!aS~j!ۣ5Q5xs^IwW˅sNcWr}h@}*s8a`A5BCÀN@ۦgVm?FqQ!DIp~:`zEĉ 0BhY{{MMN1y CHF:bMt9Qq9n'lطV(XCz`=噔vwvߺw Fꟽo 1D<@bX41BO4<:Zy1̖YO4y%SU/%#$Eͷ"⨄$B`# FlbvR(g`ّcȼ8NR~71KRӝݷ!~ZآU+6c "\GWlLIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/opclass_grp.png000066400000000000000000000032011360462764600237470ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIMEjGIDATX]lW3ٝNՖq\b*KHJ}HDԇPOD>**"FUJC"I:ػ{3wf )q_wy?^h CD H|c}58'LyRPϮO}]5Hh1U'@LR>?Vr>Gᝣv?d 'eЈ#"<$Dy[@ö}XL_z-Z?(=SKn4954kv/)J(#wb}%ZnHjvOz־j1h6&ۺm C/!桺jy`)XSט<ł*"toUB?Q14vOzܢ0:#`D=)Tk}3#dS"-B2GQ8{xDR`ҵݩ@ p-ݪTXmφus uCA%`ޅrt/v9 _(p L$Xп•7&`[NDK ho-EގcN铸F,țѡ Hb 6.ژ -c˙(>3tX-,!k{Dsjt G~q*8cT'^bT"ӑq^-ས, -pxXua ^W*xsd2pΑypΑR ԕt<1 "B@JIDR믽Z:>3%  hDD "1bf !Ɔ"I"RJBo}Á"ˍH)@Jٶs=3gZzoA;6,Մ| ~q( .\~ꩧ^oVWWqmQW|xZ끚ܭ k%;X'(193 !^Mof8cZ&yۚN֢H0 @.Zk3ό?~|CPO} իWDÀPJG?aNPT*;333r9;v Ri[{333p!IB[\!8N)l6tιP&R a|||yfg"V+Wl#Z<㘟jFls1_ ?~f3 iQqigJ{2}ޠT*jD1055Nm"籺&BfRi`r|h>N> !1Vh㕡`f֮u!˹zs"ya0 SN)/I(h4P.; gRJ0j\FӁ1&] / 8M*ĉב$HjgۯJ?0== fsbbc!ĭ5"8Fo4nܸ/j!t2J)/i Bfz694o˫}0\@Jb(Ocee% InCTv/ I)155^RJJ%,//  Rpq ]a{}@ Z!R /bB{gg'e0iQR|KRcVyh6\73mvn/),.Wan vέ%IeuT*ܹsΝC>GX#Ě1=E[8fўY| `z'A3HDڤ~QE0 q̙*)QtKOӣy@|lةaֽwn!J,sV[ց/eqf;! 0@c |+5XوN9jL4(Sy t۝ca6ZG_ 2`arřYr9q )%XoNFt[M(1 hNhCX~Af' ƘBZ=fn111`J GA-H}{f@[0w `4Xn#1 ǵ]"2Ƙ0 *SYH)`ZLMDv|]i-^w7/` +xJZ ٠ZkA[]ӂk0&Dz,9os X0֥&oΗ0Q,ho$(c)a(y,sbXmd3 9C9le^p#Ei1uj.#hGhwbX>T9#,3{ox nRJ08qnER-C7j'Wk5Du`\?; 4b$V)Jbcb|Vˆ-G@{u0ҿ$|M/!ҚfTZ &'n C1c,;X`\ש%"1.0 +85#h?IA@pXX y$ O}1.]þWz L@L]٫B$9DZ㏻%I4y9!X}u@H. "ƮFwpA]pprڑ̺E֣20zkwݶVl?wR@i=M8RZ= :qU ~U޸Ӻ:Gxy\ /5 S7-Jf% ïH_|cW Yڨ-7TO9۱r4K[D~腻O>dT*j@B^5/+uTgN_0v*qc4!|FPc]٘ $-6XdXe`sKeBrHA2P('/4&olXS &/"O1,v\ywd :"2+):JRer)teY$,w#tۨ~43/|4Vҝ(3dfJB( UfU7 69P,IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/operator_grp.png000066400000000000000000000024501360462764600241430ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIMEIDATXõMlTUg)X D\(AH  4IJ) lbLtJM Q>m1J" f@ZBAA;{qQĖReƻ{3'oN9{YU yWwk阃ޔ|<{`tw|*=I4ib% $30"|n:t1[J1mc1- *tr@D`Ha9LEuG?=t"e{+6aDC'KY@w/۸|#[PMdˊ[=)f' 0/G<-'"RǍ)2w-8ڝ$:d[ Ұ/6+x"k+I5ipR/]sk@RϷf@ϠBY¥\8w{+K.,(/Qߜ VAotWo.Y0{6}+~ֺٝ?g#F)1ڀ@`joFrO3rC  I1tjA|FEC  w;7XZ@V$5K~;y1F$jJľ~"%( }*X,JtwX+v4ngY;!t:lv0ow[1-:+< ,"-E hkV:F щo, uA* ᫀ0H*'悠79aeN7@5@" 7^5#~x{2*pe 3FiD57z˦a} <:JW5g #uH`1\űUTq eݯY.֏WH5 u:><ԊM$c ؖѤJ߅X:Ϻ^vB7bxzwա#t>8a$>lkW!3h0 sBTۡZ LAGG <27?>OZJׅ\ zt!K@IIC˾NP)D la(b.^'0XD0$D" 'IubBHX+ˈ?h'] CX4eqsIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/opfamily.png000066400000000000000000000044321360462764600232620ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME"ƛIDATX՗}lU?s=iyi R(RE a %Nnf,qmڈbeA2nT[RmK_nz<6-I?I}~,H3TO7x5ɓՙWmf2ėH^ ^obZee870h*]]]ip|L^[`iXp.;ή-R^_E%%h⫯[ZQaa)ayueq/(WV>~WV9 |21!FkަH ]~vΜg76c@)R>09HILIfh@AyQQ(UWU?aV$=x+'Ϝ )A)TG^"dНwR-dKIP1<6Wl{[g$g-_> A<T*QSȣ8Z7کuCdfTkLAGG3Ujz~&macӲe喔c81i>).wZkH)ZM"g P6TpVkYv%Kn`AxQ ul:jymYcpX,01LuRLFw|7!›W.]fyHo3FЖɐ~9#B"Hd=uBhlSػɖEXJrmH8gRYl&2ku/C!,eM̲n h_!p?z}]ɤ9S4nތp wΦIMqC()*;!n{=PHخIhgNturmm|48jjٲ惈Wu ķd2Ikk+?n_ĉttt .]\ܗ_`q4ӝJy1H!lk;dV+rrhhu`_!n:Wǻ`G^cb_zw׃eP _X %>pQ7NצۡW3Y_Ҳ Ƙ Aۿ}!?J65Y::3a{|W=REQY-:STAh}c*T&spVOXreH)yg1)%فYŠ:#lJ5 ]ЉB닾4R.`̳ [#H!رnxH!ƕlX#^2ix8LTn3n5h L~O㖑TL睆vR" 'e60Z <0LkX;:$i?%PXP)C}w: uDd/{7;H1#]2*NJ=) y԰}6m4g1` A9$zTr٬yɛāҟUciR pABs=+cxd?وYd\ ~q4@~v ĀagPy.eXIA7Hb掅kwWrY%]?`UK fGold00iÆ O/m[TUU9/J6N8= bY6n(h9/V;[!Z!d~\x0G Eߩ랭geD(fΜY Rsj-Zk##To9gkIH/!P>#ٷD4E^`xG5UT,6pwIga2Q2eXڧ8tN1IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/opfamily_grp.png000066400000000000000000000041271360462764600241330ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME 9dvIDATXýipUs&'ܘEC(RаR5̨i;R*3jkTS)B-ԢU )* l䞭/Jq0!9mՅ(x=ܼxhH1;p8[ށWpz^Yiٖª6wk JHMJr&Ïr8ͩ4yL80a"6ffitEgBAa!$1Ll![Ә zϏ Տ^o_&! b3 x,u(@η߻s( 9EiᱫL,ig|2:fמނ+J3u䤏`<!0O^c { R#4[#u pI{w%XcG *|/)p˸teZGX8~B$'0- 8>{{XY`KfT*E!ctS7a$s"5wqaA\ AT*f ??JZ] yɀqP?B\1p@Lhu8(mϜN(ıB:L`$)  xBD1 #ec @ 9#C i?(C)fsGVr~ .B)AB^3o kcf0Dhz OBDJ)YJJIM".j3K/\~򩧟Z{sxo+s=_?;;j: UjT,g|Tz/ĥRf?UX__G\6`u܏`4#IVsjrҷ6i66d"PwwV !Ӟ|tx[fp(S69#[ݽ?_ظsKWVWW.q<3;nnwNOvM d du+´4 YzROHI8"[SD22Y)}:Y2 iS=`=Lg‚6϶OSTMiIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/padroes.png000066400000000000000000000037501360462764600231010ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATXŗilT޷q ij,\5(%%QBZ〚㦊RRPFE,iIҪ qC Mc xggz7͹;w= 66O7.(;U8[9sX n#u13mǷ[SZ[[Č5~0-ݰXtM#%Lp@`ʽ|s }?EAӢ߷xSt ~]U..eD$IK)s~3@ }Cn#e!XƇE]70-m]=kad^@ q$ %A )$|t}p&_[7U8y^e].jx:0+KrKdaX!P lWr$HlI0m3=6Yͬx)w|e"y`D8S'<&"F: &x\H"خBMb߉)ronmܸ(ۋo2'q>BI˝ vq3kwRgp͖:/177 @M 0f4Iv p*/>, N]YQUmk[cO2idmxmtF.i_pjH$w0XBL }f7{G 9w> kʷ uGkª8eME"9.^%8c_GO, %F,F%Y"/uvj}#_ TGѴPw枹Ա /S֤w?ڌ""/Ep UhP{'dt!qvKA hX~ɚ.q nIoK[6`{Cۉg:9@{@ݘ&n?s퍽ͅ{QZȒEJ)eii cp$`6҆d2&cmf}_y5n̓@r{Q8{s)*[ee5zQٗB 9*׈}8t\?Y 篆L*j~w;8l"1XN~aAX`l#BL ?َ.S!F=HA^UK /x!Nѻ$k >_=ˆm2svIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/pagination.png000066400000000000000000000012321360462764600235660ustar00rootroot00000000000000PNG  IHDR szz pHYs  LIDATXjQ1BI@R_D) ƇNhmA(tᦴɢOP\*$` ¹ӛiҚ(sg.j ReY̟Jxs״)n_Vg~3uMvwۏ_)v?ZucvA_9@0Z,@0щMZ٣D[|^Dj.3 )Z'sOtށ,p ugֳxtX[["B\N@D"\j=^<}0ƘjͽiVkds 9m1D}<[$qq(V.A4˳}0qWnep!lαXv٠Ok}ڍĤns^V6yQ&ƹwe2W|U8UlC3_xd}.cb^D<p?Ƙ9<{·,RJz_3i+,CThHB3GhCqS&Pvq:/IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/parameter.png000066400000000000000000000041361360462764600234230ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME$=SIDATXŗ{pU?{^<(dEHT3>UVǎ8tjGh+QBxq4!< $n={d c;9g~w{Z]6w܌oY.jR3Uط@dR|ؔ;JҮ[}T~kKR϶ M\P].\"+/+'v?Iu ъer7](D*UUr@c8HBǻFߤei+tA|aRU'JZn`U N?;\GH=QN.pv+љgtā3MzG~ kjBJMh=^2r7>"1@RU'/$n*7ٱ)%Aߵ"BHnb>ś0LM炐$n*܅!DU2Aޓ衯c;ބu(kŋ/LO|?DBA`8/;_WCEyD*UurKr]{+ 7!X'=o?팲BH)1E"S8Tx-׎L_JUs>' @!N<$l%qĻHuBF yAI{#-y_4 of)yF"/R!{B̜2##]̬b`\r BY(|ʛ=2ԉAbV*Θ٨@j$R5jjDjݎ֚G[ D8Z.P^4ӑӶ: TWV&Vmhv Pt8ǟ5x:%M"'-:6M㿩L +tolkz #sA fgbHIӁvr. Iv:helۺs~KE3ou(2@#@j'J !(13nxh}n4q8&quǩ׊>>t[~;wa{[jbvldXncN!Ⲋlpn։ĩXgu?L@FcfUbH;*jI^(^|fMI͟?^<%n[ts?"!/<@|\[6:G2>=ABM;2ICdO`;o3 j̭O'WxYsaoJSzcky\k׮Q]2BBsq``9922:G@p]wEhOu 8E7 ӫKv }rV%#p"[--EQI*v2B^;/;`D7-:/bu=Ǔpuٳk^y}ny&v,L[Wcf\!B(Fէ tmp86pBض4- ~<Jr,jI4]û̩*Sv*bb|RI2m:ƎZB0,߄j~(o⫹vYvCq5۶ؾϹr;e+Wк8vye XIK2+?x \U"8ж[4Erq?[(^4̈#M4R9E +g?ĽXg;LYȀbk_GYtқG_ 8ɢ8oN/ ctW6q2zO)q|h54s=- ,+@z.3Nˆ۹|Q\ 㰒CZ`"SaP4!f6M_R[4OEi1E!?ɿ_i6\0 Fu iP>_>EhF051]K Si)P =i}˲8w8C4'EcdM˲GyأR:h ױ'F`2(>\ O4Ŷ]T:Ciؤn)"8 5XgD1Gɧء5wL(C)4uB0ϵ}RAT  H2+x  z(,1y7NE"&uLϢ#0>$Z5#GP}'q n~k\@k/b0^0uuMWP4At u6|r]Eoǂθ+p]OMG)Wm^Ƿo}e HO(*YGA<9EV#´\v-u-|\ohۏAy>Z!~\, ,,s)YJ°onXkp]J܍07y`xdy9oOcZWG,m#]plj \81C@aE(X:_e!f4X<7@;We~3cu8VEV5|H$B^p]tas74s8(~q]UU!,kh"JH$d28fXDx.B=FұqB`&IwR@[%+,qUU"e8x$̢xtU XLOva(nnn<=zzj['rB_qM`RJ۶̉xgxd$R<{\4{N9UpֽSrUW_IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/permission_grp.png000066400000000000000000000040301360462764600244740ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME &љIDATXõ{pT?޻cyAbZ-qt:ZX+jQT):j#/eQA Ò&6lq9# Y:S|+YǕZP #G^^c~NsX[d323ybջi#SL_X=|.4nEM(L+`8bcݪqPRRx}_јMydݶ9c,hp)?ԆPJGeXW0peW;>: 0 R\^ASmЌ|NI26 Ӿ{) 6,6aNg"`]{JB) ͕ә8T^ {YP9))/@Cf'U'pm7+)浗2~\)Z3>5k;9rcعLa_gUtcp4tbֿAfzσ4;Qy*f`ɡ`JiLbә _)RbZ&?`FcFV)aJ1@h'[A rr~ . C h6>(fˌW0@Rb3 ;BChz;f;3I[WpfFQQ ˖>DQKFIy7: Ͼ #55K̟>lė5=Kl|ٌ{H*`5h Zdyù09Vc)dB%ړDF4IIv1jhqM0 uMcjQӊF֏qMת1;w.1@w3k݄8 E) C7t )={2O(̙/g_v@?&M,7hhl'>&%h"ɹ7Hݵ #V!fj>0sxR9[2)DԔZFt͎tt!軰w0،Met~| ,uZxm } l~dZͶ$:;C(&ہ$C6t<3,(>:-nG%2tC)wUͣU;~&SY 躆&H!c464NxoGw}> o`d(N7+M3l ]^FX_UYP+fYOv8bKj.<5ZO3+i9SfP'hrpge!ED',;RC9%uk/S|Ŧeg' |\\ʐsB~[ivO4vYJh6Qp_P$0¾}Fb5ܤ97El޼ERB)hkRۓ2Eᠣկ T.L{uq՘Lh+p%2nNKԂn3ܗ!PZ;Hۧ=0P?kmIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/pgsqlModeler48x48.png000066400000000000000000000106361360462764600246230ustar00rootroot00000000000000PNG  IHDR00WbKGD pHYs  tIME 8 iTXtCommentCreated with GIMPd.eIDATh޽yu2*FvH2f3)/q\.'qT*N*ƮS ebx`@2FBhi׷N~of$ANU^~}继G1ݏPW('26lC^mӓ"E;͇hL.1¿hm_܄ b^vo hCTB"*Hy ZG-Z~ckCKKx/ {DcL&2&/@F 3[Yu8gq^ãՓ6\\V*F(*[ [CCq%mrݺh5Zk1  {j;pa&W@ET'929xXJMDQJJLd,a6O0Lzr"΋5k,Xccio*RM_xgU!m{Wo{'K ͡z:$OrNy#dž=ď&^J/j!5&]}c68#:B Xc8{)|\y|Ώѹrm{KFP`u\{)[K;z^9`9bN[ E"Fx@7@)x5Ü#j;|qtN|Jк%bk{k;#wBzٳrӍ76j\ޣ.2s)d9{ Sc\suގh͋NjL2>A񂳎8:}buM;vQ4RJR[DI&"૱I6WP7v;A`y9I_ !B#3WNy 6=r`?~hL&# He%Wu㶏//iEQ5pOs}gO9vxg1 oA05xv,\R/$]xO&|2' ϊ)併n}_\K65![V_>fu#}aʓ2r n |xSU5[hE|IN;Ӊ{"z$ӈ\̀ZDL-i1 s u}1ŖrMd-0s8LL(df"8*TyaT'z\={|Jpk`'xgindũCC?/qa*Fcu:&i6w"V!|k݌dvVO@SJH ὟITw| L#'25"޻;k0FcNt f$WAD\ _) λ$)j{pq=">44l&+#Nל:~!4<`ڍkp^fLF;Qa8RP Ϝ;\ĺ_$ A)dNwFmbdlTcLO&%pI/qފd\F{'!d,H'ŧY Y3ruTj`& w < :k.D{Rʥ)v>}ȆJT/`.. B'َ:=8<*lPip&ș﯌ZNO-wjljjrVMKV=q<F<=Eiz QA}e'Σ Gqu70iw"^PL E!$,hyskWu:<C3=֭[x;LCN=5>&T.Xf&?N.D* H2xK (2DM-4,ꢸb M+Ҳ.TG/,O[cf@s?w츃ow׮1 Ƈ-mMIZ՞Q y=fz =6J_YfD% h؟~#S-WuBRFZZZE5C_9`JcNTk;EiJE58 "i##uC9ڏy) Qy h'z~a^=͖ҹsu7{.r^o=7FxIZZ 3{Иˡ:ߍ`AjD %x|*KVRq#_e{vdfߺ弴i~ƒ,SG?_BЕi(FQ!;=ML@3'f뱟y6v.cfNa%Q-^֛W|G_@_Ht5iBk%# ^ ^^"GK"S9}1Pڔ:mkPO?W3\1hJx$vtbK+.MR}=x/+.!۽ENĔ 5b(c)UL?.@׍չt16ËʼnQ1v?,sB8B\yÇhBǕusrN<0.W^BffVC6 A$J)}Ld xL,.ݾ3R28a̮!JDpL|^(~Stto"VҪOgNl"\Nffk6^GMR3y ?vʯ*eA#.X*:"@A.Z:v>EFΜ@n$m4[$Ay:v~wBQ㽝e g*2otU,^%Ϋ?a~yA:`Vrk6ͩHmI^37z2iMps Ce W،kLN VKWu-]*%H%PQFafA [vKz23yG+"Ť~c ,"uZfnjvV@j|Y2c]nv!f3{zOťRDiȄ5znEK0Sc y7'@<~0Q(Wu N`4FNU*ueBص[8èw~p^Ce@xLu!ߛ:SDo]'.8 \Ke1|/NRH~tA?еxQ-mא]K pbYk-Z8%Ňޕ%viGC$߃b+njf2ڕzAlq5MS"7uzzn[kfD(Ejz򑻣U]·-9jzAf,{r?yO〱J:@٥:΅nm\~3'3k-}m*Mݣ3z䥗ǸX.ÆѴ<AKFLvn\qjZ/3 _a" IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/policy.png000066400000000000000000000050301360462764600227340ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIMEA IDATXÝ{pU}qMHHHJ`G|)V:(ՊZT&& N;u*V+eT^C!7 ޛs9gG %@GqϬ?Ξ3Y뷾/Ne&dҚ!{tXMkG766vk+M,FQ0MKIk|xqۮ7p$,{+v)wOa#.\H2Lx+2p 5nq+|ނ=bwpqmIU(, ˲qֱe˖<F hNG뜽fՒPvnS((f*m9ғR" "ީnj0nqaMIRM!A3}]+NDwNvɩDUUU\kmTVV8/d2r2 /d>c.]07,շ~[् gan̈bt@Ɲ>diӦ2 B5Dd2Igg';wtEYfEg6\eʕ ~) ! >שS2 :P~y5Bvn'W`&D֭+bf>I&1gΜĐ < ya羻u|b.E_=Ԏm:n}-[l3~pi~/RJ9?:e`S/E5 9w8# <J)I:Fk2JԚH6$c'_'0K}t!i&߼R0G'ւi&Ϟ9uI*l|&Z7AA@UUDQĞ={ذaCƱ(n Ju8ȡi+!\pAڲWZeqE9mJ/'q(e IʒϚ_s |?MMM;lݻa X)ex1K|NdiKk1M2EN@ػcc(ŲLb4^j8q\ J(Bܹs۶m}YoE09.EMu)hJF;?Z>q{=;(e a(Ǡpa^y0BO%E鴃0Pp)8o"D!C-,=wz` [Ǎ&Lp\.GEGGQDXDJIOo-n@F)B#F0zZX2 v0?P|8Q]qd"(+ Tر1j"K&*By  ss8JH-VyKH)ޯ(9˜`Og%e y`+F3T"{v O>tҮ@ y> à+AH %*R]cNJG>E}*|Ҽ{'Sˆbw-!4h,ç9{;՗eeR o:ט2kOG>4nܸ+Wρ8JAh"C t{3f6=;wqb[q#A1텵(pAW<};[Qۧfjll[g &7"Ad_ޤ1DQ[?2K'av7G~zEavs'$P7~iW #700X,㾩wۺ=zY"Ed'ǎ' }4i{PXA|Css3,))q?_UONuueP pP 2)u*ӎ|K8#/w5viQJɘV 3Q؛k߸Z:[ `-IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/policy_grp.png000066400000000000000000000055051360462764600236130ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME`я IDATXíipTיj-! !BD 0K@L`T!c0q L#CK1l,ep2$va06f Br֒Znr1&C̩:nysu5KJJt00-YzJ:!ޚtiJdLuuK.**rf.F%R}|'9yټ9tf yH$;vD t؏ +]s͹3DT 75 H&nsڵ/۴i[> P[[+ hNi]nǿ;> a{$FNL91ؐ;>.e:m۶oz_ZZ:7 R[[Q]]=p:d0e)S0 ۉHێnENMMeu˙6m PWWBMMg}ox1-r\7?xj3[wɞ_y2ӳxxCHΝ;hfrg<4_:| hhh04{AF#Cb&Bh~!\B7uRB0oEDJp9] puܹ{Atb-.ПLn 7MOo&ݛ-䁕3g6_^?9E$MO2xAo=-fϞ͙3gl֭'N,:'0=xwDӓ;#i"W38pVrsDŊBx^^/pdYH$7mڴ]ݵBuu .&O2AڜxfE$'ϝ~ߏ(躞vJUKo+Zʑ?xZ[?kׯHF"6>#'?cE* HKKcppt |&Ydv7'p53uQ]3uϫGz)~E':- `PMӘ:BVUVY2223\aZX&˥<0def""a̜93';;{(F,Gu?J{{6ڇ-Uo d d+q-?Xv7c^@x֫hi$I:;;K.u8N:p?;҂J$qFWt@Ƨ;f2kt%\ (ln_$}%K(|;Á  ގiNYbYMt^scY{̺[їN~ȄEȅKl|d$U EDfN r SWn#Օ›G`IUDUeAτ~8bمczk%sjht"EE( ,yЭrR23 qăP.V3Nicճ|k˧Q1No e!+3htKh:CU sJiFIqHHɫ$u Hhx )3}k +_&z|xRad8?an6q+Eiъ&7g>d0~oa[*}=tHɚV=xySwr";oc}(ȏ7J@{6AtmchGUUkwԳ"CHh&i0ұ8QץcmBSJzz%#f!4hFt 8RԠドo:|2}GM.\B0txb'}y|oOiA/ }݋ÞŤ_NwQu$z#%b5m=aA[ғʟ#Yx砛g"X~bK.Uny<iѯ'Tnt"0MQ24]EBZo[/9IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/proximo.png000066400000000000000000000030311360462764600231310ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATXŗiLgBQYewQmz1iNLScmФmZCi⇚bbZP BQE-@PD`ݹ߷q RǛ<{;1g8FMuEҢRh)4`B+6P δof'%M|z^yMps8Ǔ epJ SuI;\D^{-1d NOH[(N j۶r9X*%\i"_|r:.9?.Dtnl%qu]"8Ҝ2  6Jkxy؛iۑϯaD Sf=>B$ke /*hhhq +!{!wp'mb)8vF-X9e5 B4@DYCO+(,?[Xrr7~is_s ӽŅ?fQTd|9wEgû#@!Yi2.; G>нTסwa-y_cȋr^< 6ZdEO8# G!@:v `el*x ?سrrW_cP Bu## NG`q9x/]C՛XЁU Ksz=zEoWjF-ce%PT}Tqt I (IDeEWdʱ͙zC305u$H@"'tL-J N)D"NFJr9i:NEiA>#,t 9m*Rta,TMCMm }}8hwݮBBhr 3!rRV$`sEEթJ,اz9k'%:P #1!1?HbG dEAEeNO>/R%-i cL55Iϩq Nilq) Č @h*=XxL`Fg Xx<cIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/quickactions.png000066400000000000000000000050451360462764600241400ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME؉s IDATXíWmpT~ޏ$ݐeC" ZŒKKAq2;ejBKFN ôX: V)&TS&[B%݄|{NHбL;gw}yw `m۶-9/E1m۶&b??N%E YCuzp ۷o/I$IB4\2m۶!mtZaa!۶oNpb}Gn%2uTo4}ZolllVU7wܟ[^^.PU7n }}}ϟnYx;999,ZHZ0w\tb$ ψ'xBTUȑ#遁K˓'OV~?84 8 mڬY쪪*Rv)gt] Y8s̾-[xIwWTTT-zuh===<^^pK 6Ym Ȧ= ΝitZR0\3oP`I@c,CL5}4M-2>i  ;2!(vs*@{{;ƍA@M"T, H=X0JS`ܙ Ě*/"ZZZLιlKc,9Ni&)sBѣ->oƍ CLww=>ASePJaE1H5\pByNǻ ƌY=9%I:dɒiY;͔pA!˲r/B&k`߶>]i/ݠ:8I9LjC$A?)#]ح+WWXu,BrXt&ήO]0t`B1r$-PnZh;vpymyyyy0 #iX'd\68ؼ6(pp8s2+YH?n4m>lRqSSeySJFݍbI 'yQe²,X]a)I2?"w;$8@ dDJeYޱtR-*h{x4y(r9r۾;0HmxV}A)VIA䨉HQUlʔ)$J]בH$!34FaYԶvQTTd25Pơ R #ҌDQrJg̘A( lFss30a|H$0MR9ۇͬ9.~aaoC^8 vz6ߏFg pefx 񠳳7[:{wp;v,Lŀ$1 ^ѫ}712CӖe|Dxq7;!yhHVUUꎎh0\k׮o:h__zDe/EŽ~ 될oj[vH$p[[L&/,^s}+V\nlӕ{n$I~_B!@uuuG-[w xsqz MA8??m R}YMa$S=}ri 2)I*a/X`*5G?t+FS/GK=^8`w1_O yÂ"`$sCCCUTT"Cx 1}%r/R&ܞ\"?esfqƈyk;of0GD@W~xYwٱSٿ_ۼʙ`-.xdI$9i]} 'WvWJpKMZV[Np8ř3f¸V>$-R~u/A12B[|3IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/random.png000066400000000000000000000037311360462764600227230ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 34FIfIDATXݗylUsg WQNR4\!RJIC"YEHekB"&RV)PH’`Ҹ@) /5`.om[,65Utu93M|bi?y̙7/\ΗآEgŊ͘1;FRwq4Mz}}eeeߍb,X4,3f[H$eTN%K{n'򹆆ɱX*lFR uq^ZZZ'O?x7rx}G՞={T.StZ]zUR)j"nz۫Ο?:;;UCCC0Ơj/lll)Sf<)%C}!4uMӘ:u*۶mr6TJcBDf~a RH)GRJt]l², Cqq)%}}}_jWW@Bj&Lu! X*+gSVVƖ-[&֞zz._# #d,}i3Byx'HyLR)Rr jjjFgV޾gۻ>&ܲH8E:ۋ#9J|߿a7Ǚ9s&J)/_jxO,QÚ`ٽnR@ r8MӸl6˗)//̛W?   MMb[abgΑfSFAXzxBk9t]Cuc.:?پDЄm  N;# B! @)d2eY/s?0l"a>R0gtND Jq$ u]t]G)޽3qF@ !B\FJL:`U,Y<)!5t9HfJNggT48"/ N( f(L8bDIB`6} !=gRSSMт:T ϱm/_OMtCITæmOákLuYє|~uJK'띃\O7_Xxg -%*F/HBQ2?}rG%`7d,t y[ӦM}i'V^4o@ {B ^ye(UkW˹(m.e[i"ɠiBsoD/^䩧4/mܸ$F(R)t]cow:H_eX> c!tuG2ʁ]Ǐ]&sέˆ p]pX0O(vÏٿOsTb'g͚իWT~@A>;{C;ٷoH\i?vka Jmyf4<}ݗ.]U<\2+]vm48tttW\yѣ?j[PPy6UWW|oIv$<IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/recent_big.png000066400000000000000000000070541360462764600235460ustar00rootroot00000000000000PNG  IHDR@@iqbKGD pHYs+tIME0&X IDATx]]Uk5_x)i' i\*JҪrć?D"'l6nj]E+"/_AYc#NbeeܾW~/<ҥK;? 0??98 pرc)I @elekrn1}d!"$I:w` 8|sΑ)q1Q @evi`7= kм<\nIVׯITߍ սy#6T K@;`<b M Yh4hZXkq8|AD |{ODhݭkn(Jt3E0MS(ﳹ\c!5,%ro4u(l{4%jT&A@ >&UXnO?>_R;rzޙ< '(vo٤'7A IonUNomnnvX Yp@m$!h4L(pt`Г#\. htLp@hVD*gA|#z%t, jTmlv1Ga K{ PCs+wJjgэw@ `e eh#5d T NopĀDP4cN:7ri@xm+~Al'|\Us^(W>vyvNţaDLks7Gjy\LomHssWq.5&.p5A7Fi|#`0lJ:[>n|]!(&. +1ǿ Q̱_EkAn\ .ϡQ06@X65q1 J7Ƥ}\k.6FvaPr ȩgU`QR#={>Vpg荷l}Q 6.)@CL@w{o|]Z;rN(ȣ|@8ɲ { 1aW" _sQRRXdxaGEΖ"bv1>&c8SCh,a1r=I"|,.\EWS]꽴xcHX WA] ͐s8E1G`Mj =м0+t~YՎ"t"yڍj=y:VL HxLF xAXL޹rtI\+ Yz|XdixˊE,>4C6?tc:^(+NCgnVP0APvJ-@ sA ڽP|? cTsE׊~lsKgU6.ZYjuCd p8}zmM&}@AZ:ۆѥ \U`&*퇐QC>#\@8,DW5*+ARȸ xٳ-k{2x^IH*0tvR!ǟqم6*kk;VUU <|,?At}\, CY'';Ceq*vhH˳( yX}orA rtAJnd;mx֢9ywѵDW߬%@Fi2|`@}/Eۛ, 61GBD,dQ9m]^G_A5'L?@aD78dr(=$'a+!,׀/IWrϕN_(r)M7Hh/IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/refazer.png000066400000000000000000000027361360462764600231050ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<pIDATXŖ[lUߙٝݶR)޸GBT MVcFYD|GQLLKb$5ATB@*ZJwv/s;nn|9̜93Aqx|ڗvܳB~PpUB)O+yX<sY:h9]@ڪze/ *Fn,Rǧ5" <_Ϫ7r5.mmǧh WYf. لrbgO[MfWkO(<9|RMH6a ȃ{f(p%69mOsg- _vW-D B0L)08 lf1;XTrYEoe^=tVN,{lC5:&$[H։'EMҵt\{WO0ԩV/|tGWkTB0nm6OԔr$d '4-X§Uŵݠ> ?${0w$(q@ qnoѿHd ۣX Rf@!Gy0dP98rJmglij@tHMZ|G;X99'@Dw s4ɍKSFPHiQl:ysKoOm:H)ʁƑΎ`aq(|Dpr&wN AMȤ>ND$aJ(i[XtlCN @id6aO$pj{EU_c΋MW0%3(4vz9s;7N tYf<ȔK63ۓ>H2܆D$3!QPuQ݊JW'Dҥ,f@e։U?V!R%lf'$ˤ eS|LI8gM ).B,m (Z:NӞ:*glU_.=L3W]|Zx( d#;Nr7YqwsFmYh@"VatxhKJIsh;%m%S||VKkÒ6h Fq< gR?c FC=NGI.Ffw;2 l#"UDftӔ>qXrԮ0?rsIBB-0-g! vkK>ru"OW|1D^ 򡬢=pdA4.|,cҾdA}!/wtlɡx-H@ERF677-߳Z}ETA)ɊXIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/referenced.png000066400000000000000000000023121360462764600235370ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME-ɝ.WIDATX]UU;wkƜi4B_~@Q!CdaCEQAPBRhBBYRiM3:\u޳^=̝iln53]{u:{-d)k Z:hΣC)>::Nt\.5˃Z;{2*KJC"XZϷ6^`5m uFEˁoGnV|w!c/EGI(e$]DW( L;$6 o|fg";1w';i\ !s58wpB@)Νxg k{ߺqNy5@=+tc(6 x<'͌7G?~_ "SJ D")=I9\uy+K|/pIMŧR OL1+xWb)oQ3N`1DJaSTVnYk[z#lWo_3Tw6)4cnk .NٱgmbM  &x|m됯 AX!lB%-tWmb3v%r{?f=n'cJ3wjME|'evw}y c]xy@kM$\ScLWػO#cPC&b;v|ΝӖ֢ۛpIX-""DiãֶPd2ՋQM[mK3mHak;E\.#"MU:"ơZ0(Rj\ SJ&B8>9wkFTR{s']W_,R%IyވTZkֺt:444l6f㦦&gWsGk2T8 TH*%P ^tIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/referrer.png000066400000000000000000000023201360462764600232500ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME,3fX]IDATX]lTE;v]JY *I@ H1*J">OL@4'F&>>  5ԢĂ&-Mmw޹s|hW Ķ񅓜;gf3*(;v'vn"E) $gw{C'mVvc̪ (:2!KJ#!8e r04(rMMK`@O8r7Jc7W2vX؉sǩPEx-?#F  1\(5 D`d@@SlN<3#x+nu]ӗ2 8NRT.n}M'q)TX@W,^O玛"_>eH8v.\f<}G\ Dk8ꭼ 3gZ[nnhe&< 8qgA-;ljCG/]_c| X%&vl*"Ddҗ)/cub|$yJ6aCKd-Q\^S( YB["Ve QV!=<=x$QHTjz<L'4A$ Wv/bDQĽ+g 8/(OX>g 6lّ2s8~@śXk)JYz?.,壯_M<c`{m( ojL{!)(Pjf7oIܾ~#|-$Z[[_ܵkW P[5V@&Zk HH$h4翲`TA`7:)}e J%JL&r 1C_}F:l6[MK HũMkq%L=B}}f@ -QJQ(.TkF<|ߟ1a""*wttdT(2ƞf``ܙqڟ/*c7ITXEDZDZ'"ZDRJRNk1cDNK\n(˕٬<~vNrG(wTyZhpUE;*R$IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/refreshdb.png000066400000000000000000000040531360462764600234050ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME;AуIDATX{lV?}KK T.B+ @DD#n1.ZD#VƙK4b632DpަspY&Vn֡X-\ZZJi}߳?N:1?{ߛ=}>M߀+v0\r3;axW0QS9LOo~MWCW !-gPfQOWSU󯭈 H ~@koicJ'^]˶Mx۸kOKpzsYuZeRR:BFw q{[[ovܵ捷 k`C=~v]~UM1E!ٔ pDP "UTԢjQ:^RP$@?y/Oy跫q$p_^܅޳i\yіֹYscQ@$C 8gg`Yn˫=ǁ7b%̉/\I+AcNU#>w1:+V`L8BlZTA# +MR[>$tr=l4 a4D80`< V2~Lx'8$}|Zu%* X,>LTׇd^ Vrs Oda)rlE]!KgȤ~=|)@O cx *оw~l6KG>_@>zA w>?9J,I3%',q8 8RæIϽu? ,a_w`n~z_-7n_9]~~xb `$vfb jͨ2j49H1ؽ6(/9'6sؽ_4''F,lj9k}^Z*GJ:d5߹7^P?:.=lY]\[ܱ>^2O!@ƾuD*I_ ZR90@iI#'->9QUfJnPZ~5NM6>x_rdœjjΚ^C>*AeI&PWwg =r Ά-x=Yd±ﺠq`8wD"1fjy+1b̤%x%`ޣ-l`w/R_lh6$+v ]yj.>h:Y IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationship.png000066400000000000000000000021501360462764600241360ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 21ƧIDATXVMHcW/Ƽ`3:#%. ҿU}хvi n,nL3<)T碫 ) k3^=g =p$9rp84uKK1"B.C8> .onn~tW]G}h_}W9H F|WPpwn9~9ׯ "haxPAur;p]7)e{Wg?hL`kk t[[[CPxx۶qxx\C^Z]]=+/eabb{Z$A41y)*J_@Ducۥ4vޝ~c7Μ^ " @hq@ iH_DG L(S7)e;^\̼H)ѥ)eömB!^$Vmp'cfRED\x<溮 @1`&?RRJ,,,pLiCW-kS r-|c0T*뺸*,jƆ`,HQ%hUe;w)66?Dll;wt~?/8m*pg:? D:)ꮊ"VVݽ]mV2*avZ~,DX,d֖UF:1zmll( 09WшX׸, Tpuk9jڣZQ}ZgjT$Vdr2:=oX,T*ŲlRjVFqfp]WRwvv朻B">/J&|>ul6JjZFql6[U00i˲֍a2VVV_,gI骵 m^^f1rH&~Ya+# ĦIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationship11.png000066400000000000000000000024421360462764600243040ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME:`~AIDATXŖ]hSg9icS5kg̰֢EKS0AagC Snv)q/DvQщ` ^9]q֠u&9rBmx!ys~0裏&y; }K0 %tۑR:RJB½}6nQ@`!HPS{ݻw˅"cǎqGp2YE9W\3 C5o_|Qu0 N'N@r(39?k@`ddP__Oa' fffhmmED8[R|H* ܹskt]gzzCoooFp#GpLO:ɓ'u`lډQ9G`nH$!̤vgnܸˉصkWL- MӤy[p;/ѯW>ژJ*,nݺTr` h'Fe^QRMd>$+pXѨY><)OKk.,RJ,@ dnzC}xZJ EQPUU9UB$ͻwLXҿE>'RsݻLNt:M ׯ_?u^۶K4޽!cccIQQH)y{}+՗Uɱo$p ===[iiiq3 &tD W-ƹfWN5HR.l߾}ضd={,+paھϵ[q&>{MMM-65|<|pV=p8\îsQRJw0 C6׊$+p'}d2 @*4]p=m_{𡆵ށE)opp0,F LX_5 Muo Ų,gHRfT,R"SD%PB{%FJ"ӱ\pҥKD"L&T*4|˲>۶O5M[[oҎ;} >:̊j~0T8>eֵ M,U]iȴ(lZ#~/ΰ_:]0N)MIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationship_grp.png000066400000000000000000000025251360462764600250140ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME :eIDATXí]lUN%$Z"D[`6I#ѐw1(]Q>B0j%@cHXqEF~MԒufޙv-Ѕ$793;ͭ7yu͖DOdN?‹޽[mkkp g.2.MaRN|{G?$BO{8G}^ HiCjnx\:&!_z1H0F2nJnR\hBKht!4M0vكqI RaF eYp /%"DV Q,`Is*o"ѤbU4MKY!˥Xa ? Tz\‰1hwΧ\بY0ض-R1NԫaZr2HPJ ""˲ RBJi皖0 js*E%.kD])/b6Ij dP]]}adv|q*]ŒmJ"P~=眄9!3mx=T`UG-k~6nιm`!W4eloaGjkhKZwlϓkț؄}XxAU*okرgWo n[[UmXEאַj ]b||򷆊pW~˶q,nR}rءF@Vh^Zw9}`س߃#H!p]ab;z.TEqN<Ng_s>s^PH$pvە(|";r뙖 = bRS>f2""D vWJ3 ʁ'!“eSEbHTÑr1Q-sv̎ܰPO츑Q"6ƎGVXgoAæpWqaYV%pʎk-);\.L, ˲XeG6u !tzE3R>/J lx'6~.mKcw`aOOp8ltwwJtuu;e IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationshipdep.png000066400000000000000000000027601360462764600246360ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME2|=pIDATXŖHw_:uK4-t &*hĄۭ@D`($-lL\eҲ6rn1Y^G0+ץ9qt}.5yyB:uʖڡiKiaxjkk?}`X:v5:$Ozѣ+j] @XHR^(^ϊ +xe SUUN8AWlk, =.ibFDdLӌJ].W4%n[رcǵg|||CEajj )imm/YQ477U]jV(G*y/ݽ{M6aX}z,lVce@@QQ"5=zdMz E8;;˱cDuz266Fan&x:ORRRٵO@u:;ͩfJߪ$---2YVA4 ڮUWW v]N YYYGb<ĉit:TΖy  w\Iu HMMŋ477rظq#"륩 UU)++Curss8ߏa pq9<ccc`a`%y`C|޼y3)))x}l6CCC۷4 zcfEO|ɮ.lBggg0>>>1355(NȻ###[{177 4 ٳabC@9;г{ ׷JjjjpK{{(޽{EUUu]zzzirx%=pO`YYlKK vn0M#G`n`dffre6l؀f˖-KCU(/'&wKjmm-ZTn^g|NQDgU jJ^NzĊU-bם;w_/ F]*8NG j|, ܈:pށnr)c-))GEˌma_Co/` ;pI{ajAެzGnHpEUU4MspUXw#DlpP+aPJH9# Me1t[('Ozބᤉ Lr H  aij۶mojh4-8gZ]9`9F!WՐ$I.KG9W_hbYM_V4+FUfMYʭͰ?:#JIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationshipfk.png000066400000000000000000000023741360462764600244670ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME1^ IDATXŖ_hSW?ޛԦvY]>7 l 3aen2Mʠ/uNٟ1R=(èL7UkK]bA+emlj$=[j4s=,cǎyNEruu?.TG۷ E뺆xfww/ 4\- a|'(]U\xWk͜xe;i䓹(04Uka2`YRʢR/`YV0Ms)%pX455]H$^BPJgWX7*̰w^FGGs Xv-oF3!DG-gdK];tH=mG]g(_c1 eu֯+#奐+nڴG6wqKgb4@=ķ_'J [ Ps7Y8@WWw瑩w.gP8{,+qo$eD"aN'===>|כiܥdePJi/_=%,ƍ۷iN>i\rǓP)[lH$}瀷|>c˲ʥ~ܹ0vÑ<!*jjjRJqF ɓTUUOgg'\#g0Uu*)5iLus͛]HBR3`nkܻ|_VȰ\́v(v,f4M)~?6kFϊq 7Ds~k/ 3Cxa k5 R # ٓ!l48Ns>4 ]׋l\5)D"CK!2i *[˸pB~BPCmm0S;r{bbFKk~~~M2tR)Ұ,Kollj&u]O麞r:OnBuu 6<rbAYM'Pb Gz^++.W%%% ,:JCPC1/_zrſ dӞEIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationshipgen.png000066400000000000000000000027051360462764600246360ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME9EIDATXŖQhSw$5VdF;S):2%F* qi JܴFWn}2SfcNZ)u6]]K{sCTm3؁ |;QHMfa޹sgIq85.7QrMSFIPUug.gj(اneŒh_`+3 U!/בc(:=L01ɞa Pjkk_~Qz{{',˶mMdǎj*dբ.XL{Ӕٙ]WWᠮCXl"B$UUx-Z4eZ(..n*>~xZ[b&X")DhnnnuuuECPdxxz"555KS]]|sMt]'''˕HqqqR"2fV@]---۷ŋK4'N ^WѨDQq\HCCCrmppPΝ;;M*`1{{@M 9r Bɾ}0 ޽{,_oMwOdGuF"kwwwV__3t]b1a4k^r4Ml9`FgrRƻdqk|]2]ůddeem}#4YL[©%gIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationshipnn.png000066400000000000000000000024441360462764600245000ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME g/IDATXŖMhTWM&&$j&886JK -B YB E&H"Ѝ`!B $G ih368o]81+9s288X}kWR]]]o[):?+p]г[n oiX+^߄-Y^m~mW\42uJ)Ǔ'Oeppnj: LNNryGCΜ9˗yc'Vŀi_߼ysؙf=d2thhT777;q  vi$IN1DMA1dr._,,C$ȲvmDQzngP^^~y099QfggAD[s% ۺt:rsscMr6 Va8|IqLe\ oT-}vvj#[EKO}fR< 4;jLL˳@< /_|>LAzѣG444DVw cDn?%}$j]TUs:%Fh#\Hχ[nAVD"Ž{pb#\[7a-zZyDqcJ_Cwzg[W_Nr?~ ͆X~?2hZ~@AAFFF "8N@aa!dYqk<44I`4c*ZG_pap,^veAQϷ @VWWCA$ܿGVV:zzzOy%Hx,rjr]]UVVbp8L`8: tjjjjj(55rrr4??O}}}}`;bIJ1E===%%%/ER$h4LMM_:;;GA@>b3!i^(@JqʼnO3a;fF $)l&q3*{7J5Q)?mrMjll̼Bow0 ωlv"tF n?*{7s8 Wؚ2t: @(322r1"bQPlub  1 A/j56G]xQcccP($3~ \$4t0 |ѧ|,k̏z"5|s7 v:H)q\#QA~oy" o]3Х@Ճx^{9J)#DR) $c" ^wX^^F6] ,pJ""q  %Cxl[%%%-dat9Bda3JmM5?ojhmmsڦi3C85qp\7}yL1)پښj^Gm2/.O~q!@iMpO(xvڮAUem0m;E"AP8apFݩeh8Rua6l: w`4P,hoݫVΛ=\̚=Wg0wɎ#?覍/OlڶK:ݟ@߷;u ! r BQ;5eOl(@\zkRGGGn4@u5//`0()5rl/ֶ7-.p8===g&ܵ;b1\ґݑؖc{XRP(tD91l2"BNN{D;n;}^xH T 9~P8|, `, `, pښcC,mD3$!vLsGɓ>^fiq8ND5ۼX2Ʋv4M6hwK c0sqHXem;sLݡfY8N$I>O@O GS~IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/relationshipusr.png000066400000000000000000000025551360462764600247010ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME }IDATXŖ[H\WscjV1h,[1dl@۴4N_ 4)%AB !DX(&ё$6hc-/DgՇ8NFN >Z{) .%%%]4m;qi]UUU'_6O_t:/xw&4-0vCC͚k&jwͷ"`5ܝ86a 蚺8BD]UH7g, 4& "['`YV6zWR(Ԥ߿&&&]TQ~?"Rty]Gqq1~\.Rf#C%zt:xʵca;X&iiS@Dp%'33u CUPae^xԔ;wNIOOQǏ *TmEQIRjLH)_F22%i[u?vߠ<y"1cExv"ugfddatvv򾧘~m1XZ|ƍ_rp:TDAY}Fe!"<|H:"rJKKl6irnn˲P300ݻq8333@~~>siv;TVVMKKKU4uuuaZQVVi1]$N8 ٳÀx  iƑ#GR)**n @II ir=fUjhmvR`w(rrrʕ+\t%4ȹrJ[$;3S{:oׯ_߻woz(mya33omDvW[u-p$2^^D$_SQ7 |?w^dmbeFA zM1_oUU4-UPVՁ$berEQ%LjYYpJT!("^%;dz'/< vyА0 snn.1 &B!ieYZYYٍ}4M %$$,\%`9Wܐ H`zv򸺩e+q i*lڔ>z<=,2ֲt2 IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/removepoints.png000066400000000000000000000024611360462764600241740ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME+[GiTXtCommentCreated with GIMPd.eIDATXõklSegt崬tt0!"Klh$B" ɾ&S ]D/q0`p3Sq+ְAퟜ=9yA*Ián%8pO@.iʘpiu7npRQlT,Xe=9M@w/5n`,ƵrNȒtxhd|Ruuux "^|ۊBB nw4#Ɓ ԇ}b6oQà$I$e )p3G_AY˥z@mطO=zT߄MCN$(z獒̞ED>U"$]mmm){d /bn- ɷ؀ xq'U"C7lt)v|D8?ڀt؀M˗ 0x-bi%p!ƦTTUU_},tHLx<DRښAͷn_J8BLx< b^ֿUU3iT7f &<i@k /oXSv Y&V EQ ]Lnutts <!dgkƺdC7BЯs31 ]@UVTEF:fI*N66_d2և큦@.0MˆBCqp 8\֕IԔpJZ&`&e%‘G]m~~ND#yn-B6̡ÇٹkW |}vs55s] ĀvXl NGss;>F TmA5}?htV2i BӺ(*IsYN)^~ZP~_8fdz6ٿG$l% n'V%{__݃ITWl7I@$HuN禲x߯L*+yd͚ cB>onv C^ ɮ`o/x< /挾2P rf\zNn~hP=!woW&D8 m}i-1 Bt}(zHΤ?=pIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/remover.png000066400000000000000000000004751360462764600231240ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATX!NCA}k8 p pE3 HȈRҤo+7$I$g_>~r }绋ugv.^N@)5Ng= ^HKc/Jj{kT퓦{5Sd L07-Mj%/^^g˶o^UFCj.a&c?pb>RUf/I$I2odIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/removido.png000066400000000000000000000023511360462764600232640ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME 7v$iIDATX͗oTU?;3w̴̴RQSE@ AcPdY@`"Gt!+Ik\6+b%`ҷʴwft9?-8u:T=ws=9cqSGm< P+,01R:' e(eˆ`)T ;kg6?rͪgj"nu! 敀( bQ]E͋uwY)׆mgEP2fFJ95oBo\>ךB L>;Nn"vSsqޛeNQe1/W).P6UM+cx29EÊ D#6"\ Fn!vfȒ~z ~>Url hcP{[R"XBdt(d6fDP*V0Ơ 2NKj,cnh^p\ZWq#J|$yr,ln.64D$Фf[ї[һmLfs8}sfUPbgmm<|+9y߰^َ {}5SYVeY8˖##nsb&g"08doǬZ9+߻ӭDR)b{줥?44гz5%Jx0Z}jmI&Ki]_OϚ5 )dUαm;bv(DpӁ[;GG D_b1ǶUulVg2B* 7rmogc"خ}Zv:kCx;AWW d#dֶXb 11KD,c4={}ppPVV*7 |ms&;w|{9[ `Z>jjҽJ S)WORRa:-Aͻxu[+h׉FqBy38pn*H$ɉF*^vL{u߮ LzФjku?xn펯Aw]'mX!Τ6kFO俀9VMS@(>r"+IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/rename.png000066400000000000000000000036551360462764600227170ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME2}iX:IDATXŗylT?^^/ $MA)1TEiSJ*jFV#\ A%Dii8"s! $461vf`S";wf~"U;`TIP\QD偁w1'(;KPB">p8@YA^2A< lV .2@ $P^amۖgޑRNu]2D}_6Yl6˗OxBO̞#-̞UNށ)%~RTUUQUU54MN}\G8TC8TM8tp3.G&$0] a(JWFSSeee~RRRa…1|.]6˔[vɧv¹ y|Id:̑>}q ,ib ZZZX`J&Sw֑Ak{! /};8r-)hWq^͛QJdɒU-Z4wjxRJ^&70%GRG~J^3R Ƙ1cp "EhEK Љ U]i4]?a•bX*&?j0b\tzD"!m( 19M:$Ne?k2/wW{]A1\CF1(}ǤXDb\ Ry܋E?]o ""+s;U +rH;zYl&4YL;x6<Ȅظq#J)nʦMREEE)%[l+Xd*1ӤZZ]J쎡̝XA͚،$(?J)]~ J)ݬWsvP09 :&.^FI㲘4~4ަC)nvߏ{^n R]eX4#W/N0V6VBJI(bՄa qk׮<.]p+ twYf '>>ƛ&[~'O751t#'R]]P(j%==χvJmm-1 ,! &zU\ބ$77B=&l#4 ԅ2"sZWWib)SB"0g )H$4eZfff !-)xF@*aJ"1)'IMrkԱcjvۏ YPP0w޼y{{+OWRv =Aj.hӡwFB@r_Rڻ*۰ >Ҏaeyek?q+omkWQ[͗il}n X]EWp)yG_*ZRrƷᐷ77ky=`sUR"@f+PJHOSՖ%LxB{r҄fA ϩ)iizeh-$tn׌SrLIZ3ŕ֦' 3U̔B*B_mH_sSºGZ̞.#3-eDբ )0B'Jc}cks͙KG~{~/"IyfsFȜ5*gЬJm-V_񷏢֛@Vd IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/resizecols.png000066400000000000000000000015361360462764600236260ustar00rootroot00000000000000PNG  IHDR szz pHYs B(xIDATXKa?̸[IHvKB^ ѥciAP%IADx)3Ύv /;<;̻K$SSS !Dxy}ƯĀߞݛI4==k{{;}_:@qx'eeQ8h:@[= <hᩘ''Lw-v}퍳Ql@vv\M-aFupaZ ?s]ugzqq1@: m΁\c(S\FU$BiB~PulۦVEwUJZmv`%C~!2@'HЁ=021$dJX X~ы(MB*·J,8Bq]DOOOflh ?8Nضfll졢(`˲\[߰N-RG &$@\J| @@K=IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/resources.qrc000066400000000000000000000032561360462764600234600ustar00rootroot00000000000000 abrir.png anterior.png aparencia.png buscar.png caixa_texto.png colar.png coluna.png conexaobd.png config.png const_chk.png const_fk.png const_pk.png const_uniq.png constraint.png copiar.png desfazer.png excluir.png exportar.png fechar.png funcao.png gatilho.png grade.png imprimir.png indice.png modelobd.png msgbox_alerta.png msgbox_erro.png msgbox_info.png msgbox_quest.png novo.png pgsqlModeler48x48.png proximo.png recortar.png refazer.png regra.png relac.png sair.png salvar.png salvar_como.png selecionar.png tabela.png tabelas.png view.png zoom_mais.png zoom_menos.png zoom_normal.png barra_ico.png pgmodeler-0.9.2/libpgmodeler_ui/res/icones/restaurarobjeto.png000066400000000000000000000030261360462764600246530ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME -6IDATX[l\G3s.{nر]"mFMI/$V)UJ*R[UU"T)<HhRT^(BmPF*$v.&I'q{߳ݳgϙlM6q霙pQ }=~cG2u8c!a-ul3E2F#Z@LД8ΝImXl=>q:!υ+cAkZn]_.hk]ԴP[}caS&5iU[nr#acS 9UЉǸ\ƕ ~q3ǧR"fEmj",MjC]lXCWXr[,aεi\.PlV9q\: !Xy &)Fa%l^ ڹ Kϰ6ZU1h1 VX 6vj_5m J9UX8֋ByZ7Ƭ =k7eTrKp NRPlxt1D*>l{?OQt̓ʿ\ˎx{#M䂈B%fjPRP-'#}&c}\r.~AnD*b<$B⹂Pk<'+1ь3Ȁ5Eco jXC"bҘrIzBPFUI_24$ ό/ڊcf˴kgt&)S){d|38!hK,g{Ύl_?,QJJ)<r!(kt\$Kou퍼(cNa =;^Ú푼K;Ba2q]W~ jA ]R!cMKXT*S7%[~~Xvg;v].ZYkeENǮZc1FZkV3ӭT/T5-K \zjujnksNzu6qfIX :h|?{X߽~csr/__'!?@@(y *?Rw=fWyu2?z +5{)+ B%nemp;u/j2L=E$RX qA.EkD=o ޼M;'3WCq]ӧ6F#p%m͐4MaLcb3N}c15XIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/result.png000066400000000000000000000036341360462764600227630ustar00rootroot00000000000000PNG  IHDR! sBIT|d pHYs+>IDATX]hwfvvVZ)6BrlC 4n&Rbj Co/40uBR v8j&vv;;;s<}aas5:u*j~NL0 wso@RJ… 3ɓٳpOOi&ZkRH)QJBk?o5nh6;wu]w﵃ٳg0 499)\E)b=GZ}qJ7qu֚9fgg1M4B CX"^q:Z} B4Z[ĄR !/_&ɐJbj4f!}@JIXd`` ѣG^2O.ö8-l˲رch4aY###O4c2c+&`F> Vrbqq۶teY8)lh4E~`-Al5B B"B* CCCݻ!zj/Ν;>o߾M><+(ˤR) @AVjϑ&"&,,,$c`` ^#AG6Ŷm cM:JBx̄ mێZcYVd"JGTh$JVa!b"#&,ۅD<D{ym mN01<</L !m1Y^GJ`u]:;;)1zt:)%rRo\Nhm d2IPJ8|!D,ڮDZ+Y.l[&8 7Z}^x[y9mYv?>@y3J,+zߧ>=Xo/#}}L )U./s v9B' A\tˈv 8A0=kJ]yBJd>0=o.ԻZ" dR!R!g^yojWٿk:M#h4.#l4=l`_CC,τ4*mt:+_Aowg!<'mcu~'[.߹GC5yZk gY&'&] L.ķ'V8kjvv;wh Ժ@6Zݟ&JI2Jat8zYZDdj/QA5^ߒ7w_JУqOflsB6"!%4̵kLh$Pܙq_b0W*"@o<8-PT _qcz=w޼" ##[st}oqf~%}3RMAD688H.# /ȕ>b/Aؾ}95fd Z*~:J㝂۷^6C8PKKKXaP}o}O?ThZMdVkwKiw _(x]X[\.={e1Zs7f4 :^J BЧx|>G ]v}1?PZ3q!uՖ;zBwᩗ_/Ǐ^_|]+!S`'1o)ԝ/0{{ȯΞHl'&&ڹs/~&\^J}Dnmh5:ʼ^xǞ>pYopppرcãGHj6MAa[gFFjF&#N>]rJl\@tRtwwW=xd~)IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/role.png000066400000000000000000000036751360462764600224130ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<OIDATXŗ]]W{{Lf:3ii4 TlR%>JE}EA\,}*VjTFGcI&s=_{/$m|qz:g;^g+ast g( yH? IS$%sl3efvO51Drdr)lON./O}?m %'_XnGӥ IҔK59wVgph2 Sw͸NO*2z{yk)%wDL( pàtlSgZ=/ǝry.4"jUM29 7Fbl>&ml0ؿ\:ED,)z4Z`TЮp!ܖ|!ErC`MzHVXXvi#5_TA)@֠UAGZ/>N}}! WGlJFS,;Ӄ,\6W*(5ߛ)ă#|o*LߗeK㮝(q"(8ϚkqIOx-Gm;כssҠ$d- S0?n_3xxMccnҌ<9qjOѣ* ^G 'vP/e|%+}bFh-Z^yyAA=;s Ck0Ȋ\/1L+z&d1g߾}ܳvaD1Hr0(U7w}Gs>>޺JBDڑ88ADck0&ǘ7N K%[N)"DviWx* D(NEqfǢf-.cs:8ZAX(wϮrTk #'dJ"WD~!-X)o.כ@Ў4XMTE)lUg8#% b1(i'"UGRgY^_ D@6fjϖjc3ksQ>& +1 5Yu'v˨7@_)jM }VFmrKYMWjhҥN[Uz̟q?SP$_#Bk(밸+/ox&WJU$k_ތa) (ﹾRQh:(kRd%i_xa_<q3n)|`h s3"6(eP*3f% ,+4@\ Ԁ #= 066Зш[};VJiFs]o9k=IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/role_grp.png000066400000000000000000000033071360462764600232530ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME 4XH/GIDATXkl\ߙs=ޛk;v6ƹp@ DPB+H*TJ)RD UUII\E" .IDnnĉ^{߳63Dij7t^~eI~tLsoGxr1N8,A/q- owdd>vCfWό=; WbyOwD<$8RE,` }ߥfjJev +$D_B%rפny Mܱp썛Oͩ/M݈gEOe \Jʪ{Ү+,'Z 4,Edfi) 21:'>i[>ھbi{Tz|A\+1,0K)J HC`Ǎ=ZSpB `Ҵ*`` $1^H)(0IAe/82D]mm.0ػQnVhVw\*8Rކ$^d]mAD#}2S%)?hl{-kb`Ϝ~ SW 0-AP7f!\GpAJXyD$"S>6G'?-)lzCjQyf|M I0jg28p,L5Ŷ}z2.K‡6)Dof ymfG?/岧B~p8g6' Ncb%4˕0G:=2 %%K%k] v>^O+GX)NUN%VոAUԨ"mm$/chcT`?%}`]0 ÃG^; N@RD&)|-EXV!57[mͭp>,G]F,!|5=CӰ&`+AnsTikhA* U`{PFC`FjN#}Oбݏ S\AzOѷٙ9m,jDkioiSujeVu耡lؠTD\5y(vAf!+LVLhBȣ>;'~zV-j`159Up*I#=5)X :% OAHwr-_}UxIaB~?6{M \Fq ! +C(|oBuߒn9ት/Җ, o [~+IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/rule.png000066400000000000000000000031741360462764600224130ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŗklWwfv뵷.N4qĐ6udcc)&$T*DIEHHHP!D|(HVKZUGI;-];qQX6[zwˇxFJ#]}9?;#? bYB @kTNm5J)H)ݽN߶mR$ y'O|$cǎwuu}֭0Z#/ϲx<=zgJ,zR)E)%@|PcDee%^,4'FL&;ByyyIP JTgP ?*Y^^f߾}Ԛ=ZQ222a9Gy\t Z星_t)qi緳gϺL9r}/` ?X`ΝhΉoӮ\;wB!Bq&&&>>Nlf~~x~V455QUU`IRʵZcY[l)PL&9w|>ݻx"H%a~!n QwwpQ)7+9s 555ر#gmð&t:]԰fff\E ;Œ J'P(i޻o &3q灿mQ/8 H)x8q℻Dp2ccc} .s s|qkS}r.6t$ $d86 UxD"8x!ߧz+*gQJqد?pR *t#cDFzLUy ###,--{9K|{=P Le,GQa DQ&''hnnСC!xL~SL:Dogya!fħ[[oNdJF)@GG k~R- quwl哇c3ظKn`* "ފ#?p*$,&~f[h5ucU듋R̓F#Ϭ <LƩ>y;FA%tdvv(++~»ImhɨUmwWLc)O=…KlOT|9pڵk444={ 1 rAkIF&F({nUܓ?.r)pd޽߿߽}?\ot߰B AcWT5h/jRp Vb `cݮ,mOh|2$R9?#N ly_ua~<\WPU 4Ms X Xce.[N+C ǺBX,&޽W Fzf۶H$R>JmWH)RJڧp/B,4Ms@nMd[ ([yzʲl Z~/TV%IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/rule_grp.png000066400000000000000000000027131360462764600232610ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME !,KIDATXmhSW9ܻ66Vmu9|N*+h7DFmò7l:p(S(CW`VA[aևu3$4q/f/l;$s#G$#-'O"Bu<um9/=JŷlV:~PH}䢪jCee嫖e:#DiH)muB߹s+V,ݿSB<>m4McϞ=$ 6m?fH) ] yR4\>iG{{;t]immehh("o)t~0| A)ECC===ܾ}]בR!r*RxIGmtvvR__Ϻub1 Ƚ h4@qq1a޽{ټy3HK. qp˲wޅP(4T!cvPCvZ,tR& ʪixgϲj*`9躞/TǨ ̙3R)***x#F! t뺁)% ՑwضRX,ƍ71cN&4 08~8RJ|ItptwwSVVʕ+ lݺ ՑdcǎQ[[ˌ\PyR:uaq]ǵ'TӄeY̟?J)2L=:r"M0MS0sb"tjXJ+Ʉ3LeYԩSKKKæi:jjjF8NM6Xt)eChnnmmmvр3 csRQQѣGYlea]7XH)PI80<555̚5 !k֬ɓ`o}, .dʔ)XE}}=sa"HP~=[~%Kձ~z4M#Ĝ9sXx1]]]$It],zW/zOp :RsX:v؁%0 Ef \evlޛՌ9.f24fi7_>p}ծg&{pk=QN֒cgS`ܷ*8DE #@6֫LW. 5P+Ys~2v-FRJŌxص {i8ʁ`h2Ǎ($.i>6 !h|)_x&2/K["@XϿ`MRL͂}ߣvY`uD GxB vPչt '6mEБ֭͌(d^<2жPi!D*sVLo@ ` R{U*W|G~Aƒ+qߖ@A&,iQ6\B[Q0i-H \wbVΛ9pRZ/Hp1_}x"|ZrW>^[jۭ'f -vKs+Zg.6 ں1kܨ&%_[9堠2q?}]z.ҡO_l6%  '=VI8E/?1`z}l"FH TTC^;GMs8g-'޴S hP8Ywu3}}bel"0j @j^y[2_ s/~`\8nSL}6eiavćzjvIL ̌D Dny;do'jr|[q:]vjW_\0` IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/runsqldb.png000066400000000000000000000033141360462764600232720ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIMEjYIDATX}lW?9߯@-TK:`T!3An% Hqn 1e̽4SŽtvP`6 P_i{gGq?{97<}s΁l&?rXc*.~oVĹ;C?pm:찆aس{@xfMӊ Vֆp[[hR5!ג_8_a?y^r>EpI7Uqndž%hDoc@\:K ւ=;:ouuw+|7rۣe\:0onѬ[3i8>IDĠzT=xFdsv[;yqqZge+5WhMq,`1""" kHG+rOoX ǯ;1y ho`Y@q1cDPՔ1cp+@XzE] f^.(UEq你C v#lia*E脮h[26< C:0`B'CTQ>y;V\f,U-J9ꖔWFTQE "1B#P<nbhΉ&O!a4zd ;44P.PDO\1&cDx/!hDrͽV:E\RKd0[- DV| b8FiET@,EĦsGzJ޻ TTQxMQT󪠣zN@"H=8 ~ GiK R g@ &D)DRG0޾ {14(g~BTcdPL9ͣPXGz2^ɀjR2&~҅_bǵ^V@1#T8Չ1ň l'{z07~q 7Uz9!_Η/_ssg= X~ۇ6oRjδUN uHkOn MohHWun=ge#/[[ֲW>6-z ݔhނHp9~%s`o7ٸwߞ6MiD :UIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/sair.png000066400000000000000000000032751360462764600224040ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<:IDATXMh\}η ƶƑT0&'Q0V`hM[ȦU7M'fM I?tQhCHƦ"""nbۖFo׽f43 =p7ͻ?̽ 5 \' D:~EѵY u]\Ƕ1 FJEw޻Q]񕟲H"" C(JGH),bիW?ZyUQ 4M,BJ^+PJ0 ǡ\0M !D P*fn88XmH)ZwĴ8CXIJڡ7 #@T]\qض *Z*ض8Q/:3iaf p'H'Y`w /1! TG$4C-4quS'mn˲zIss?oz7oR8wwߵ1 Akt7(ƍT*fggq]wrmO33;}@K#v h )_08qaFGGrܽ{y}>}a4GOh`YmI(yzЛJٳgYYYAG*?I嗠¶4"R;`z۶assjcnmNL,-", (C6 h ,Bm"Ы~zz8i4j ůfLBxf@1rgxc?@oJ%ܺu ˲r:v"g?-/G3g0 ESMCy hX>K}"O}!w|ɱ1gk>p0 D@>zbҠ$ (Xag?g* < RJn7 CÁ1 b&KKuj'=<;˽~'(W@i^1p;uhI3kyQ{.)~m--%.ׁ ( ! Cb@TJS0Mˍj?GklZo r!n'TU\%qx \t?Oŋ !{"C0 j՟7_+eVq  AG27)%<|2vɡCh6wY2c<15Aa6Zi($_Zk@H;9귔%8aZR+vY|@ZC)*JnjV;Eq!R?9m~ѵ~AΓfBc;~x7ݦ3cˍc\IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/salvar.png000066400000000000000000000037101360462764600227300ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs+jIDATXŗ}pTn6k@0 !"hXc3֑q?ڙRgNu--B:h &;޽}MH̜ys=wE\i̵wh#6Ia"p0⹾=[_ԯ|2mo؂ymӪ5`Hqʿ3Wniϙ?JH1=b[X,)R 9~F$_ ̭vumW7Q63<͊ؕӧ+IKJBCTd볽ySyr+_,17z~zW:{/)(1t_= O 9caNZ18@ߟvpp2ʶ$~)g I ڈ+~H$IJ ~kndvj,ʢg_|/TWJ)w]={';Z[٦Mvvv" 74Ɛwܶi/hmIv;wb3˖-F"͗Xd-|>mcPJ*D9wfO#+(7w\0(#u]:::l߾]^N,Z6P(RQ,)h7sv#ϞF,­sy^cqpyAmxG2dΜ93>"!V\I. 1&D,Ï6si92ϑ`g3>RJRhq]ŋcY֖ ֭^Ѐ8(H)Rrooohw` Ch(++CA.CkMPή֯_o"Q|'HljF!,[CSlJSDQ8dd2y8)%H .Å: u%222 ¶eY$I`ߜN4PQn#Dkz,_ߑRJ{R!L2dddgϢFʱ,+4ԏb1=g!8ZkL@ @8\ Z%>/oX]xIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/salvar_como.png000066400000000000000000000035021360462764600237440ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs+IDATXŗml3wec]JsI0ëi)"DJ~I6}RYV U4T8 IP `H ۘn}3Wېb=zw5 g;Tx^N " e>v=([Vh9j+ӧIya|_q~dwz{_B.{, ͡x]yb̪!maIDJped7.u/u[0y{nDYO+`MR7f$*1Drl>Ikכu{"RцDMץCSw_>s򁊒ȸdڣ0?B, x]sU-l%3%<{_>YXsr+1({pwrek׮ lw-k2&5/WD-̆U|UڈsO6ƼX5rЋ04A5黖W7B(([|= ƘlRJy8ۗ`hm]֭[܌2CW\_ƐGIa>ҎsN1k׮'^O_] qM^x1~ﵽyKl["Z1,Ri5&yu훀kWV} -ˢ~F ?8WdaWXR`[F#`eH)0޾|3ϧZpϞ=>`X.]J20qT`2dw8H)T :w#۶Rt0Ջ껮$̌v|| 8ItDm"7 n_&H!iLfу0rHp#1u%83\[ 03NmSR JL> `f03Z/0T,MAE fSSZ_QٝsgV~$ԈlDx[fıa+ڢץT⟠7=slSD"رcG-@{8率G8d+p!|%$ƴPY1Hs]yF¬ m q"/᝽N5vC?!A,@ʨ&i_%XzcOsl[Oͤ 16 E1l["8V65b%mPUb#L} |=Vs4$F .#~}rq:\7&pL[G>iJeʔPUjmd-?8f%1y0d-E;FPp[Y0t@..Pz&i*KXEϢ+}BSR$̻gdJJ'j87kwڎ 1жp)tU@E=>gA'4 1|*ԀC{!٥9JCk 0Czw`*s. 3yPTXSR} ;s Ozֺ$$14.C* ұK  h'뀲/F2# )D]ay]a|C*U184|(uK@Uu͟[VE, w+^T~*٤% XBi`~FDnMgZ@<4J.„C*LPNd?xR}q竾5h:Zbdž0kJP-1E`0=Xz TZ#un<4lPAo8gL_bZ։;\P!wMh- `EuS_ TYj-$` XtJ;z*^ -;!zTۉkeu5*0 FgB4vH<4?A! `yX_o; Vi V@2c'/܃gĖ̀azK^_R{ųɱ.0E,_kvb? 9)X׫@U43БVzȐ€Bٱ=uZtɾVL#hlRy6t&#̱lcrG ~*!w`cG"˺tvm&ߵ7nֲ?z yTC#C}$+3 AwTE1=H4Zy%!H R6Kv͋GQ>oB)8*Nb}3DX Q ZB30l ˆ)!Bv5gxMPv(`qJթ51Sl' :KjUezIB[/ 6lЃ]`ޣ*2!2g=ъ,UYPUUx(w,cd$"ٺu˩}W^iyw9Ĩ-TBTe ;9{w[qLco8ӿtH.8@@ja[+j{vƪӎ0gt vUcªOgOFV>K=h`RTf@cʂf&pB: TK)<oLڨҞ,_d;QU@|Vم 0!, eB$tKfW.:h_Q"k*AdyJO"ރ@%: uÁ*eDt:E-U*#xr,H;)]`qQt;o3rTC0XI!j@pVF_B]*矺KEvr&9ilܕ| n^fDg#_:`RT̜UF'ÈBF2,khu $uHQZ|/u~<͏2/AEID4i24{ң {f L$68ƁθFZ@-H)0[5)V٭S 2+/PU] ]|ʄLqƪtC=|7?p׶:ћ*Г&(aCw)ӝ+"# L3Gk\ew!7o~-..:2]폲DXط7ܛHHӭmTץ)#eRnSG_?c pUj.3뎷&6+MOH"-A!'V٪W{$n`mJ[7zES+(P тhh܀8ou&O &fYLL M4/#+83݂3$<؛@".VyCCʖ9x9$r'7|^=` C#yjm}MLnnyeM|L9@A08i@rJ>S,U$ID /׭]¯;wC[;(01hZ |PB8&1O$2]mzi۪٪J@)0gi^ցyJ+hD9~DDESf:GNk!`+E{Ps-VS19тZ#ʔxA?uLH9Z$ Pzu+o&TtLhh^5VOc_C;ٟ rq=ND,-.o_ni=́zGE$.ݛ>5lX|=%Sqt=p0;}Tv3QЄ+ Xb|Ie̹^>|IGv~wc?^#O~#(cY?w2p+RbPU\MOG|H$7ӱ[5-:å.KyS^3[O@{ۂ{;>OWVE Rځha([$BKx]Ec*:PVFp EG6cJ̲P/J)<J:D"(Œjq#5qyȍi6.~Ld:+@!P(\Td`H_gyo? Y=ůV;p8|Гl'HhFr9+`;$Qjn6@$o; 0`Ӓ:15){./;ؐ;\ ?sp{_]shz~WMMȵb hÿYѕ_\/P0 B $Lэ~'!~~!)JDZӸvW+^k&$ԓ2imJ MHM'|A4$K{[l3W|3V:r`2+pJΩzZNX4iSP6 *R ϩs~OOC$ HSHlx' NjX0(KQ&5N/W#,q҉ jڵ +4&)1V{jj[2e{]B[{ٌ EL""]BJÓ>P5|@f+O1[(z[;k$H RWsxC B!Nk)~rq ~gݯf\Uzx`6L#("'.a1sx"ZK)~Rq XbY H4 5H Bpࠖŗ!B).rh̔'+@, лCm۶n]inW1g5DiR4ݏ3[X. &["=xo} )jj2M6Xt}e{6#U\3a&ڶ|ßΐp'6)ڦlځ['껗ı66Z߶<ƙWN34|^ h q836ξ~RNSK- 0GAj(zx)+?3_/'Gڋq݇>w΁mVqgϿQNWV dAJ96g7;_u{n- =k^:Z +77|8E=~sSkl̊=}򕙩o?o !wϙǣGvnK{Bv=5jG/-tEX~6gyniƊ᝛zy™y fI΂m, [}/G/Q f""V P^´!=v/jt'm/؂h9Y V|⽾gڿ` 3IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/selmovobjeto.png000066400000000000000000000022641360462764600241530ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME !C*4IDATXKlTUgaSjA /EM\Rw&qeFʸpc\_"E UCӡtνN=7wwrOd2looqj#&$BH! eHy51QXn<梨.BlOyBƾHi7|bh<|TĥJ)vDC|t,[n}wPJ-^ (Rbԥht RWR !րW(QBv۲~F'Giw#O'bň810 %DUg@ik-DR%+ L܇),NG<@g4XcEpN8 Z#qCqlb 9<`&y|ښp2){4jbwZ: ?Ն P\3^( \.9O߰Dի V*Z}Hz>;֘'D ϵ0l>_s_"R~0}ke D}991nOA(`йY\[bL4+XwDn|7BZ▴p?c{텭Akz0"3g|avgiGg+hmA)Rj),"g^A\Aixfgyj%QJHZde:pcT>-;lcށJUq;YaFرjh@ak `BiY-c܎6d6Ҏ,}nö,KJ)R.%`#sVw2L49tO1XkUPmŶ,@I`=22rcDb)ZRzczWlNtT@C(AԍЖ؆Rkb! ldBP1o;vҲhs'pEXPQ9f3| G|h````E\cG`g,wesxv/EJA21 D=̛,)c-豦l<<;JAJPD递_@ iqL'_ᙽG mΊU&''fYjvcM\5¥ۄM6 0FhMGK/Hm}XL)l*^|6LײC؎(3q+\+S47IڈM(M ݏpIƒǷefppÇYc Za"f<9#fIvn;*s)6}?fȐ NYƘYH @%YZmj3'OJD{=`xxC;-V.Lqf|ߧ%IZbxrG?<, )%RJǡ%F/_I!RQ~o}cs}x+?ʖ*VtttfUjfKμcgPAX֍M3trï|t#XZ/)}V IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/sequence.png000066400000000000000000000024631360462764600232540ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME-=l-IDATXWMlTU{}Jm ڦj11h .HNHh$Ai#1aCH`a$@4!tJ,Cg:}qѾLLKč'7{Bva;Wn,F1Bp-'G8z===outtĔRZ%dņCJ .y֭gd{R^*~{%J)!=|!MMMX,1V[cLwxK)P:)h(#)~uxUܗ3AhZ+Rhh컸/J)(W _ֈ×[hBAuOPۍ=fvb0]wshs±Y Y!h}y8s#J?[7yb}}xÃ9PԓS'bӪMᥤ- zlA#Mm޾'?*ط@Ɍ7DZyft5w^Bsis@!* #!(Z-$mCj6XJ).޶1l[WB G=൘3dIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/sequence_grp.png000066400000000000000000000030411360462764600241150ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME )غZ=IDATXŗMh̼J+Yubm#(hu3u b(`Czh!=XP`%9BSӖ b$SU62)ZǻL+Kmy"3< 4-40<<,CCCùcǎvιM?8fzz::~mEڮϜ9ȑ|>{jMIpʕFZnN>=s.}o=ϳz6U|zljjj~__ߣQa1wi3ͱl1-yqBZ4KPRϕegI\FM6L‰#eX-!Jl!hxH+K_"g6 "t]}=m;Xi2cJr]V/Ǘbu*Qܞ .w}Nz`ttTmF?;;{m׎]9K^hQψ*\ìixf3,* BX*!Jnp,5SY+ sС'Oܹs#ï>%v~g'Qj)"ZDLcc~A(eK tishB%* fёBSd,-zȻ.ޚ|Q7 2e"rِwq7I^ tX`nnZOO~Aȅ9IJTXXs'EYXg)T mP"8$IMJIGSzZkֈJ)<ϫp:xZaBkAF!ou݄288/jIjjwo=&|m!KdY(/X)n r%-""R088DM333c'xvgRޞ"6cg?S6ni T"~,"t `GJYѦxsbdC[%:}ǭHcџ}qG|j f8mΠ|2QQoV;]Vc3!? 4oSBϣ>t?ޗh3l=)q @kMzܽS*eMXQti{^3*Ӊ~9l&U:ոjmN/QRy"ʟjّZGZB!HAP,ĥK- PARNIqJ%}В @:nq)X[5XYYٔ <0 ioo' C yˋ [pikXk'"V)e=ϫ]~W-?t#Acqe pY/@IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/server.png000066400000000000000000000015171360462764600227510ustar00rootroot00000000000000PNG  IHDR szzsBIT|dIDATXK$G?=c,qK" z=DL𐃂=!ыg1A={ $2MOMrY'auk\sJ|UWʔ'm?noox[`aaanee}{{+yXF^osss}l6z u]nnnX]]8nggA|+סR֞@k(RmU* WWWdYfB'")Z...5skP;0LfOn`ffJoE"~6@x$+G~LNOOj/--jYV*"m:8yYZ)$QZb֝nR,eׁZ,I8eJ)˲,522D6ggg}'''P"RHuPl0s* R t:i>>>~y^mooYZփayy͠ucZ-2"B}2c*j=99R p]q>DT(6QeYo^)ET23>D頔7j,?[ ܡbYq m@k~Swxr 01a ۣymX럓ÀPK0ʀ, | D з/kj&QIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/seta_abaixo.png000066400000000000000000000034561360462764600237260ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATXŕ{pTǿ޻wcX;qfCQĖSP?NvSb  I `-JE#b1T  5@fGv9>rsLoϝݻ=}a9P\K P?sG@h l/ȵě4XJK6,%8! sf}0Aeaxm->}qUism!cۑ<} r4돟o Y W*l{}[Ljy9w{h*ܦV6rv(:wj5Zc V1%UVTY=91^"ܳ]g~._;q99d7AO7*C=wl['_fi}2WPla,3r wO9K^4 yS[VY>4@ Kqn6յë,0f@ei:Y R<ɘ[Wj jV&L\=Bn*cLs޻J]c0]&T}pˈv@G(G SjkɍIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/seta_acima.png000066400000000000000000000030271360462764600235270ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs"" GtEXtSoftwarewww.inkscape.org<IDATXŖ{PTeƟ]UqULXQLK3dfxC2䘩cjՌe*Ӽ7H24&r嶻pp`]gηsyJI Uݍgk{[GK:88lCA > ػw?~Кm3dUht!)y*3s6jF϶36a ѮeױFƵ[P{fV:['jQ*IGUXR [w*M`I,A!B)[qצ5[TAEK+;9 o4! :?]-, ڢ좧D߱s>w,&61X,BsRYsZ:yp:jM{’UAqؙYN}vFbx)U$ѨoAʏY=rfeLagT~/ϙAw*p!Weptp[io%$w`{ 26dl^S߀'@Դv}ةjs0קN g]o.X.z{J9RC@f;vduihnu G Zɛ3 o_ɷDFd1{ﭔ)5a# ߊPmdJA]8白T*{p F&i f/S0ocxH(d|) pVF*;1So\/t9ds6UڼF;''yj=Mbem5qvrBY$@*x1Wrxz//8qpe~y$j<|a3mDZ法om8M9KۘsGsf|/j~޽{ 8Zkc*5 svV}@6 8p)ΝR0 q]wN޽{?pkƘ4@OOJ)1$I|/D)5@P__ \T` &}hEgSi\FX\kI  99eo7 G(/]¹hii{!Xk׵cmHGgDD Qijj@Yw?;Չ|oQm9Nw5(8˟]4h/ DEk>Hi]=G3 IZ G'8rU8pcS9Kye۪4zGYZJy2Rl֮>˽Wx?/ q; cFG+eATGH.4VGon ZAP׍K2y}~k6|-GZAS)ޜIW䦮}JdrAT77 ͠b- L O$\"Khk ;ƹĻ, m#dOӝq5<hEW$~<Z H+ܿ8yʅ (`2{+L"oSxZfr(T%-%[c +S(UmU-ZΞ= ֺ@LҠny`(2c ɝE}JRH$}u֡Fk=G&{LE(`n7ϰ[3qΜ9S<9H: t"E9 *2rZ6UV=Ƀ)PB9~ 25)Km\gJ g∎GY~p]x"Hi'E:NW+-tD1](-|E4,Z^͏9 <쮙g?äIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/sqlcmd.png000066400000000000000000000043021360462764600227210ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME   ~OIDATXkl\{zĤlHLq .JR JVj_ ?JUAA\VTQ*TЦ) QPbS("4vc'^}ޕ4ݑVٳ|'~o@L4y뺥Js@u޽ե ?.@E-~qlǎ/Wy^%8B<ϣ ۶B,|Ь۶+$ŖǗ{~V5.~i1ۇa(DF SA2djϤ)νY4F$͗,Ky{[W!}D2Fct5Fyi8ɋ gҀJP:κе3y^)|*EKNsSY `H`f]2%)ڬ`ݺu@Q!~Vfz'~@B2~) `x(zBp&%X>㽏F%>~cnym&D#87Ʉ#?9MrZмj#k^TQf-G9d<+tM[jl18iXyv^m&6,\@*O?ahBځk%T3rr'bkR |/D]]l ø>tr㊎/%0 NrCCCE'lN4n馫c'(<t!^333CWWapa,6mv]Dd ]?z۷o `޽X͛ioog~~h4J*d2ɶmۈb<䓴:k[ѤѡId-W ";wb1t]G)]1 04 qp]qطosLHmC=a D -Ar޾.B+E<ϻ(q(**&BuV4McįhIuPK(V|$PА+Z7duB.3M, BaRbJRa&VbppK( %7=Q~9q iD"H)/iF9~xC2MD"AYYop̣,Hl(_Rɱ1$h)e hB@P@4RL>_&Ņ5@" 깬 l6|={l||t'OL&ijj4Mr244wY?B]dD BR(Ϲ[VCo:h[[[muaʕLLL hkkczz4QJ>RJR9r˜.8} ƴ-omd6}=1|gsϟ+l6Z SSS LĶm4ͬ߰` N|sb@J, P?7~)iKzI>q8F%ɠ©QXB,HQT_/%I&z0~swy ia`YS^^N$!F0'(;@>R|4$1 kmH$?S}q˲,#DGGRJ9vBG33 ?oq2-WD .l3q pE~w|ypp0077*uggg,k׮}?x@0 eY<^/vݷ9swW4M!_0nі cޞćƷK*d2FMMd3gμL`Y 1vG7w=|CF*+BU㓳fJ] a3BRI"IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/stop.png000066400000000000000000000010631360462764600224240ustar00rootroot00000000000000PNG  IHDR szzbKGD3'| pHYs  tIME"#)7_)IDATXV0}3gWc]i{KJ-x=dMXRd,c`6MVG so7 e{%^Z<<|AY<q/4`-,| #a$aiƨ0A)8Q`vĩ. tEGm[28 Z$CmdY6:UXIS$ SEeq5=HȋSBj8烡fS{ODB e3S@yV㬀'L@ f  !pvvq=N)PFJA 9+"S85xj:T/nY~/A'U<=~{ة"sFHڠb= émkYczIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/swapobjs.png000066400000000000000000000044711360462764600232750ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 6$~IDATXåW{pTs_I{Cؐ/H[a( m+h;b_ZmöZ/PV B$&6!{w=_P"7sfΝs~}w`-(߫pƉ@Λ pfsD2,[I_GlݺuqBS_6S"y@Fqp&cD2$sCE {/~̘p1v1 _2gE&@B[Z`qn@Tߝ;bW?D%k*@ h ]']Kk_{%mZ␀a`9Y7)@K3qq>O_kkeYq q-&TaCXCS._ Q l1Bɋmۗ<ނy#W6BD&eU%D7r'z&ͻ龜I VmqI0یEFk ,ؑ#6{6Qjfqw/,_9|}<^({o$O0 a#`\ , =G޲/zFbQؾhm|I0? @`gٽ0Z͸KD;w",bdB@TU$I_" jt6݁p:$ѓ1< ӝʖV94"ֆ{ s0M0Fq&  m}eAϻv4hdahZ;k5fj|=D&i 0| 8%(UU>ifd${i8_>EA]c+RǗh/)pd_3D,d,C$Ie-cLpl:+}\j?$lm>prfJKigZQ3R۴? ֧8i'WsVuәX_t: iz<#++˚>{`0L,;z!Cfs5 &1N4x#/e|#0_kShX`ۅYvGqX#3yN,]yl2 V/B[ةЊW11F6$k}"||ZR"Z;N὆7׽u+3JXT%‚?i^7"=%k:0 DDF6qM. 5 dљo݊#W]ueˮr'Q]|}Gï;K~9$I m1?omY/xw9!T}a) @8/Ŀqv.ɝ fRjեdxR'' gIאe)m\_3t06V ƪPr1ﭥ@P yqvY&RaH4RF-_aEIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/table.png000066400000000000000000000007771360462764600225410ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME QgIDATXOJ@7MEx@{I".zJW.IUZBddZS-h"!fDUx4 u[_>P b'VAm4kH5*HH*"'tUmhaݹq/,(@3ܑvo(3wHSIL1QlZ-%iHQrq|XlߟNtƛJT-@@KnT%XE'\PaXk*P(^wf*23v/I6n\$ =F1p!`X)]!NG ؜>@xI%:3N$+6kݵIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/table_grp.png000066400000000000000000000015371360462764600234040ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME R8IDATXŖOkAgӭF`QDJ)x؃^^&"ޒC w{S@QUkڤ,MSyǃͺImgI{Yγ j,ϗf/a cCya[ ɻx>|Z?y@.\uNG{$Ǝa0Q,s̿@\ûs}6ڎ":2;8]oѱرG^=^2Ge f(퐜sG!8,8IiQ!f)?Dv;I`y&L\WJ!}lU%"*;6%8GIT*_X\\v9 d~ lS`kms"# 11a[d}̲#:qlYv .u;LaH_{uP?! ˕_RjN*q,3 眤8ya\ޙxGF{{IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/tablespace.png000066400000000000000000000023711360462764600235450ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME!'YIDATXOlTE潷vKBAAAD@N/z\PD0Q7 M&/l ݲn7aKk<8d|3o>71޽b,Z&F<=Nk0'[pgiGs4 ܅o AR#;`H#eNSϥ~Y퉘mۭ`r!Ɗ<52 ZūR44?P .;nzf}!m۶Yw-y[lZz+d2(* f2\ѱiÇkZ yfM W*Q^qo\1En%[@ }D9%!\G[fI`Ԕ3:.xىTKŞ 5ǰw,g9~ *ۚޙ=r8.1[XɶyB(壕*+ Nۮ" &95~j`x['8ΙĢ=#~8翽Huq}YqA8}Aq<|%{C}q.ػ.:͉8?=lsH=r+RZR`iQ&YV$Z(os`%\6JI~^k5DN5|]hW{bK_{DCs"a: Q2(DyM;oG(ptj*材G=4{GľFTv(빣'<⪅+ZKZ.̓jdvj>~}Z  ? wPCors(7 宼nhhœ:BAeȇ;*"ϭK ]cb{c|P!+a CU-PҥѣCoɊ ⳍ$KVSrO۱ ` }}lEٕ8>F8Ér WYN.Ҵjiacuk0E(\0K"T0<6P@wUl?. \ٷ#M a|9վd|(Huy'S.56@s3P;xz@cccJؚ$1@68y/NV:@20n n/fIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/tablespace_grp.png000066400000000000000000000027361360462764600244220ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME  )r^IDATXŗYlTU眻LәVZJe@6Q VP5Jcb S+F&>DcQ&&DM[ PLgs:RZJ/sr2~.ϗ}9D{?H A6_w~2 醐ҲM|͝^ްaY h'"Mw!Fp<0n!vlMsxӊNT 낏 z{{~ʹ&yA0c|0Nd<$ΰCOej v.K7i>#F-gʭ86B47~c qKh)aG⠺kV7L~-HL(&~FT m:#I_ǽ,|t]PG41rtѕdiҎѶth>GtTͿ2v Ʋp H?љ! ?lYgcKq}];hK)ra3zy匝:?!g,5npx4=9*bh B $k12s5)DVcL}m _jIOR(gڃq l:KYsͶ,$e?֑8_ q_4~HF(v9cMr찧sj eu_*Z$r·nu r@P(Dɛ,-ڴpUs'O00ETHGZIX_cGZ1]k4,v~9 zwR{LӞo҉-vl^O;@tԦ{X}X{vy:C(:-k7ܿ|+}7aL?b#lg:/;A~W˨};e RMJ9sE@O; cA:h(r~݀NcȁRq;vG;VCm麓8#@;V4y>  +3'IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/tag.png000066400000000000000000000023771360462764600222230ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME'TIDATXõ]hU&v4ۺz!ŋBQPh-B1`,x5W(?UAbE$hA6iӦ7sƍf7|~9✣cMuAt9$ ECR=Ayio'&g Dp(] "01qC `tX&iODǖG3~f߀s>7=}ݹ]uTp(Zk9I)A۲,Eg0W} ~ >>y>{E2U|Ţ&K8FFF<O-0}%'LN͠um Zqqaj|>obB.!\]u~0G"ceg{FQ-\VJ97cd)_-fV K[ZϾ}>-3uPJODm0*r8?fކ*)|TW*A# SrAD ,FT9qu\ "e[UR5Z]h]eAq ĀCD<ϳstB/wJ "XZSM{%k+j6RM`=Ss (ph_4=ZyU xq~mL Tv3bj`Z`R1ͶVU¸EZWmBil6Z)pP}MB8*}F%$dDMص}I0`L$BU@=.Be[رy=+W.O?ΥLX@#Bi5% oyu.]-/z*t9D4{]7C86+;7ђLp='o=ꛖS"* 8@>M/ˢ&^{#On3T♫+{(BkWr+ DG5sJfDѡ*gA7Z#"Z~thsh3 Dx*ڠjpIvQ1覦&U)9@}qv88zh.4-khD_)>YaLa<uQ;( l {I\'e B0$7t GIYTkC%DgiO'Q`2<>li3`a p}:rJv{2\wD,y <|:D~e6EuE^Up,2\(@QNVi*V-tϚW'HLF,h:WԦ;  UV4K[HnW@4p; uϬ6"]JI._l>0)e rZu#Kf+LLϐJ[2OsLDY764nFƣ W=D,d,A<5U53M2M0z=+@y~u0)7C8('r^ u7d:T4T,$ӱSW-|l͓ReXx/ie))KǁeZtlT,9[ g?a2jSyL?Z.G)}B !|Xx]U@"@DT !T8]R?2uIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/textbox.png000066400000000000000000000024431360462764600231370ustar00rootroot00000000000000PNG  IHDR szzbKGDh pHYs  tIME :IDATX[lUTKl#^86(pil@)A\4&ⅾ6 &5JyЇj\A{Th)О>̜9&V^d^k=^{%H$aӧM ml  GJHNxo#"b{ 5 ynT}Kܛ1`1& H;lŒSN.K1$zRA h;Io @C%eKzy"]~*@crXH%5U5 Loys 95_ZqPQRrB"KcC#=m=R 3ɜ&S&0st}_b˵9 }Fc874;kB 7 oWinjpq!;B!Sr+*%/ضn/RQTAm],pUMJ]mek(YUBgkgގ^m(y G/ȧ*cŹα{nJ8q?fV,xy;ab6L>FoW/==ضM($Nw{7+WRQY@j_)bE֮[Klغ]`ygN0jh)ˊ]QOwG7 z93QU {+fT{~M`Yc664~R9t^w`lnt`ml&/K_U`n@ GFF`{)h@UnfttE/B6e4i¶m1#kNø'q,Xsvlw*g;CRm<~),u9Tf';V" UG=>RM)_y

mڰ6eڍ\|#a[kbvlOGk*F"ȦwJNdee=p``b4KY\H`,e)M**;Δ}|W :HM\gr{<ݤT" EX>?[mi M--G"#@gL` J\ߨ0 x 1K}%QIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/textbox_grp.png000066400000000000000000000027671360462764600240200ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME wIDATXŗ_l{Ν]:ةRJHFjȋJyϕ"@`!h@"!R!JѠV U*Z>EB%4vđ-;Y3a q<ΌvΙsi{ǞںZUQ?8xW+zz#3e9^AqHPnv3~'Wxa``e:7";ɇg?dto cl">?p=ܵ.֮eqY]pA?O{8_duex)=?ǞHJ@^:* 3f*Ly /s'[wnIӬ o@^:ZGSxzf=#Ӣe-pd 4,fHq 7a}J{16-sDJn[zs)"q\-`+:kfK׮iLNi޾c{k76P* d:?PɶIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/toggleattribs.png000066400000000000000000000011641360462764600243130ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME(sEIDATXAkAoBp|Qo~,sVz1xZ\MzЀ 4&CvifЁ3;;{oYoyRsӇ"DD" nKw7?Гޔ WX_?pDWJ5؎Ao?|~(L32q/ӝ|ZQ 3?[#T5?PPt< )&| ~t&|>kvnHs 6 Q'8nb̈́f1`j}<_9pm'IRgXٚHE>3(N%S p'5%fl0>`&I-lR&ȑf93IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/trigger.png000066400000000000000000000043361360462764600231100ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME *kIDATXWkpUyI+\I "$NTk T>mSk+:R#Щ3CEPD4&yg#{\4S=ko}H`fgp@MoT$"mF|:? Q6En3@rI43 I؜wZag`f.;]~I ю[\${uf#Ǐ Elb;TTsHGDW˦qsbo `sef~tkMH\r5m lk+7W֝o7OזB@z| #vf z(4 zñNN$Q`Nǒ +b #qCW|u_xmf`>8d[ P9zZSHԴet$3l lÈ%#dFAr#gs !Q|0wdU"+O=W!"y<#߿UdVEEl%`D " 0pXWwm;^ykZ-ɘsRzI 3@5 ̭ , 2gHgR­cipDg,eykPx ^xSN$t<1oZyuo1 D(@Ğm}οf xNK6&3LǻD:&GmNbcYa+&le7lUZ2ZXX(a0:ɋ鍻^s~xm>dfE, _5-_fN휥##Cnxpi:`x=fTrtβ0NDs,YXRR~v$fCC1 #9L})Gx\6܃8RISiJE_"C%,[L$҇EsftEcrߌmt7 ekgy4!gXPdaѱX<308z)*/x$ +M=| [@ĉ`0klt ñss 1% ./+hl\uE ~ah8M~?CG$Q^屛okآ :؞!G]Ѱ"3"8*x,=FĔҙfUWH Pl*x;7 !w)ZZ`=ԟ 't7,/c?}aw @N"CWd@ :f.;u#cB"MʒE$l} )+О6dm£G:F'uum~kkʠy<>UWd M!s>iCSd cR<.~:E'cJ_\ڟ'mp/ÑQr_RaWʺ勗45FX$s{3< MUՓ9QMՊ-=^9=teYSryj@]1 8"~=U{{kKDZ]eV?Y$c_끡z}sGGAǧߕ12λ1$ (\Z;kDjrʼn@s7(?~~~Mu pz{v[ Tg鸖bHSXaSLowI :#C1E}BRhL>O)`̼MM՗~ ϧ'ݻodI]d0OoyLOΏIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/trigger_grp.png000066400000000000000000000040261360462764600237540ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME *IDATXŗypUǿoK{y̞# Y XPXi`,Ch:ơejQf2ʾDǡЂKH lb޾=#Dƞ3Ι=~w{5 ~8 ϖoD&Tl:y#b-=1a2?HqQN2?!EGJ^2fC*T/*wpF,QxH\Qu Cz"  {]&N8K!A/+m̝0o>O~~pBC!}_vO_#A|2t:nk15e#Ky*yׂ׏c m1tي޶:gƸȚ%h"h^q2bo?S=3tV0cЄEU.굻gee?c2*`X4_SY gMȅAjNʵ)gbEƎ;`B(r7U=ȒbrBpɄ8 Uj%; U3!DCʕ(/NkD׈ ;y[|;ZV1j⒞~=fT1vP(@qyxN;k~tKζC4: )l.aoñ. *E#tqv+5Z'yڴ OBG8J RZ@*3MdϗM6ИUh2g[J9+-鄍-o(C# z3ڊJk8dj1(^:X QFf)0,FQ-dUScKf9wn;hRQzֈԮ}{#46o1X;>RLY ܦ>0f؉ Z_{2 Q]É={A8~û p}DyꡑJosER ,kF%i&ilSs`D`0 NQz¼-*(5Ul* r*w86T6ԟ:xfl-۾ ȑ̂ݥ lNdPt/)4U5(-> %O+?7'.>wu'?8&'11% NSkWw8׏N`(]hiq"@X/ 'c'QI?%!Vocg[ \<9e8ƵW[yNAGg{] \ӍcK6_c F F|TxyPof75$ ctD.\il\VGZ߱-NVcߋkeO`77D%IQ- *U90mW,IM/z:85{1>'3~o(򷃻m1ivoٻrK)Ww_!#Z@jɲ7qg8%/!Paרw,IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/truncate.png000066400000000000000000000021521360462764600232640ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME ; IDATXŗ_LU?ߏ+e@8F`% |̨͒OE'&ćeY8DAc?_>BYD+$'{9RJv\ )*u*Vx<[pg)Ea !d¹ f +Zhnll<!\l/B>2B6塺zLSRb{!k #ročf\fũEH)|TVO>559:x_}b܈倔2 H)5 +1]oWR؊.]c7N7FW060L(WA KZ[QYGӉ)"t}lڶkVWe,Ovc:=0X4fN>{t ]Fv셔g,J>9|8lx<Ϸȳ,1+GjPlQ |,?MǛʏ#|ke &w~=seO>Ex)+ \Fɩ{qg&LJus3}ph=>f}Eǘ;ƮQmUAjyBD0ez8BgYY#!Ks3 Q `/(`jԏ:rcױ5 cX_U3)j>p]Ѓ!R"z}Yf-4(~fe/]㟙7=O f'f*~b|3kk9iڶ4MŏZ#ys/÷(k"HQc~m B+X. )*qRDI10 (fЃFjݏTR a~?偫K?cs*P+`rD%גq&̲:/h?'_/HĄ?ߌ&F^y4`h )H(hb-b.vg~m2s&s9sũSE>֔.{fH!4i/twGN%9rŖO}VvĆcؖ.9q*Q[nXWgnޜPtEhYÝa +ʙH׶MM*.O0c@io_뺹 nGrC={)}r2TMZ]{cAk3&x1Z s5r\R @)Rj~0_j քea, R ˲rjzx 3&5{7擔y\p$B?Ɍ3J6}-K_/l'YK0:b vFBgBPJ8#;1fQd bP R ([ٕpFΆE7`Axʬi9.>ڶ(.۩BX0&R c_D"[E :`qk9h/mOиK1wׁC1XZMZA ",c4{WIm܅%aGGGp8ٳZͅ,tF 2M}A/hjKhI#]4k).z-S#R9nvRN\$u]rm6Rmro]Cݶ0 LrN6cpV5 ) КK3x.ޙΝXںfh9c@ۮ=]SA,]|U^|o~)F\㣄I)Mzizi gYlreSd=RNLcTȞKيF\#i'1:BrdIw(@3|I)11FdڤRe Ωm_w1WـIP]:ìkj^WC/lAPIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/uid.png000066400000000000000000000024261360462764600222240ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME@IIDATX_lU3ӝne@ PH4`"ICkH A_Є(RX&"H FhTRmk-,vwgan z{3wNZ6q bZ9'kqH.h9R4 "Q4-Kd< ;'\(OSYRt pmO n@5´VRja0_4}0M,_\{\okkX,tpe[=nt|ƭ At#AD{OoLy`Խ2"bATb؜}I6l|9lΟD)Rn~?"BOO===9۶ Q.C$G$K$|Hg߿L|4쌧@,FDH6<bNW_;5gNWyq {)ׯ_egUvttPZZĶmvA0&Ëq_UWš7qs']y|([+XDÍ<~+FDضm[Zhoo#JIfJ)>>.kוaQBe +Y29~2PD0MyO x14p\x<my (5Mc߾}(%!Mϊgy<4޽{1 #U 8_@uIIiٽ)|z\o3@E,+pҥ`f#b#=`xz`&?R>?7tIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/update.png000066400000000000000000000104501360462764600227210ustar00rootroot00000000000000PNG  IHDR00WbKGD pHYs  tIME +6nIDAThgՑu&hf$ ʣI  &CZ6Ak5k`Yֆu̱1̂M8 k !Ќ&v~# :WVmvq"G\4gY8+ `D ^Ey0V@ "F҉7QAMM?o]|5o4I04DQU>ILT-LzUDPM'֝PTkhd+8¯y.9ڝLn_?34}ۅӱGL!NjK=!93w]L&bRH EF-ϡXY4*V0}Tftu;]ܶD5j4AB&LK+ nT W0v;%mS8=AaIa>cf[ep=&iX" `Aj"* E\0`Q3^QQKDL e3?7<Wyݬ #5<^gIMQ%%h|ԄC$FdpԤ GC2)_N1$ O];o)F(&R>KM5N;Jv@>;ubg$Y%Li%pfs92ll.G6S];sd\mrd2=lz>G&\zz\ƥqߵpFD~"vw5*QPA[DD@͡e,J`$c&Ok[̘}s!|Xa 6(eLd{hA{JC"dug\zD;:Wa2G;:65~=dw&6CX1yע}r\t-zMI$5ƽN1ۥPv(Zk $mg\ދ}A'DՑ fE5 Ic $ZJi|EQ,Gw4E6[vOeyOO@{+o=5C1z5% ZTFPlϣ 6N{$#dKi3mQ4 V*Tí'LZIDb3oIW 1f7 Sr1LZ5P`K|scYG86Nz/}a/MjŞ( ^pc멟%OXzsG(Vkq\qV>guOjSj#ǐz4SzQL{&{|}JʑƖ5U:7@+"aecXu %Q$+tCP 3#Qn Q qk-Ypl8]e.%6J5xU6]`?0"[ȏֿ+FGiRȦbMEbúc-AZJ4J!020(\Ogb>ȑd ]ǣ?u XKqz"йu ߸Q&NERYHE$"v 0.@TQT|)kZd0Øg UYw/?'ỷ3\!8&VCo&F=`-I' 1BzFR EC}q}]9)YkT]zwaŝ+],K@*d؞~ʉ*jEyM7U2;b6+'«BT)jx#aJOw7OmBO?494I0[RŖLڟ>!D`-サv>ofx`WXg1]Cb( 6AK*D x*ebs?`O}-Z0~ y-lzϴsi2a?kV<(!N=M z6QoChCԂ":ii㶢 Q@R%?!>cQI>eYmh9 >fG8^<<|?s'I6N8ҝh㰵1lPz==Q=`4;PI jĦRe }B<4ċ2l`r1LmDֈA[@lBxkqsSr$^Feuzla|!Wf2V $b(xToan~0aM*QB*{9qqdz77n.'y .SU决zr7߻A@:ȃl{ 5 2bk5^ 嘩rpc y~eOw:t>:m"+fy%xc!ozXcJJ Fd72r%Tkiҿ՚ 9 uAΉu "$qX&qԀ`.N2cZ6&; )zIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/usermapping.png000066400000000000000000000042271360462764600237760ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME# t$IDATXõ}lU?yo{/C*BZa-c^EnlEMq0ܢq N +從sEQyys{~{ 4VGx}VKQMճ'I̩Ohh[77iP M5^]SM4hrF iM~Np(SP$ E\W>V>Yݻ}EiP(fFҜ N%ʞ`B'ԯXWM+D|Y02Ex+P(Y}D];?}[pu,n҃d=Mmcq s«N[ ,[no:#y|!uFˍZn$ŇUJ#ȝ+L Qeʯ";̪E Kç]Vv __Ov}>xT M{{jb=|+1=՜zs.hȥU5P6U*kWe.y7=ő͜3̙]3/hǻ8ZN9J(0 -\!_A:WƱMl /Y=gc='!N 7ypjG,5^?M]Rweim8D2q2Vq۶gO1y͎O@Gz+g/Nj>B^E~ȩSo>49 gEx|Cu_^Y\}jP\Q%/BPt=~QtQ,Gͷ^' жmG*u#oGghh}N&!Hpba088Ȳe8y$hndY@ TWW_?noC- w4OEeYYh4JUU~UVQUUmD"4J<'A.C Npva;HD"$| ***B`&i~A>GUUEAχpW$ bH[[_P,bɒ%{A(;v I>lMY0lݺO]ﺮS\xGǪ?Lk˖-wG?NLMRLZ!IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/usermapping_grp.png000066400000000000000000000037101360462764600246420ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME8*x4UIDATXŗ{pWf7&K qI . r)JF8:)R{QGitTJC6SJ#!BBHȝ&d7^?*Ԡs̙99Cp.p@۱ 9oI'@sk}M3`ZIFszKs~0zhvuYdxY)kAs!!^^ol(~UBIVT5񃋋R|-~uLbFNDqD~5MJiۊ-97/o>^LN:&ПthAKdJ30%UF ў X:ml/}|Ӂ{ځ=ONrssm=>iKc|Y3s%k.{FiQX-&7pu rgUcݒ/=7*.K~<܍ .,>xp>r>P㼲l-ά<{xtF0(Yl|OѰz& /ښNPv- 9䔎 ?svC*UWi!"ACz#VMȚr!Rx4!(*gREQtATMi%BckMA:K$8Ȳ-k^?jBGGy6 xY击wRMMh4ěǻ?&y?ۜ, [#i-ǂ;zHYKi,],$I⽺at Z-NVb6d ԅwp;95t6 /8\ÌTIbjy&(vPROmu_ 0$m sr7$^-W.s!I#eS*SK<&N$ACCvG_=p8Tv.GHs9ቅ8/%>oB. bYM Mzj*9[Ś"uvio1͞_al̇8NLDQBUht/ZO+bolh{0%eB fZ2@0 CS0i U_ =}`6F5%Ἥo2F.yȻ1hݻdlbS`B@yPXϙ:"tLk:PYd:Lu:P!<T !B޻ny9#CӞ_|;GK#Noy_wgV jඪ͛8U3Mg춿_{VF$-+v2n҃ JGp/ p=k+s3ǟ\c 8'VmXtgQIuAkllj.;t|oo\`7M߉߫|~ŝ`F 0: =)F[;'O Y-}g 8oڰnN_0htD $!2n yT߽wᶭIӦ|c%$8qqi^=(T1"H K dLעpw=:t~7"!\gzs ZbɎ@YK 蚊OC:5L"1j`dWs쳆Z`fbJJPhpͦ ,BW@K9:/(B@4$ca|x|I߷:tJ"M8zDMH1pn#YbPA5O4#XY5,T=%Y$)ASeX8dYyM[9.[XU+=pDМn )'ZQ8ҍr>P;ǑT~<< 06ռS2qǼ1W`ʮ~ob;j:8Z_c\xœl gB/|E(1%hרo;p&qSag8@=oEWx+{R.OPfyU,< ?G#+*&#mq 0C\}?1(Y0y,p9Z<nD۸n8.ܺy уS+At+60b $IJ0)ֆydxlR(#(s~MVȀotl{,o" $]۴>'͙UĢ+ $04YB:<1\+$Y%"c /"hV,%\轇Ix3=;ť>G@L$e1CKׄO0)+z ȹP=T.l6zjﳮW6rɗg@ԀCzS3D " zRiLJw`FvdX@;d&+P<#}0ՀuH p3!rBQfwCtc%܄q^nS "+T. !8kq_mX,`"FJ&~Al*$#t/IA( ȟʮ^N@#G3NlB|1iIEL3 LdxAu71xdW4Hp@zOѲ.( =[+ YD?PHAF 7E!@`Jp Aph?YdDk\g97-xΛkW;r] TYA2k33B1O/~ !inHyA"" ʦq>{z& %G>]pnb&,a+eyn\LAGc ӳ\*%Y몯^O&lll8}kdbu}^ Y 3H$KG)VP ~9Ƴ#po@`s yє{/D.)g.Eq%zw>Re>dj L!50ʊZtJc6p5)Rֻ}aXg !6d8Ro1SCrlVA]kB2-/*F#nԾ/UC`ObCѤIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/usertype_grp.png000066400000000000000000000031151360462764600241670ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME 辠IDATXŗkPTe9{vA ,7Ӕe0ΨHj[Y02M V(8fh:DKEx[Ё, {}əJgZϧ3yy^_⃌/ քE>kwwҿύEoK%'<详)T2z*0#GsmI `Od OGӪ"&UY"D@g /rυEFMr8f9B GU1sNJz}D<:HXahdt{s VPp-BbY m:SN4Ҝʠ+zǩ0tU<> a~l%Zbqf>d/eX^ҜJ[Df&|CфJͽz4΀nrZi#+wp݌')s*{CVca:.U%y@@B9rœ(#^ ;m lya GλB6D,[]۱sy I p͘<e!x Qu 5"^BGcUŞHjB6{KիiQ##z {\ M e!nxMq;U>5 Vkו]aa zSitd~ݵ.HP BbS|@:^X4;%9ƱS̖H-vtbA/!`W)˚/xcQII&z 6lh=_vSO8+U8ymME(VpP0PjpTƙO4E+o>2)Z}FnGj`$FT٭Åj }7(d!yYf~ڭfatk9jD ?K6[t-5hP"u_ΐ=uoٴY7sU `` dY>Y`\[墕1&Xq U / Z& B~iCFDIW>tBXP*RIqMvA6a?m"OIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/validade.png000066400000000000000000000045671360462764600232240ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org< IDATXkgf}a߽.,XDP&MjJ㗒jؤ16ִaiLL4i@U-JcmDE[[Q-rYx컻6sa]BN$3y~ϙl{v6i֮rHUJgޘr= nlmėuБ8cS.Lrt߲gT?p"@&8INsٽc\447޿vuMҤSi,Ƒҙk?bɹ|kN} &T1zA/{ѭ;w꺡 _ôL4! ^J&SyRSy .Cg Kx /*=qއ77zǶ$I4u-ť) uh\.G2bj2sF2R,h#iMTo{[^ruc947lڸ{+%(fCY֬^O$! LkKt7[˻ٰdS5"$p>Z(X`E#G7߶a!AK݌@ܔ*&!x0h }%.c}4Qqz)J.ׯޱm訥kN'uXY\"q}\T U^ ,P61ew[#J27dڕ:VjV)KH(e#Q }G1KT>_o ጃT5jG5ڴд*GH'r(;8fgg6Z[8A4!Nۤ=P)f6bMkK-X ky:/63fL=k)%a:XXH .o[:Jƿ%>99+hkoav{+&~1rLc)PJͻG6Jv̭֭<trܦ{wQ&%=tF?Slw'ep4ұbUOl$q YMGשBII E42^wBfw}%K{~ ۷v]4Bv\ƻJҢk4M`.n4N03c;HP.~֯ۈb6SsNZ/]7)%apb]7-SPJZ|8ifګÇ_楗r- H)gZ¶%z.z*fY1HVv*U\MQ(,sFd=|;/2v%F8%fsص?dZdrr;}b8Ld&=>!<| KHMf3LNdkP,pBhUQ7/ ,jيxroY=>{J]} o&7&ܜ;Nj{tyHV-NyHfYVf/\?Ef: _,`nm1]gR1.[u8@u DZgX\0N @I̧B{Oxg Hu\vq༸PA<'`&XNRs^u91)5+À}>_`}C0Zn]i^b)C1{}o&|rul3Y3EGq̙iP؀o<\@ى9IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/view.png000066400000000000000000000014421360462764600224120ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 4{IDATXŗkAǿo&?Ma(" ^hœ )?s(,zRABRSelNJYݙ|%fi^)(2k;RԭX<|du&R@7KٷBdvOVĻWw`0z.R$ q`![V2PJYM}Zkkcu>*G}4vۏj̬m<_ZZ)pGg& l ̐X3-"@<`^R~"2y_kڽ0d{ WE84@؍099xaaHonnf=s:@^VJ2`!RL&nwttWP20ԇE0 m;8@ʓdIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/view_grp.png000066400000000000000000000020621360462764600232610ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME ,*6IDATXíMK$Wsm;&im aLQ20 " {!/!! E"L B C 8=ծg6tSmUQ\>uιBTR#~Q ܼ3vgB1 |֖w~?J)bAޚ8~f[PgTe/MORzJ@0߬$JX+߼2nNԣ }OLI%A!waRN0 BZZvQ:h30)G03cngh8:+7ᅱR>9,oG> 10@"BS3F{X9!\8 o.N}03:3@DFC u ְ4 b[e l`[xHAޗ@MFR†MTkkk/--}jpZQ(Ve8.ӳp`8 ƭpVQ6=w766frZ~rJTJ[#`EQ .nz=휃1Jױ!RT7${cO|1VW" ss@J\6a(%qUoj5~V$ y^ 13130DވXYYxf@]T3eY!l! ~ M4QJ-W^+#nwbw8' rkoA{{{NɥKX rsy'UN>O n> )eѣ/޶ ܹsl{~_O\Sbff#+#[ݻwbk1qNzq ֺ}}}lon>% qyӋvt< wJuI`_:\y|rپm+GJxfjjq{JQ \%"U8N,BJRrsa ^VLa6SEw%@" P +H!`84B+?J, ]эu 1% R+[V|~%7Be(,e_m*)%C122TJ}14M\.WtLN! T9, FLhp9%BZI-jI6m< (RJXe|ocU+8}=RJ!BY)lN0r-z.tvvbTJsـh4mǷCvo0_)m.!i8%!Ɛ0ﵓL$R8tP!9Zo϶U|.10Ѓ&*3YYBk aR4HerOl;bi}]WW|~}}}?Y~|wl*%ƦR9K6se,,8IL3>~[H[z)< ~W>93?HCM%vϑ#G0M ǎ8i{.1pm>m۶g׮j\L,sO  0;;K,v388Ȟ={D"_zoqi]*y~TtwwJ!J|癚3=Ú5k#LnJCCͻn_~x2|=9*_4e%H$K֭^o) A0@Z}0ap8br90RJ_֩ٞ M c7ojjji. $'O$ |d2$ "hn!⦒^{m.FJf+T5˲faqFFFD t:MUUTd2sܔ(hvaϕR@D{k-pMڹwp'k8::*oOh;NF!,Y)cLxwםsFX @J@DRQͭs"Zk?kO-oRR &/yi0z1Q~}ᗇxeM*k-(lx^ ?>Rl61o9?{o:h֭fs.nJ1>!_zm9$I)%"=IL)Y\S gE4 h1 $ օ^"~^j$E$0dYVH+G ^۔Sʼn;JPRpT+wnewv&!B\B-,BT"Bs3TBuH:PS"Gt;λR*x<(3n%yN[MS$h6s/͛.H$ⴈ y*( VAm(SA*~fJ,ːeZp!""|B c(5߻`!"DQt+?=z0{@ :4M Q-$a Νkf}^U(Sk-1!b'Z-Yes~0 "/R'''~'Х'k^3gRJd2ågC6ш4zx<^֮8b}{o фD4B R(Vk1+xxruLV8wIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/zoom_mais.png000066400000000000000000000044301360462764600234350ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŗklWwfwf묽~6.umNpMC`HfɅ-,J T-|Z@*BӸ@JiƉk=3W::W?^ˈX˱X @7h4~\QbIgguuuJH9 $/,,DXlW{{;vM1cfIC8(> ׋) 6 ?cxϞ=WUUax<nqRp%#y}ws;ɏ }{<^<1l:us;uT+}WD)BVϟʦOnk\hƞ:th1˵\Ko#^񛪪*<{lM{kWK~!8*_sUm=~aUQD"ؓUnm۶y^ë37ol 68D&JQjl[*q '&y -[cg\mmm}r07VWsE'p7-2mM` &eZٶkG_<4L1ՁMPHP:4ֆ es۴l\86N R@*#wt(" 7|>% p|t&eiijsR9':2#^ҹi6@s,s_3([eYDRLM4E&ղbqpBD b$T0hAhP($0wmD p c*//JJ$0IS)0`ΤSqF r"wsX5;9X,>V $sZ0nX\+T4lX6e; 3 'A FtV w51y^*޹f4=e3䕌isj%pA'Ap0\p2F."f5a=Tjv3??o|>\K/v&zax._Ril%:c01 J5Bd2}įFG&лdZբ^"8Db$pY8 pB ŹH=/  ֟x3礎-uݗ.e7@N FnA x3yԷ|i} ~mWUյfD#0"yoU]g:Xڞϗ8!Juwlx ` DqIECAdr"\D(HR_2̣n~`nn,\.c`` }'+;s} 6'p؜3eqPu?>"===ttt  b~~1K/t0{~`MͿ&0s'Sv:_%DR̟zl9*߾cӦMGn*+ea$ CCCù\7/@h s-7J)^ǫ'nfqn106djjZ m۶֮;wVY: pd28~@rl"p06fWꚽ^osΩ\.lrddd\4~əl6P(k5MNݨE O<+ː]. NB8vu]]֭x<,_9/>.|>/dU… t:[Ӵ_ݻs~pm#of1` d\э77l ÞEkxxX?.Ғ~ȑbemW^~ױ1&cŝ:\X`u#Uy%^L&{ر>bJW WJv']~W-ՙ>B`M/@NeݥIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/icones/zoom_menos.png000066400000000000000000000042071360462764600236270ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATXŗmlSƾLb `IyIЕ2@ؚSM*M{aUeˤ}2YONjViV5f҂ d&N$vk__ߗs}APhM{Gё?9G^d2ClD{9L&=񟴶[ZZ( J|ccc_u"5d2_nߞxDZl^'Se|ŠFX,&k1@2_ooogwǮ9x~RY4>:uv"xs$ɮ{3ӹ[cF7*nE\tu\8silVK_/wyf[زɤSO=+G3hGF=eKtR76x뭷>2MD"q&KYOOO[6?=lI?ѲnF8[`ЪMNӊ߽j}vXF_p\O(.2XG$&HH"GHǑd1Xqtf5X45X@B8qE|~9`Yօ\6Wj:8~ir8*VsHqfMV).Q3&$h &ym^w( v\ &L$Lg'Z2|]gƵ陲YI$ɥ[>k]]kP0::A__]%@Px5`ؼZ,610N.M)d *c+9#/?9 ```fff^gϞ0 /vpԪ;sӻty}\#WhV*zd菟~x[c`Rh5k?P_mq8lmոni똟Ο?/Ν;l*˲ZZZ޳gDū3챼+^: MLVӧP,ԩS?MR- ǿ EQ=qi{=~СE8`&;[/R)Gy?u}K  HJ@JK%!Tx %cBJ% Z6~Rn: rsǏ0 T*τáG.)II -fVN@yRݴ{ڵAu~ j5|> d T*5y_xuKjqHH)IF1R/[dlmooxǛMӄAZiPUΝ+f/R˟1ǔn m۶'|k(,bN[uDts~0yص lܸqXWWW_^^΃ EeYC$L|`Æ ggykk#4MF e~Ԕy*+ܰa3`ӦMﶴX[M i>]qq+- J.Wy+Űk׮}x֎kŶ x3NF(Cw}e°헒=XtK5fKmOfZem!3‘iGʴrR#bKaYI1C(Z:es⚇%Y;c&.0,Ƙm 9x:;ӌO]EB!S6j*'Ln̩2lp2ێ%aRR&FtkG^ L0ʃ`YUX]eYHRoO$=Dpt?z#cO<3r%^[()q݌%Hň| alA$*yTha2@_iaiCag/Ԏ΢(86 @P\snrk..<56ںeU'O$0 PR}ƥ3/f%ÚvwES`ĉIrO>j) Dcؾ__]ZzS-F˓O>yb*^,)* Lk,DI>}zpM:-eK(RYTM-(+ fa׮]uhgg'#29CY؋ⰆųeDžU$gJ,G& 4Q*F*’%K7ܹmʕwر#{]z6rWOX"o;NTՇo6-Zo"fB+#1X@DD4Eoo/RVX ^`oܝ6r A8É鞞v KHTح_+ bp$a$Q\\`0D"ھֹIrKuyG҃gN} `4r}}}aX goqPRRT*iioo_~M$! ?6ws۷W%18aܵe˖7s8P0 ^1]-uɏ_=v:??!廌nj ݱyza6fQ]]͗/_BkkcWLp&pDHسlkQ:stgSqm!$?|0xLqW3gdt555D"(//=֖1ұpgbR),-񔅼-qCmќ3gˇVU8IWк_ܾ}w;&h"9<oX,aODDZIH IauꍎD0,Pw:93kX#oM^IgKD%tp21vO1O.sj~IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/000077500000000000000000000000001360462764600210745ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/brazil_flag.png000066400000000000000000000073161360462764600240650ustar00rootroot00000000000000PNG  IHDR@0K|bKGD pHYs  tIME#,M9Q[IDAThiduZ{ߦg30p"o$xA6BN&RB9D)9DX(رI'b2!!j`tV]]]{| T]U]Uݳsރw;v^S|meJI*?Di'\(M.ʐ2) KIt'jPmN\B,5۠n`);kw5m^M2@cwۥu " *nz*Dbw|cD98P1@i:èup0:U8U!* ϒ囅1ԺNUQUK`68@,ֹWΐ5 b|q(C+PMR`i+n Pp8uoq vɡYq I؈n璮8S>8Tu p 1kћjp,7.c kVS&R~gU) Q[ ꜧ3@qx+WU=>94X:F4 B&K6>Qb\o@l-p̀Po&a,S嶡YYOAyQNQA+c[=qy3t$8oNry*qx3N-1*M| QAync e &ο8~;"bcӽ]ᦟ+.Zk=.n!7 Dp! [VS#3\UR?<=#J&|7_R?B8>3r+{aQf'-X:u7J^c3|lpQpT ={<#^"I܅z$A\?ڹwFoi5,^? &Ξb` R5\U#'ٝt{b>LB _AŖ8t -./L_Gb-ZY0m#3RHچ7yZI/;w鬒4\ZUy^L? vM&kٙUpܳ8F19ejg=nVI  kG_pu9DA`i_20"T: 楙iXa[7XοCZ6wSkIEԁҎhgGNrc߲DEGp>zFiJUDB+C3ٳwk?.jQ駗a~f(mR焧o_F6G 7 Wu휬!  Na 7^4fYF1ݚE N}\Ҙ$IjTuDj֢ <~m}L7Ĺe~>z%x`di )eDՊJNjggSY wط<lp- hPMBhk*tNoMsqwt먷A"NKD)%JsiERQff8>Og0EMQ.n8KE(W /-ʼ_,wNrC97|K4BQHTAP U%qk)te J^'#HOl>MOONV/X^931fpi?:)*1bJN.^T*@EWý FL-rκAI#k\萿A0T o[LsYm'@/$ul1}h˽dҾ m sٮ s'YJyJ$W^*I=^}vx KipMEY7ʹfINb?>&H-CZw4 U' td˓$(,2?S$D/G_J O?PZl#-4;3ԙ)ĭ4w܇s{AODMpF*QDy7ᶡY45xert9VhYECR28#|x+4j~-`5IIlG9E74(aZҒ--`YJ;xÝcS\ҽs}$qL9k)pN!7]<_qUL/ϞǛ{v5I<@bE3 Cl><] Gws,9A8¯_>co}b#UGJ *8'L-=~l>{ljP986.~qPUׁ6;DJ8 wύsp;Ǝs}oupU/y39N Pǜ1^ҽ\}1wp/NR'49k,;&m" 3p61O3.((Gky~nn\7F'?=j%R3|.B.\vrV q>RNTDgY&CD6u64-p7曗\ڒ6NzÃ[K3g2AdtcеNhvУj(.p?"֥'9-܌QiM$r,$Y`j?X⎱)հ+-.DʱZa G z 7x'5t>GpHC9tH)Ӕadu`e'*|v$͑1`ܳ0WvP3HdYRؼ]Wϝhs'cCաηTO /N7]W F#•cx&i;qqR(1wVAtQ]蝣pGsmdpӦ]  aqJduc6'Nʊƣ "P~tHargSm~M]'(nPm{:L7K6YW֘V&4/pL621eʔU]چf.(L CN wh$ TF *ci40JTu3ϲ/+ m\,I`pI(B,mR'>+DP>+wLHx s{Lp@dTl*CW:KƤɦDbȘtfz3Yϛ-%-g8Up@=YILQ&IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/bugreport.png000066400000000000000000000434621360462764600236240ustar00rootroot00000000000000PNG  IHDR>UbKGD pHYs+tIMENO IDATxw|TU;- -tP$vTұVEQ,}}WPPwWU+qEAz5@H!umc2LO&Ir'${ι{r .\p… .\p… .\p… .\%!5o40jf#R8bVM%izqxΜYaK҃?o.uW)SO5uzrxvvOħ o2,1{Р֚o=q?M.עWN֙SE9\&Z@}?=.\8홣k .p2,V]"0>̥IHX7~3MpݵC7^֊jC@)狱"ca.VKoޘL#¥L0.-pp…̅ 0.\8\4MOK%DCU&zADX8\"h ¥p20.^ߛ\8Lrpp܄rpxk1܄R /K=nbs&s-srpr rp[&4oX ZppUnm۪̅k݀\bx`pOrpMZ / CB&, !@ ~ w9\"Y"\t yyy8|Μ9(.*fL&4l-Z@ѭ[W4ihذ!!B^p$ذa_A@RRf'N'wTUߏ?uȲr7yZ*gɓ'U <<3fUx=Mt/KX&OƍS#>qxmƌ;onU3jCZ%B DQ '1-x)P%sEԩS`6^G.[PP w>ٳ7.\SN,####]eZB,Z}E߾xb}р׿56޽`޼yl7ozM~kjǫ7͛7O?>v;l6͛}b~G>p-SOIIIxꩧp<.EQwSO|O? Ο rn7o^PW\i4ȑ#Xȑ#q ?>S< B`<`F6m y܊+6-*fhG}JR|G0UN[:XrW֘P]_!3||Nôӣn۶ٗ#>/;2m^e7)) ӧO{p 5Ez0B,fMqk8zMێU6cXb%T?~< C ?>d.((ʕƍC֡-{ѣ$I&z(馛>_9P&3LxgW #N&T_-sd2U^i/?k@澣.{GǢ4IIIaUfE(7o.z}4 #F܃ .T)Å 0b=~3B][c޼BuXc%[Q~ᇰ܊R;i^ İhN+ Qш;y~̜9+l-*N<2!*w>A=ł5kF ˪Ϗfp88N7n׿"111G)nzKd -Xja}:L&SX{+_]p2dg4a˖_vZ݁;# U4Mwwʌ1e<0alZ, <(.]?i޼9z& &L֭[/2w5IM <5e޽$1iҤ ͛77"I lԨ}Áw^u b}zs?Ѿ_oGrrrD}Akk k7.li_xܹԩSsFT9DUUL4 Su5Uú@c /rPx;u?Ai2s+U+qu@*2̙ sj@ `á?~o#xBw),wرx B&*u\G۹Awblƛo vBpbŊe^p zða|(({}b˖AMbYp2h#hÆugWڰGς[s.fâE q71͆I&h/#P=~8X{sM !ǡCѰaC7t>&A8~<RfZz#d'>Y!"z ğ}):wꫯ  PVy~:Kvnci8p`?Zh#^V05l?gwutl>6D{٤ &w }FvGC`j=Q)/K|])KO-U-N{Q7a2%`I-$AfRL|Gu>& >ZCV]j?ZX1mګHOoޚ"m{J(hڴiR_8S7R~ cZ0gSNawsک]жl/ &(C`E][N0`pc'F&i~qx ]"8-|s\*]k>rhӦ ޜ5 {ƦM?_voz]պЮʗd/|Wի'v{{a|6Ȭ#wkk^ >B@t䇠T3?-9!!#G>QFBL0ǏjP9 ⥗^ (%eU$t% ?0v[>*Ur,*SppDj&c' wJ3Ơ( DQŋvGqqK(,,f(tHLLDǎh(`ATj v]'r pR֊sg9/8B@' UIE |kOJ46e}X4 $}vXr(t)͚5,K!r)(_bUfĞ ֏A.83q.k:s~Ih Gׂ'VU 6)) Ie`v\X:0PB%AwUj:\U9ڮ-P=Jmyv4B/Т05&t[T؎cQlQp:TG9MN}vkܺ/rJvGEDJ*؎И H5v%;0V :?1r[˜6ڱ2\1Kp0tBB͛90  H1zMǺ/Ae2i49r0J6BZ[K\8aB.S`$C[b͆H Nt vW|=pq,w]ᙤڪEЃBJ@|=p˩4^iaНٌBٸ3kKv[z `$tuHmjD49%^l qc>T. ؉ R+pSM|oz v60PYh2ﰣimJ$sF'o>iP*| $vieJj8(1Ȳ[t vi+ЂZ1 ?5qdH({w9aAifpÍHHHt)9xv+ ~ iWi ['F-ܒ#Tzh4[nE}܏4c'r@+IZW_7| .Y BuSd1V >}sk4$vYqJ`P`]v_Ыw\ Xbexez7D^}赘}a>[d TT֪:(M*q>xսS)= c$$$+[oׯ D5n8p7ހɔ7v#2222*T 3`œ.!4@u.XK0Ǚ)HE2 !رZHED3gč7ވ#GW3 5*6ѣGd ì( ڶmXD@|`w%`P"0{2fhj: .1L3alٲ%(у6~ ܄{>i:upr|9VZoU4 .]% `ƀ hċ/͛7W sFxΝx:}>0r,TN;":KR/cСCXzسgo-1`jd{D:sK B~OJ\+w*IAH?Pd?$I馛¾`O<ÇT19osaa=x衇2=kۦy'q}Q·{YD|B,RJNxiZjj41f߿f/ K{jw1vؐ+6j[c) [jdf`ϢQ L&7[n`qZdxg#Ҽ*99lq  XRl!d%''W*d4 /_~7~޽'?v%IIIFٳw1'tB4-Hg`0ݰe Ȑ!ؾ};;$%%Etu^^x ҺA9tƎ}4!͛7ǶmAh_q%)5߽ 1 sD)quV䳨Rbb6o -Z q;vRnp?5Mw^9*bK.6 !4fk !DdR}"vZfa͚o|1Gcܹ8`u 7/?j2P8䒘}?!u޷CpE; gWJ$T8nDzeːѵM&y\ O`iPNL)ܹsyX8Rhy /HatEyx1Eйs爮2 OZL&l]Dh+V,w3 E`B1G@PVkx ֨fWD$_#>y`B>iӦ vx]9hPA(Ihfi $r8Xz55kgCigƒXUYqu׆ulx侶A2+ {/4 >zDvk֬UW]g\{lR'v8|˿伪odJNBPj-B ދpeн{/N>L8ݺu 1w4Ja`'};ؤ?[0<$_QzI$,^֭&L WZ0x`hwߍO?] I*aLCQ-4 !$9Ĩo ҥ`РA^Q4MàAGPO+Nm/*|sf͚~xPJj"i0 J2ɤ0w ΤoT`!+^u̘1] 0u ~}?& :Ұ$gv;J!gd|hD:?ZLbba 1OSܮsz1gr_:"7Ϊk΅^ς*G̨1 "OV-JSkx=ţR%*Uбɐ/[c޼y q8;߭R[`1w#!)[hv駟h}J6M NBq$B)U% CXr%F#&M]vU VI;>x{ EWrLpءҰ z={TU~}8^UOCNs,AeNƽ#FנȪ@5.Վ)=}wٲe^+t:~a;w.b^8}7w`Z,|7,}'tt%3i`Vqymz(62 [<N<hy]]?=Ra{O@ $L{C̚ךes)pC%g@QQ1|p{G;v +|k+dr[ IDATCT(uG ):YdEܹ9F=JJJ*5 ϗk]CN`TZg?΅qα (G~t;d,YC#8$NH8֍z"Iy|^Cxܹ~3żWjL[텿pCϗk ڤebz >'6sk^HLL+B݋-N'z]Sc*o;6Gi|5eS+ێ F,^:j*8B\2祡ضx3 s{_IPRneApM^iԨ,X$VwCzDxX\y]n6V#]t;pBę`fիweɎi];ʲ<=>C ª EE@q'EuZt\nEsmϞ=svz9akZ)PY^T +{->D ֯_ր*">6ė㕱=wOq5CU ޱl6'%%Np]Z]Ȭ|UvITDzkK, h6{JNbW~ ^GRU+Op l/I~U=X]gOYd o@U0N3WMˮ@|Yvj]oC{ek^-0 !-)){a70BEhRa1;7 -X*8^W?s@w߶u#,>~o+ f1@VoPKJӄ.* //B*5 /֭N pnWe˖ Cf#gه"Ř\V 1Ʃ[Sk~˥iӦߢG^ !X_݊<5 v=MĹZvIIHZbqlvXޓqVnM ןrʰ2n-^:KhLo84,D]zHxfe} 0Zʝ(ȼ7FL\4qQ:J! vyjXui[O \[!;pKz޽‚b`ܸ믴Cas *b)!v(+4 kg(x]bҥbhkbBإfXfà.aҥV;<>gEI;puZO_Φhc]VҏH  0!7ҼE) AN`D^AvZ(!!mƅ.eM.#W ZP&Mh#ƕZlFo(b^dS:=a`LUK`E|0d_m>~EbB  W2hQP &i .pQ5E2Բ[cοk\v~JMZ?~_Kudy=x㕉IژHPNE7`l0Mh, .>M,O\7mČ:3|밒v;W)~dBFaMTt8 Bjtj:]F߄ׯ;C+HOx k ] !P%(6:AgWO6J)v:.5Zl"Uj 6;+J\(ΪRbi:6RS<挌 jlF&cU7bA䠁={iX *&n95E%Ӯ_f$xh|}xc1K saӦ¸èQd^J C9n)5RCiuը<+~ bJ ncԨQs+^TM#W RK;` *:%Fy]SJQ!^(Ai9I385+W{V۷Ze3[$6=!:D+(u'`LFߌ?!QhU~nj=@ ^|?Sҡ*jPxzŻңlyPn5M#p:y>goW[T %Yѽ{Z%ݻwGΝ ^k&ZkPWu #PJ)a]YixY|:_͑ޝx絧ذO9 9 b+[eCDВ}`=|= KG b70l{±cǂnٿIڧ Bq0 :jA,(De@h6tk | wgibobόw=& 2-+: {mNApjZ܇X撏eBK&NvgAx=1a7J]j_a]C*41NmC«8JD3g_%ؽa!6:}ٲ]W|6;fg>D85ˌ^l Yno߾XlYY@(00 5a>@fjWp(UMFf0{Ju)6GbOM]MCxQ .CbkMmF~n)cXE |G֢V`,;f˓6h&̧7k0hDǔ{oۇYAUհL7wڭ.B׶zL̴:UȒ¼Ԫ;z{!IA>G9{l@YvVa> !Л,{w4l1cqb%̽5ی\Tjtj0 hҤH *Cě0K\^+a.*+Qhsȥhz 5F38t/ȒZR1yhݦd9;APtv#kAUWE R4ԾGP16 ~w40j4oeaixieZ=[C,]\x?JEsU4DSDC#\>A+lYtW*^{q L *JV)<@ ^pXJYp&(姐Я9O<xkh͔XUe b@fá]%:P"@Q% .XHИ 2L b0}hI$ݶFQBpCSqK% :YWRPq1{1s/^ / n{n[p]1 z! z!û bFz]AE!YȀALZTw_~5Z7KSE i.Fщ !q4!1P9-7v/&X0HsPV- b;էuùc z!]JFDOž_Ntn4-`#$ʰ~LsZYy$(}NLj1S|{pcU>} |<ҳ߬ =x !{q.!CߛbĝC샭d9^C{,JSlP4/>OݙU^P98 0s}x o0Eɷ{M)F ]^BPr'Hh l?jA$P,LY !MF`ULM2WӜ~۵D:RR=>X7R _|Hx~hڬEH:h=(@rdtV\ԦZ:a@Ѻ ĩXa$I =/OQnU.Tv[1^SATj'"T^$tR %6]/2?A_~݂vfye-’V wwmYuzX(D!]u;̐Q pŎRe61O~ǯ4_@ صg'΄d!ƒbw !XZ4ig'(>sΐ:6@'`Ƽs:& [3nbAqI1 /?9y9p8p8n9Z0sn݀7ċ}{]_^ץ iC:*8kY36@҆Q۶nĤdBpd8RGf[+nAE~qRkK 5%%&8Ppr]8 l>`EM@Ab vh{Ji[ hʽAN t/uлp6_}=ӦLA< I 2| Ue\qOM2I^h&kHo)))EkPʿwИ6խ:w+żW<Ԇx1P ,b~+(q&kh1/K!1m:mZd[KMQ\x!gU'q`Bo<ƧKOgᇯ{=mɱ@%TE <\ͲjǾOPUмy3tz7!)%Su/,^p7V.̛5w-w=w GA]Ai"B#YNg;K9"D@!/Eu%pFhDJ4Q &At @nnNj!2aa ܪ~xߛ~?NQ4 7\E SUTGHx;fC^3Pp.JNiOUՠ1@U4Ȋ Y 2$Y! E B#dBRR2a4&h0BӁR J)*x-'vyOyiQ0ߵ̘\v/ yi2xYuϐ=8dVVJBY-wC~H5p^UegΜZ17r7s/zas 999('bPpM-pZ>g]Ҽ!#^T hݕ|\bW>u 0 gTM}b2xnL8 Dΐ旨~g.۠Tb!\u}LjAn^ k_?a H᭚ӚXɟMӴCA(sA8-Y(b^W!AGjrspP})3yew`goUs.CC[x7sw>~Ԇ˅*(\:&A*&M&!y8}T85u_bmс1Ey^j{^ʱuu<}m( 򊼫EĘDžrX8s4,KSgl{W> Z:/>~EQ>+S/+GF8֯Rvg==js"rvHΠ3S穔,Kc߶SNl0@)ȲHs!hتbˁ``ՈGg¶,jŅTl/Q{ExÅس.cĝjh, ([Px).(yJUc8k('M+vH+W+exV 80}L$ ){ Gǚ8}jYuz0zmȽt킄D0R69h*TBdXNmT4Ҭ @`TdyΈ}1iXS41PuK6m6L\cJwf8B4[ZCVkd)eZAm3){GG0Ls&"P >!O8qQN$R"kj'BgHƴ3AN9%صw'$)EiWch7ՑdZf2BAUKgy*Q h ` `&ې|ʂ[()] Jl{> *8RUս-jo h֬YD9=ʉ ^}='z߭{Ņ9i# 9ɀvJe*` M Lq@SߒIm{ywd.J)\J u 1!%%%fu/m! <;񅹱d$>0 l\pGZV%cOE0rհTt:9%* `Dp.( (ӝf [;p绷0m-&NCZZ[j)m[BA8s/?-,uV֭*GS GKovpJ+T#"`&NcN߸-N?}IQq6Q)7F 욦!55&S!>vjl%$^i!hwtn2Ges  BEPJR*ι_ɮgbEݿ;Ӥy@A`FFaMk ^hءvh b&[~lPeGT@5;|~_!LQ{߸qc4i$lx=38=vyejKz f.w+Z?}4ޔU`B)Ӿ`pxE/x~ώ^9)) 4pssȿ^P 7r-7ZcV&܄=s: ^]H[pO4( CSR8f82x5&^Ɩ)Rox_T*1͛7('dY_6!9†zd02X^}9L(gr9V_6eM2Z`L?de5P= !0mq,C7 ?م6"Hu)rrkH(٭7ڿ|u\s+n!>R3jj*pk9%pB[ K2S0h1K4+ g.@xүwkz]Ҹ. ^GC/']Nى[q?{ B6P`?紒@IUq)2b'^w"%2-!*+r[ߏ{wPfz~38*!Mh]yv;߃+VdWsS 1⥁=MzZ{;9{_-|}LBR#I1}k8r7ti.cd_=DJS MIxYםHn MӼ|̊G,)!MhcBiȉ΅Չ~fW=s!D4=Xdjc^iq.nʉE9*{prr+v4/U|[|C%͛ ,: B` *ĚN 4k4\ }ķB!sXd(..ơQPx%Ry=,uGl&y@(_zKnZ8W@Lde8vn^R 4o_kG zRHA[mB˲4MC #n8stek2yװ1E ,8i HV^s]3qM)פy[Lxctz`몎QxcdG")1)ve8vHY92+tɔ$oi+9]*ġmAggh4MoЯ9.x+g|!,11 B̪OCAѕ2%a(qm&/$2&d ZfWP-~whٶ+ 1z)`,WѺ?R@...Ʃ3'??sx@QkqGVf&]'HsU:^ozs{qtϓHo2HռLf3n7)1o$c 8s4.^k\z7Yڨmք,,׉&5eiOUU|6m:fbƾÑ0yw+=pSBtܓO J.EZ\JKmoO@u:Z,1/+j7uyF 53mww=63>/"he)WėԿKڪmx] 󺀳vCG‚7ZSF 4h7O1!l3Qm b}Ⱦ| 6|z 2]kOZZO<6~Hєo: cDC. c]b8ݗU{;IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/crashhandler.png000066400000000000000000001435261360462764600242530ustar00rootroot00000000000000PNG  IHDRwJbKGD pHYs  tIME%L@iTXtCommentCreated with GIMPd.e IDATxi%q婺˻ou7zA7" ;! "E)z,{<8QLD;b̈́㘑%τ²%Q"ER @F4v}{]Q\sg7YB0`0cp80pli ޕe/+,1d/k/ OaLUܺӃ)0X8r|N{PQv QWJn_Te`"[㘃gTA1`8\"LOƳ¤ٳvt:ߟ>'8op2.t: F,}2kVNkb ,F زX:JDtEYLz˫wΎGQֺj=\W W+wh,%ջ`\ލp-DTmF ޾2LC؂fO \YPwE1MD "C&l߾?]GpHsc?9",^ӧO!h<.xuPИy؍/v%w!N'8nh,u(|9gALnA,hu`4-N]J MEG+V"X'c[;gqPuDyb!XlAFo+3Nb 1cݷeQVF;6osᱶ0#yMoPN>6dR{1[Gc&% F{e \"8[c~nPjP]cQ02%)C㵰qd(ǻx4aLZY@ɱW+\ziLM6m gV^ ,;r,guc%=0J"@Fw}ͪ^ÔD,"v.s\G~% vpjK6N>,*gUN>$um~W0L7uzSeU g\X䭯b -wx9p;ct,ǎ'c0zYpY sOӃEfDt7mycR);M[,3GyEmMʨF.T'\wÆ' ;Fru5`2[ṋ Z.^b"`7X`q`/nOpjĥ Y,u#Ėq.?_zku/;Ÿzɡ+nZ7)/`x%ފk O!ۺӛu7m=0ӳp!Ce;b0߁b~y bHCuv|d*.NbUה^UxovrI &3joS'RX. pӅbZ/ Y ʻ;v}SpgNsƶ)ԟ΅㏨A[Н}ʪsls@&G_;|n Y9䛷&A}d[mY 2^!cII؜aw"mXG)Sc&<7<o[=d|=l;7cx dW/}Xt/ˏbc^yؘjIHu bG"&1DuMj2,o@ s3!9MM#۲DfnV@u;-D:f[UXYf!1eX,'SֶOш뻱hN>ڍqcc@@(W‹a|U}j>OVA*&&opY8F ybU2Bv=aӊi s1:oDjKU/<~00s0Am;mlġ^`^Rs`8}OV^9T! lxf]}kXP 5Sd.+$5D,$#ik``ed7­;afnMȶ@m'em <^y&z=UH-7_Rʣʮv;<,|*H؁(8X:*Lޅɻt(! Nj/ u:8 B>;A ̀*ח>;uh]@ <}zׂY` |';me,d6 ]4FIgx\\Sڸ脿a B{U,&ar"ξYYN/lT_- XWa:҂auvލٹi03ևct].:G L&ccFCpm 'yȼC_"!3)F-dNׄv+x} Cs_}4Fuݛ߆|af,@ovN"48 .)9bqXK j TBkZ4*‘_x-+b!᱐4Ⲱp΢(& [ny fmAj Yt9c`teia-a EQ`ue,QΞ:3NbumlylcKڃ u&kpScr&Lb[*(NZEM`۰}a6oBEwNaf~j3PQq|C$~[0\b8\G1)`m5 kؑ#8wvNd SLBQMXC`cgϜeī(lh onk e| h *%He "ka'HF.'V]|s8s[X:8S}ɴ0$Ruղ,nmw wsvD0^~y{b",ϐReѕ( [1'/wqfAt> qΑcL\X.dJsW [ sCLS4TyvR|d~ r`{:݇ρWe&I6b[Xq'> 0y29W!Jr!6dh0w*Ư6}##Fcv~Ph{AL&c|`m+cɐe>βhġ=>:`"P'1Ef榝 ? Peפ^ BH*TU5lw`r稌[[BZ]Y1?.Ǡ,[֋z9x;OM7bvvY-/MP|[_lӤ:w-an‡>alݶb ʴxLf|HbWw|5F\LD30i3܅oDYL^z yvW;9MWyPYyثW-tiS˧ νcOUqcJz;g:GF;K[c.}Cv)8 /[LC7`fn{o x|x'ad7bb/}Io^NyA֧*TlӚЊfWF F!fuk_K_*xpwO~ mE$Drh8;5 \RQIMd0ے*G (ǗY+K\@Kk)U&; yongO_+:<ʬ/1UJo|< xoBS 2ϡȻ!J:F kW]FCv 絺/~WzPUnY< U>O? ,rD'rzjT>mz? 4-J" U8@_=Q Bvg%>; [`22D>TKVѣGo}gϞ:ևCLe?UHjj ȶY'(׸W`CrxMux7UFAz!w~DtBS6By:%/g""\UM,Af:ޛo?!T@(YmD/: $ kES%ZH|UK:iϫ':y+'uJ$UV{߁= G>O2Kp9j2dT%\}C^auAS9 _Q|ݪ-U!dY8xFw1;3ރPLSwC3:5QD)RY(UzH7D. 2֪ nhqE>lݲG**lע|{߃7p {UɮR ]ݮF!hטNW3$l / YY)5.Jam?ä֢!v"7j K}%iTc̚]I|{jH*˞ @KPEPJ6زCؾkbRw>:Hx饗:FU؇*ʾ}jΜ9,<^/%xH?>Bo2;| aE9C!, ߋje((n]l3&1GP WQ i 2\Uݻz--foo 2D|Cf2>|KXY[m18u R0NXH U'_W%ZdspVNRrP؅_'1kr6sV)k"C9ޙjA&SiD8Jq+ 14Z$l8n~hT-r-1y3mWFqnU>}X^\ (–Vw0κ@1*H, ~E.y.'_KX[]o;Gz]ԏ( 3Sa*1J ,DMh+$F C,2줺씱gǏ2j1X^ZOZNOWW]Ă(fBHrV3n]H"A n³ew?O?C=}< 2ǎ,v,4{\Q-y׶d@~-k!'2 0Z[lΖX;Js*2od`|ϯ`MrkUxHkTIJH*zHBJV Q~ޔyXsUlqIP knDMe,&ش?ae< GtTƞݻ93u^~ha1KKK\7XYfZ G:HӜX"86mڊ}# GEH#9p)y+ʤcsxA̼W*1@E B"rYɺ^º+xo{;n=v?UxR~f2|Ҟ=~)*,3l %snMbjd}wx͸UYNΖ| Urf;5r+ bfzE=WoŽmX]] [(O88ww=,XL>i:+f90v>𱌋SG};NhN&S,]ǽpp$V)\Q1wq1 :M %rʙɅ(Ҕ}EQL.܈r5+]_hY=ОPSMaMdm^:`9Kgϰe{w?Q!{k's}|L:`(Ĕ Tx`d$q@ri|H<0w<_U-K [7}jy6BJbPS` wN tq]w,TpIxU6V(e54KXD|ÐTN`d7Q+ͦp27K̽pX07$@x{Q|YSA=$HStW1Lր41A qq9[E[vOIjsxڒGMKRϺכ`|m6a_Z[LafvgWq )&d5Y&"9m{ -N[ `]15NcHG{s:O (tZoM)oX^eakLIc: hMޠ@_H)Ah}m2 x!Μ:ե7`{l.tstY@V 80ϯ™e u92p+A`vvtS:XW͚jFXb˧F LFeB'jHr ` fZ;Di'܎Oѿ+Ҁ8* +vpEOta{Y8!O  5pˁ F@A!#|SO-hL+ܡ>Zj)@н|*QQyzv+L%{.s鯋,k(&&R(XSZqqq|;\{'0 WHg7X-%`$ }uuvAW KCqbH-7ŵY(`5Vmhs& =XĚJUJ~4[6z8u_2ִ7oٌXʳ珯)|zdX8njRfF{VlU }WvMiHo,Zn!a6 Ucs^ԭ3&Ȭ;!wjv1sBk:Rl`~I-:æB)p85sI)FCB6kR~غcwyVO̳(QrRIȰKhc|TJ gEc6Z VCS S2Tzi<@rBei#AcD#GqbLEHD6Eȍ"jl8G$&*۔2~Jq3nwQز|2VX:1F1.1(F&MUk|1/z9\o:WBuD"3p ~O0R2 O"yI+<'2/RIa$a㊼T5R'*t0Jr ǭE9g,7 @o*m&" yY9.lݲ6j B+ „!1+35֔L!UUQ-rpһpQJc{# aEdw{BU˾Wwvbz|rC6VkK~+2 -KvÈힸjv`|ߵO:MsS_Qf&JBԨFzE Xy_@5+ΰoAFT5UI9Cڗopbf\׻tx^鄥j&ddQJ?4"iT;"6(/t}ZQE 3a]AJlBdXIʣ>SBmDGʰRNZGMBg{ q.RH lH"z]V-}u'@ݠʓP%I5DbЛMwŢqgkg- Lі gq`6o;{) S[@xm䉟_+֝-H _Z jjy֥'-G嫂lJQ<܏[&hBNtXIGS)3<=$sRNz5ht(ˬ6>vy"nr$0 ,CO1 |(&rY٠lj#',B$U1NxxXH\V< dС}m`h\.׍ |$`8 p* *n#vRRCgR468ZxMQ$%ڱ|UU!P "Loڂn;1;vX:Vǎ-lˢwwurbh[}Ԭ(ióvhB#TDe,$ Ix'q**G%BrnUe檸eK)sbbu>|[^-k)I ) 9 XGz}E 0ZtX:QΗxDS8i`.#_r x;Dc !q*ɪ#RqА?սq9 ԔCa. zABELI$/42sRilLC4١IzKBCp>\j2B=6C$i!Rݨ` ssĹ+W\Y~@iZut -t %AjZ" %)4U54MXUJ2t[Ώjf5thKKekY*-IZUi@Y و6J5I9yK:Mq8Fq=ywZ_- ܄1Z X؂a}.+h\IM>N٥uE()D"RE"kKHWUd.<;׊*.i8U 'B2>qM$ mDJdiнFFHJ}G,3!EwX0/kևþ[8t$ڍaYFRhxVU=!ŇJ*0&1REʨ\BsKIRZi7pM:"6[It؂~Vc'- WaDIrTs*J2du&FxŤRdر>^GuY%9bQyk9F% :  LZ+dX3H$Ev2ֵ m3NHV(SZUtD9!ZYmo.ʩ2n/UePNj7K܈j rK6Ȳ0x?:`f(1)hHsJ-i/E fj@f]ړ&!K uT(ҾI5z'cZD;Upf9]y5T%H&P։e#i~';LME)b^ׄΝ?.1_* ,NrU(U!~YkT!cj@T5W2m5+\֥c9X,9(&N+} Yh9יm7W9'"rd= lOյp .au&JbR[[GĬ )Z]Z.3aُ AkK⑪Zu҆ _`wu8Yw A*jJ*+HI]6O)ee 7%'թ @VhWJ7"l%"!>N]ȸR|Vհ$yy+*E!T7dZ`8a缗uqÆ^M5rܦM+d5o̳&zMf9tTTeu g!#0!х#Ob{^zݮ˳($iWՂd|R5"JݕR EKqDaXu9 ZE(~|ba`ͬĊ^ZHɅ]CƇʕ(a2Ez^%M,"qD5ykB싥P'YDر&9hs]n/{ԂZ'CX:5Y{S'AYs|TWsTSQ θZF[_=3ɺ]K&3̜330?jzXO#dn|̓mǯ{2@*V#! q=w,E K-۰IV\P!%X䒬{gWWK! FxG%e^b8MCa$JJՒsEiu M$4tGPm9"pw SJfzrܟn`o`vLmٌ&t:PIvPZc/|aO/>X+%*·m5$$=ؙ7끹r!xG@ƴHTKܑ*CV~dD$s&),e %JZKUɂX>yoH&S+['(qI@G%yjbn{]G΁l\:uFd@&19 U&ݻ.60#bjP 77$Ncc %CƉCKp9 AO,ǘx5IR">eV«hn 8z*%cpnLkkח{8ϺѬK"b:¢i ؔE@k VJ@y-hp΍[]X߆ĢWEgu` IDAT YWMpwQ_w1GͳCi]I섍bW`ըή2-н F/9,4u"[C8&N~Fb~ 4 w2 s2@UMk Q$B<-mĆVoHʅ6Xxzh}5 fF*cJ>s ޠ%u O[ !xАpRE;)PLJtYQVէUyGN~8M!:S.cn&v끯 5}ݥyVPTG/ENJ1 VJp~ACs1.vcP6EF"<( B@ qb1D I'eQb}y4^u DE$$Nrl CΝ<}x'K alWO(o0VOP|Dl],Kk[,ǩw ar_1Ms q-ɂJ 0zdžb75a}rXY~eQTެfL.t$ڵsأ!;i^P:7xNZ FiʼKHRY4Tw9< Ν8]S_7QwМPO";~O؃_"~o~夨(x)E 99<9cPg``.jʜ@Պ4b-,k+J \F)E7H)(jlj!=gΰ-`gEFr7`w!/h ɣy:]8Iw h}O= EQ-ƀ^$)"ͤN+hC"+C<7:U)q!3x!Lآ735sˋ4&IZI"$G᡿ <ØE(&c<'bcL k)2آ@̩Md WK$ObZ!Z QbRӊb#!kܔÎ ;7`&1\ ů倣H`4bAF2uQf,&x'& $2=6( )ɭ ?R,C4<$ƪ@٣ɀ29q k0Pm9,hؒ>A kg@ojz=,GYLW?ǾeL&ͦP Du oNv^T!O [kY+T6 ID9R1'Na :|L2r\ 8uBl}s=lXBIAkpK`*:nj56|pN.@HIH]rX0T -f&XU)U䱇Wʫ8'Bd f'PssoOD װt&PNx+ǿ(&cincC4 D́Ȓ<wН"f$^# YU68XfLCDƵGCN/ntۣĹYS!jkMd.+H* `! IǏ~ ~_,MǦji}6oQNB]spU~zFS72p4{}gffڍ&7SR0{~hIKjOW?`DQ7.H񲛺2Hf[kCuqUxմpdJ9p0f6/jr (Xr7 ww 4`J=-\8{ZՄ<ͱIH JA7=oc#~,?]{cf~3lRJ#4Eh #jBQ9>&pරq=(:1m|?n f$g5ٖhm}d^V$Ѥ/peAAEH$6JdbNxJO% "e9:vbG溒18qayx ݘxMX8 Ge5DuReQ`]xG?صFk+{n oSx`vlQ֥s1SIjh [}h p4F"ʆ_.N)v &SM,(vl4R޸D $YBe'Fl&DSdMw&tnŋn7 YO< ;'?c*ZF}\E'Vd69f#UdHBA W_ ?} 5LObN l0P+Ih@j->_丵JG}+&#oY;?ֻp1^_C0]n¶׃A(BhI:FTN|NGrD[Kԣ7 /Q"hvr!~!:8Q7X0_OF(H2Q*z1+`es,Su<`vnC0xt5i'G*/U8B䲘=(0we5}a7n l,Pڲ2'j]^V||[0A?qQ¶Hע4\zV~mE"vYmNXl,՟X*걤 Ǩ|U0Ҡ2Z頳uS"a+K>0^x1uI[7uDE:]ƪ_O{O|^G_x?PLưe܈m W 52"JM7< sW,11U*#hiHZ-q[F?d*TU*Ơ)P6`JlR,',i+%Ftʚ$TDCCxg1ae<'Auq*_)V HwI%%1b2 L7t 2,;'.N8,Kv\J:&JfR6iA"X͂6SF&'ؕuBe#rGbMcaRyDr!-ezX,qtl:s#YUZSS*S "SY*.27;ETy`Ae _H8ȁbxcܟk؀8QvS)S eL"߶߇3R')V| LJ g|C )mFn? ~!{yt;=Xgy>pziL&PTEkZ2('U^_Lb<x\eBոo" RFڈhiQN ofI@:>)!D2  ҽLZD)E:BFXðgdn;ҽ(7mO&#;X]ZwS,_8Nș$hҁH7]c3?O P< ;^kmKc{ϱhdɺ%0VݵS)=Mѣ#Œ Vq6AA`ǁ*9aLe0515Uo|AqUV ώL]&Ԯ+/]A/@oidnY=n5:}Ͽo!r!, lf=S!;fbلL#?XYYɪ^RC¦]F<  9= 9)_)/O 0(B(jqHfx2omX׃Ĉhe"jVo[uI,jI?)VXx),.^,YPX]M ]7 :TfF[.CTk@:} ҁ(')hb^za+涻q-wC[&kDŽOntg)KFjW&[aJj89*䌂ʁʖص'7Q4g|]wq C8/ lIח\T,Rxu|.:\wDZphijR]Espɤ<$/>C C>gAKO?^x/֫on@kpUbt !&@8y0obW͘Ǝ2W>.6\zmɜd!C;rVw:`Zh=SvAd2 R b"{Qvu)(rӍ5j-?(˰D($DG?GQȵӒ/,)+=m^>u~1ܱ6Jy.FI|SH*Utu0fK)K$61( $1ޏCxZM.G{rlXEKPo,*v^yIs5ЩƖ5N8aIƎ)b+PapصR0\YMm&DKGvRȢ0ccQP 8=*2,)(ʢcg۬h vJg/!h:`}S3P3zr-|IkT}nt|4Z mdUHVw-Pg;~©- 8BEtf1qG, hF@u@`ibgVvomMjP*ٍM=Yg*,vHb(s-x3[9J*)C=sKCa)'9DG3I 7!#`-^S8c rET,T\cq|2,w;ώ)n3 ҹvtTYArC%CKke rE qL(@UfKW@O7rt wTp2sq(k:ve]BцWYJŒk̎+<b z sV~j7!ML%P9lIyJ#fƭ@2J3IJen:gr"Ίw@gY\e1`tU>{_x KJ0x5Q#xm亏.\Ly?AaCH*3ZC:0x8h4AI @9$yv1?s *49!J"U{blZi]Ȉ쬢 W3kuSfIZ,p,44[T,,ITQѣ*x zBWkz3-oT."I' *򊧨 93,_+W]} 1We=x)|ΧZM%ܽر`颜C)H.5VC)c8N<5f.AuRęeo WE{r7+Q1r$)R/_!esFк%(]fДUAHz*?Вxjj֭]Gle˔ v:xWΑ'gJ,cR N=Ss2JU@NJ Nɕ?!ʸ CJ*BG]QiiC18 !?Mmlȭ6\?Ō8 "FR5^~a qBXjd|2t'5 {- AZ?81;7RyN?qg,t)er;fpiCup~x^ߛZ+!Zˉ&X= lPTa(<9L͹Q0\8`SaVf{0e:\pVlJ(rce2R y 7A\H:tA]8Nb$ t?7[@! CjIԁHʡ s9lA-˯5(`i[{B;<Rqiϓ@4 Ig ByP0=3ks ^SbZV[9a.utz̔K64hG VYRx(l* Kt`B>04b=СJ2`Ymi`h\򉻱t*$Hpd>s8ͳN:S$QĄ+MRf#%OQR9}dZiPI':l&$FDߦ˷.JeWՖxf<5YRfe}?מ1-ZրazZq2^"ݙR\GHAD4?00 p1>: ]8ATtRI{r~T@k=ѳ2طo_{r-eX+ fX3D:EH 22 ִVC#J-ǩ}BGg<9@ Ҍ Ҕz(\.c6=PBi8u5$6Y>~5E&٣B۟Knj0`WࣟAY\ߴ͊prrq2(miecoīW;(`|x姰`xPa-ץ^]$Bmk5@iEXk{RQ+[eb1W aٲ!9r'F fTj X7_ᔟr >_t'SX[{ 0ʗ10pddgLK΁0$\XNQrUP.h@ N\1G+*;VUxa ^ބh!h4ZZm6vA{VrPKW ]P2Z'~]>irtɖQ|L_0xv͉bۅ۟FV "z֋'O_oި#\q0{P޴$JR+p&Iw@`b+j< !|XALνK&> Y{\8`:yOʩ.xri@r{k=ټb9\/{S&,|V1P bjm\ڝZʿ7l-L)t.x金&%(S5ɪ% ^^R?;^@X:$q֋ފ onӏk{_4c>1^m+(tgqFT/9F|{fB&A pDJBT؈\cBԹkre3@TBٌ.LH~O8NV~D$1BQP2l3/k_3@~ P~ż +PdmK/rɹg.lX@cޮ`\2'ma<ϟ+S {>oNDf7j<>NOƳktlANN#%.j\7YКX98XYK"GqT28I-ДEyNQ ξP"T:o}/Zb|4<)8Y@!Fe"3Jb&)|Slݺ_Ćr{Ǝ 9RL$GQ  fa2|{* >{'(L";j# eIX)Sp׀>W l]67uhpH蹌 NLB~#zso6Xުa&hv9M~ok懎4+2,ᢴ$,8I4SǡPhڸ+h } t'?/Xr鄲>/uL<9uiSwҶ4b*Ѝ%yE꛷D6êd5QѢPiXJ^76syZARvV)9NEFցք=܈8k>T`Nm DK =Sޚp#GC)uKP/pHL~wdPh dV%G5rƕiqӣ#f5$ qe^6 '`vҗŋX ݉| c''PLʖ'Q5{0FORmR*"{ 2a c2UIk{\J s|: sD\1uRZʼnc.m/@"Q PBЦ2[.eBe!SWA햏Zi^,S?:v (.h~D Ǚs@v;89zʯPN5.X%K"I$I4PDa%@u/~/byR;cE<59oogޣVQ;,K]~!ī(͈xD, V,Npd, nj[ +/DeG@&$+HJ7z̴[9N%wYѫlȥ/r,N>4M (BEQ0=܃ZfR[?y›F Fw(IJ\(Cכ* /0 xBD=vqO\Mo'6XiόK=jGVh僆J+l.㮪I\t}|vfT:SAh!ZTTIHd$m031.\5&eOȺk d+fJc޽x饗Bbkk75Z2Vůo ŤsZk`S?׀aPwx ]oÊ J/TEfX&WWBrU"%Pv_;H^,ϓ){B9IxG,2.W 9< %̀`p85HҦ0{ Selnh¿ZW sTQy`^xxD{{]j"kTk ,`=R{h0СC_~ZHS8`t:t:EEh4?|sy-. k~DIa`b|86rԀM(BL pxj!{9N D)r9k^wypztnn9@5FRy+%d&Tg9A%gA6Yֳ26F Ogg'"bNO?xj[o +7o1.NZeWkjqsaff=0`5!2RF=|azGZR ǏK›? 鼧^ya-QQȹR0drXfv-V\~n"pˇ9%6>lN󖥌Jv~;s,ً֭nFBl^ZJUCZ%_`Yf{%DAOkFx53s`/(5IV7/b \qDZAaŶҝexc a+7n ȑwa_ގ᪫ĦM0t)!N"n7 n`xx/ tZ/<7|Yn[btcM` )S!`8qh.zEr#ŸC^gIY,h9+KZ:hA 0ZP %y )F(fx6KkFk;M1fj'O3?:Ǝ%7܁ꢥ%a)ãk-{$By~iN8}xGpc͚5X~=.XX:4ZNה3hZkn8.o39~`f3xa5~S3@/4Z C@+C(ɜ>YQl[ GbDGQ]lRjʱfvi$$f$r_4{@ vy%d3)|=S; T& *ȑ.0"u{^(K݇ɱ;lӥHUQ߁낧ZXrlqo< Y~? q wߏ@\X`!-_z82"#"!ܔ0/[ VC/>#JѸr[ Ͷ*P}~{ُߥGo?3B~|1mP<ibѢA0#@,#W 0DlH90@Մ_CUS(^[.^(0;?j-'..9qz)VORSIpGH*s į, UfZ^x[`m=zJ'RA`ȡ1z3nGsp6MS&6_ g2c/ZVN0j>D+n7_+St{!PkZozְU9VD{A^|O|'5=9GޮA;oW '1 Â:NwK'&T#Jl&|g! `Pd`7^>3G]V~v>(O mbU)®& @]t5px޵'CSr멄C؄8`\` @4pjF %icPC.0K]aVEp7%hLžgzTܜڙ"8u %i*w 14 ~5gv:m2鷤~<|4" *y #W)B1B6KWH^yְ2 )#2CgqEFۇt3k/qދ{1>vܖviYT`[ezXNP Cl3x{57{x`I6V*&Æxa<:־[O<:6ulJ\D1}?cI@܁N MF XCN7dB:Tt->F\Kml|" ;rvKdQcS* c(ܽ3ꊲ<עv5X)/=e]vȖ 0;7ן{X~`NrdIDXj ]W` tO`;C<=LJ177cā5*,Bu*^4^z;L|W˗ n.5X6SXUjRܙM}ԚE$IS#IlӉ{>n?>7k_cI)aujIYjr^LG%d@esJ:EjR$ ?Rv>'8ލcyR P90 j#GIlH,V-3"4?=|kg7PHMV,Т!(`ɦ 03=8@h(6^YɝZ1H*X)o ŲM tRNUJLAf#S|t/+"J!vALigv `,R %NR;ʔ Rў JdWJI#LBsI'2(F-1+c #Bdٌ p"/<;rnR8qhz\;rC6;5An\ZHm0RyZa(L8BnQ͘;:v<9@P…k^:ڵ'%}d*=x=XQ|~tJKTr7y!lUq[r<qJ Y#R`<_*ש"sV =vHRvET*U$a =kd%:`F)$^Q> FUyxo1{~A1+H@VU* +t`UWič<8YY#tajHg4y=?(1ҴQJW~ۻ wxww%J+5]ew?,]syt|#@āHiߙ1K L_KDA@AT)l:B( b V(gaY}p83tBʌVW[z KNeSAb?#Wj Z7V,3 1 0:.^ꢵ4sjU6#5uz5gNM\DKhof:(Mqrv3Q_g1ĨkseốP .e1IH?frMIQc) IDATz?e`^|Aɡh2^>[p. <9„4f'Bˠ&'e^o$iR כ+ZS+@5(J*FeB._ Xy63ey6Si0'6[VVbP+v)F@' Ta? myџ13 XP#BǘKW*{@031`~20`-gD4A }l 'lf&eDB!9z4n0w,"w̮We'&=lî*v= $nоӅùICւ([Zաj SRB&ڃ%,kn4rf\9}F\c *V᧘3gTbTZfG|A6e|QX5~K~brIaH3H̜ca!22*V #LjvjnŃKq wC&WJ!Fh)i5&S$gJ8:s<`$k+yqZPV-ZK}l"LV%:c5+֙?&DI_JKi e5 hvv&8>:f+9)piINO)O)V'' 1o|_F=TkeL9M533l撴i3ֺM'QOEQ|<G24YMͅjM_Zjz\tpev,/fFcy(r7:'1ZvuIB z#ig+tLaKO;7+ّɌȻx9Ȥ6X ]+@XWl4@[&|9jn,D|a=7&^Qe3ϰ>>}:%sZJ^y s} @Zwg_HbU-sP]Oj=.*eXjp-L5>Os3$#G?Ӧi˯/p5(rW-*7{@%}xэ欪$~h#ٸ͊{_#zU9dHtn*`Tt[S2\i g ><,krRۡ }ఄ~ ʁH#2q^U As?glr5ATTcޯbfl"ӋUCk;?gh}9\rݎ.B$VIGA4^op`vDQV.Tڟ~`Z 0êͪTU1N(T>?·85F{ICk49˗8 ЄV,#_c bCs;̤]+J`PkeC+p7D%Sh`ːL r(BP'L P8_`\'YO>tFhT Uoju3`ܟbǙ2Q " ؖ68Su=z>^@'S"ALPofh=`BJ%=+2&!;߈yw\H`ۅ[׈_ʦӅg1$v56t'U?m<^ AJ6h%=ˬ"\V#ZxY XKPK\3k9AL.9ZĮ\sM"` Y5Wyʰ 4U̲3`dgX(†P9D}X;J!]PЌO)k ,uuua8 ZSn"`reC3x177c=I.ykpn3P&V*BDhA՛MqNp&.׫CgN<&E46αqtF'O"M|*E V,@eQM,/Y] 6\l/M+uk`,r`3eį_ :oSCs*>g>aD'۟e.;>Pnsr6b9z\u Dŧ=&|H!+Z.`)* %|k;[B"(h;{Yqb3%eq6`z mH_kZ^mkaanʕ.ͫ~B<5So_>ȩiVHf;>Ͽ@U}7-G7b覵-}YgaMDΉ!}V4 YQ7JqݙckW7ruؑA8`oa{;szgq_F{ƫ5~x9u -*ոS1΁`j*|?),\m ns*ZkhBl)VA^xr]$X*k?ķ#:IϘTvՁ6ZpANvNNaf;sy5; wcx>ֺAK0txUIgCMZ4L`Uj^׍ KY 2gmr puSPɬ$Ut_{s?=;mm6g5c7hnȰ %nPf)iжcŘɺľaAٖiX<ܰjQ^UjՌm-x}nS+_G a:7/=͟5{{"a""tr nXX| ca2$L`bdS‘YSx?=7k>}V-Zy-dK=_%.Hu8Az&9N.zh LOf_-m@: >v%krZ'rMXy/@PζL1k,?_YC"0^~^L}%R7BqZʡ7Tk@5[P՚P*![C`Bxw~oA#D0 hapFP'3Q4F~pתhoXu-7aka~5ݳ3Hgb]X[Ϝ^OH$m*GM 枬ZE+[\`58(KKG.h0:EfTaJ.*RX %_BBx٨A|Èx(@EF#Y7^RkgsF lMhTA~=K=@0r*bGS \Fv V^s5KmV@9*ff43 DPN\<yfQ^ZMqJv [:]:LJ; ~ ^mXx3̟ǀJH9F .cͻ"o-QF9/M{ \_*gIxs==;xK2K.epԒd},5"5=ug8v?}{y` dRw7lJMЋrEEC䷊TLfU$ V} B}fW?0>DAD_u%V^{ hAHRpᶙY809 LN͝ tÕ@m\5@ ./h1s~iFw׋XzIl/_E/OujѼY3wrkN%}78gX `<'G0?!>T \ZROKvu.6a\6rQC~7c'M݇]}FXa*$ 5n3xC5̸aYPlڀ -GXZ]hw-=qwuÈ_?z+%@;]P =?C~ #FY 0|{A`t x.݊6oK`3bz|ǟ<# `3d3pɘT>Ƕ=wqbɔa7^Fwߛ҅Va{,XV+!vUuzc+PAxqe s[JkDՂ^vx`ej2+UjfhYkZf~=U@q/X{b",Z V \.hftl=i\΄0!Z+[2q MЪH 7^㭇]10^ïalՀgG:J_fϹڧP}%;<'UIPgGin n& i'WKr0,K,xԃ# |ބ^\rz.f޷7N\d;56 f0a˝w.w#h8xxpYbH9WKšS{@ PKqg?ū/'.=6oML}`V ˆܠ#GX6. FG>b+L*0O,)K^HSY ^{Z:ID1ޫrܱ|HjB4} {o< _2Tv (z:Ƴ>TPU*&0MxffՐ _*Iqɫ?ǨF.6sSGYKCc$a SfrNe{ʲ.3$xbhp jKnW.Y?'N@#`KֲzȲ@_Erg;L}nNp?[Xinɉc~ɮ|c:E=5#IR)tȁxGpy3dK Qx>l!BIe*Ft&X 29*(n P VXCXH5.~'GT\tXvܝiQ_V#NO._~Eϛ}q`b ~ ҁZ7Zv 8x>0?MpYJ[JbZЂT_dr&>aZt@u Da{J>r$磎@g "jGː2bd|o=}8ʘ`ܷdE>|n_=q- ;YoK@C;vr6u;Sy mw0V#Z0tFַΎ|\IeEsf8Cr(#MaVV]~ I1̓ϫSvy687syɝ2 嫡7n:0'CP Ն6jMCн|5"Zo~O_`ubM7<~xzFXhfQa;2ɢ%Eޗ;">21$ VbҢ!FW&\`i}.aC[̲ٺ<e=DN5o!ڿ$梫0| 4 Y͜ϙh= R(E'i|GصT h]fE n/]i fT 0zÔAD֢2G`7^F_ tggM /@Kj,eZ>M0N #:h?v35m#`3?μs>Fʝ~մ{q:RHN 9P`FyXrDv!=a(3ґ?ltwo=^0IG~ .^ \oy ? ÜecZÖƿ!s*Hswm'&`x4=mOv^h2y>q}ۅJE$H>xnو OўG'uK l4au:e-{ӼNlS$YˈYzX9yu A@OЅƯNS .EKms#ӑg,j4Nsqs;?1JTNV^ Pِ)4Y-Ps5jA6h:Vj=ӳj"#f0c7 j4pa`b-:qL h\9`}׌Y=yFC"w)GFNC.ۆ[63q;p7LvV t:Sv-3=Թ,':a8R،Z\ kӚ#H?xw4cv^`KI n/R _)\UBg3Wëլgk= M!Jf$[#!+.Cu&0r||]߅P>crFa䌁u@cOg Ki0 Tx /o|{X ihW,,}j~ V_o¯7juxT{ zހΨE'cm7#"`jQg6J%DLn+r``WgLO h.ق'Cܵceg=lIory%"sXf6G7[$YYβ5$,,KUo &م{vR8Wd)PmW^7 1lEPi6juJ 16~Qoff<_K,zR!Ϭpey^rԦ5ғc@jR,v9J Ÿ 5?7 Α_na7HwڟHGxWXCr1`Aͥmv]SgjIc9IsנZ ^0JuW*m,^ F#J^aAExK9Ӭ1r5@+.+/Eҍ 1#&o)s')qY&+@!m7Q[7dži}`ך K6fBiKɽTR'Hls潕=7p%sy#N%p严; ,"(IlC+ A \o«U6ۨ-XDǞ=vh~PJC)&ZtO>˨өois#3f3rSǡ%d*4'|-.-^U 8g/!|^ɨr) ]y2K *2*;kF"Dq$I E,s5HJ~-t$$A|F}`0:rDMxV V )+zelG .A̬AfxjW8 Ѿӻ1g={E lT7>/qDhaU+`r:}l)p<$tU̝k}{k?7g&V*uMJ|ɯjÏ=Cz[oT-nhauU-(@[`pr#+k :G1wMY[]7 2sG$ LRlcmJeVy5be>+$V+g%eJ΍T۱1'YAN>b+8D1QSj]4B+j֚NCfSEjAP{S*&Mdi%@`2)YMnnds+X|Ylcy۹ײU1FlN3:[-DO۹^gcOө`zտ{E% uEK$OuYpi-^欝x2P{-c KDU?4I Hǖ/W_tcx0VcB٤W+GFUdg\W+xqbM,;| ١ܡT\cbw(VC; ɮo`7XC);zM`LQ {kuA)>D$LSO<)c<#ĕJF_XZ%37|ifWr $HϹJ )4;\|·6ozGH/Cj&uY!VK&QFN!>.(E{liU~W* 4[T} =6+xIQN8PmS؛bA7c~W4Zm_A'Ĥ66ЬxSa22:JZ%k%+ Vl8+QHthZ 7uwٺI[uYV=Ǜ6fZx`]lKghrR0\ X^+{q= fAN}rl3[J\'j'|aePԉgH}pa\Ekݏ}! qI6[ 9fD4bSWtA4%MRRv2fu.~02>6$Ů:l)rگA5<!M bn'-k߁8nƶ;v=1B\P0M 4SQ&%V7DEv1M0J\TvKr=k<ʡx4׾W5 &ϔ35m^6#{fNѳ IDDYk*iŁ xV6o4Jm-l8ꩧ6vҀdmD$`@yYX=T`#i*2Fki,u  :;iN1ҮAVbSGK=0@R7֘QQD.7Oxksx Kv6>͓?W^L>?2!|>$muUߒw[ OMCՕuxuwc57wK׶8A6Re{)ZxB$IQ+`+ta={|M:#I{fS}+Xuꍿ qW13QH_!N#|ѽG4by(-4eZ\,)1rtj<«-.a&͹k4wtIznX.^"+Oer_(őսR7r&:/=(vB!#1y>tWnOg_Xx:kZo׶=`SIݣx"Edh3/ D E^5KٸvYDb~6K)bͮl)US;M/Bfiϡu*㻐^$=6+yXKeۧNIMDkK:~Bv[%B^",0n +ds8v>ĭJ+ξNv "]+{X :t7%4@z=GWxvӚų?`ȣD{rM(Z9HU9ءGOp/W}@]]BKH-x4E[[ haPmJ;Q{ɕ0J*ulH=$љh^:¦%_x[_SM7cD(%\B\Vᓿ)h#Kq+W鶑4"4!I,}K(Ab(.ޤ`'䢾SVvkEHMe.IO"[*cԮ߫:c32*܇mGHj 6E=)ʄ0c،urz2G.Dq$RrPkP({`}L+H,(qmZҾ+ֲc̾$)E~;D~@RfΫll>V WiU-n!~?u=w2WYMJYNojR ) N\ +AġG0v܎8 J-Lƪ<;PU)L QBHjDse3DTQQ 51Q,={M\WJe.tҝLf IB z++°l#&F[ʌ}XN6nfQ}33ZGQgKRb'vf>Oл:IUVaoZ'A}lp֣3}g;V)d#{"Psg0e箛hl!Ê4w:ew KFa_`VN8_K%70J@ ]]63<$~^V{յ MUX)ޗW^{Ŏ V(p3{QN<*.k,"PUӳ!x6hnŜjZR_pTy-],sDV%P$.ot UJWŋĵy"Ͷۤ.}-Tt`V}ݗ.0V^3]?D!v:, z>K8Or }8%(Q _l݇,lN{Sfl! #w[Ē)^ AT)yA}S4M~YY65:>_hgH i21;iFBz=accxb 4NǹCܭUEG)SŮCf4Z^2V{0u7GPZR%ď\")I^B2'0fH a}"Б7 VqFh]9å  雈`juL>+"~|oY2Jc{䥓42\!}{O(x_G܋'*]mvwO%$q@|r4_o}KC[Ѡ+'6Q^Z2uND}"S.͸xR}9k-0AA _~OyL8H6.:=uzNnݿ#Ú=uk_*@u|νJ׿|{i,wVoMk:"s} o' #LzEYqLM+0BmRzK EYD0D? fiq hP17GuCmŶإ%7/J9,sG˲_VdjMoc5VC+KҳV)xE% ~půסh3~?_$pyX4<@\_]x2SOUȳN"a5DžW^3'YXG(knjlt6`( L`0&W;(Pw,CO!6=Wz8vW~=6) s\[CҴTJdXiJ-7$zjQt۴ܷ `/jrN؏gő}Ơg?I* ]"NpG2뜿vJ ZT2RC] 8BU*(cVA( 5XiNxZ'Tz!0shcxe伡&)[-]-{@S[oE*C^SRK49#ֲ~mz3N>]EYsSM BT=4ɍ+w]_L KyJPZFQBSv51C=,mØR#PA ZkdvlBffP? |fT#80CE+2k6\rTX`8 * 037i,Io ߮SEvulk9h" eb򓟡3_OU QiLb>|:ͭj>:QbEJ>BXjbALd1E<["Kȉpd4L]:Xʼ_9L|$^JVf& LBjY2Gki-s `=r taZZcO2/ Y%Ϛ(^cMj.=Or DE1:TkD##TZUd5Z؞{"|Vi^2`.hrkx x:YlX?kKnhO`̵Gb^T%$ČU/~}Azy^_ʭv@u`%k!_\9VsU:} =Z}_<+)Y+*[BçGgF1> O~p 8FUj>B<:FTM`֒tfb.j>}[q y0+Sg^董}YZɂڒ%% jK >8ws! s0;Ew id nպ%w't\v :L ?ދ2[o9|bWV\RqGBf8δauT}`dpdxtZC@X(՟(f` ԧ}X :!=|S?+k O2{b 5N!7)>J.M.ۼn~ѡT%uusy+ⷀ?RI:ݳҎG!ro}[DL5B@ iO>Dnm*j5>9՚svBaaJ1*a}>BbG;$Nd*ZuZKϣ=de+g.P?pѱVK`֙aR6xS+a)|+-`>r<6 ݑy?:% Ymtll^ػ%i 6:bPN ۄKO"_noӳ j~ vCbVWPTkjDPVk%(iP+AJHCa3KN9ŧ1G+I1H=x}LM$&e;aRYnSZc%>UYP ~c 0@җȻ\ZmoH%KJiM};=ruxE! @biAL>X# *5ga+ULTqMt{AŋG ~?HXXZy 39Jc^:;ne߇ 0PnU˥̈́VT!~h4.`ܵ|`Tf] mUYԾZ8}ӂ#&Ƕ6()GX5g!i#ڸkiez:ΦmB)SȄHWQQP^:3:2'կ t0=J9BmnPamCzկqXhؾqG":8MThh][dKtr0aIXXVAZL9FgVd]̩@2++6EL(B *!00DLtu4)idV6AvG)HWvj_QJWjwS)3mƙ[͛%Kx㜁lnxMtp83© 0Tb顇HSMAΦ~: Q Bc{]$MG)'ܥ*[DKU٢>Rr'_g5GDDH` DĈ6R33棫TO&j>{! hDpIJ,lѡt3Mr%+ɪ0rd8+emq5 нݸuw9p@R[/~ /āSz 6a&N- sź UƸ pkc\d>7) Եť/Wpt&gUs}A9  3O&U#8J> EV&$Khh fQZѾ© :|.ػP J|gIA0fk4qiZ>6FEe+mL\9XjEWXo}RU2H7ۣO~wa)OÓEOѹpyFp75"iTK.e<h]T!74/ͱxdטrIDAT撬4rw.l7:{xXF/q@{nD筍h q;-GL4}D>z|έ4X?9.NiG33Kx??N/_=}N:MR$c&G^7tvV'|&|:oƬ';E7hѢq,yV ů C`mȚ,n4Gƾx'cFc2m5m;"IRkCD o})+J}S0[l5tҋߧ<UjW3 \,kϺJ\pQk8چL;F!:4%x{%5ld5›!r79h"5J8=N4;Ekоʹk~y^u:[\jHax^FT=Apũkj U[_  ]e=wկc?8ƑLUgL"Zm[\#YX%Y^']ṗbK ڭrtbꄻ 'Gv"Ykxk+sy16 | 9'R2 RNFy|q-f]2 'YJ &5P]ѤzdmvHV7H[!CJfTx3VÌTmWi\]ª6w16ϖe ݃S՞̀qDp: |KX2BN.6*<;JQݻ$* %m.imun2I˖:t`PQ :1 *6#UԠq}T:7 ɧ3nv;sUf= <d5|?!`s<ٴkKܡ/(wx#59ͿNbxX;cuUmzqQT"H/q iVn? pVV.^ݠtV7Thw1V6On6|6;}oYWg?+5kꓹY'm~v2 )8;@0 ccS#p,Y0 W$*!Vbf ͦU)ǹ4֛Z]zf[vWNJz,|xp'ƜBkv{l(;Ŧއ-ũgi;ܻpJpp(<>A(+C1Q& ё/_[&@lN_߃s 喝둃3`à5K\+wd]p&X0cAxb ~_lEdG˹kp}[~-ަ+-펅}v9`u /P1صF^xp0h3 U@rRXIрk79XiX|mTmȝ^\; nvh5pGCX` AV[]B 6$g]2͖ڨ!=]X;5~}\aNdvC"`Q;JvW9vc9v7$8IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/crows_foot_notation.png000066400000000000000000000364431360462764600257130ustar00rootroot00000000000000PNG  IHDR+QsBIT|d pHYs+ IDATxwx-Iv7'7D"M VST]X( " R!%M-?&ِd !y';s{f9s﹟+IJJ2 """""""YIJJ2%=ўhO'D{miOHM!>%˶VqpHk3D{׮=9N f5tb4e<ş$[P,Jw%#@[U{r._3quivM׮EDDDD.N]lkr7;:!zX>w}ۭiY"Xu+""&̐ Rmv`EDDDr66Jk1P(h)`NH|J6f톈HP9r$" .`EDDDRVQV^t U|v/V`U-QaD:_O.߿NTFIY%zrss|ZBðDfl)IjiԦ4Bzzz H046/b^nAڴBV+)zFfZ=.](++ֶMl5^\d*,qoֲ V)L8E֩ \}CEy>SpcuN5Asi41 yWJ?i#5SPx3گe(IuG!5Wb־X Bc&CDVp8ep{xn,ܾ$τ`}>>Fzਂ}fgLGi`"ώ%6JC=˚ V:QB ̬1j}'r 01~CUhdD3(|WGA/RYKʁL83TZ SB.$4 Z@)K@ZDpxΟ?ZhwDDD a: ЖqۥLY\$0>}_04TɈ&f+|XV&a+cч`UɈF[^L;(WWPL B}w1Kaئo{<^NA9nbBVȅ v:Xoi&JϏFX/-\kFJWgyr+߼emIs@]QG"Q\*$''H)L8exKn} ȕ6|:C2xϝA{ss^yRP[f p3y¾{uj;yۋ deBoL CR:(!TOO_q0=t@Orm[ӥW].J3߾?'~߬Mn @@ZZ␐H)J#` ZALa׎p$}Zd3_lMҝ}t:vEDD+`0Pkg@c}o{Z 99AoUnN$ȏB yq+ϠtFWYuR3 p68Ah"WFmp* 28v)ꋇATτ^Gn`D|K/N !=J$BDc` `u($4rʥ eede6d0ptq+A'5j5hJmD S9ݕ NGUU5.!nP ^„Sh2ϵ@7>AYn2RJG,{"50L"aI?#1cITf--IJG0ŹTec^G{q8!OlJ̺V{YS%q_ NzFX @s` Iu^ _Bi`Q{T*puu5nJrrrD{m{/&~n\e WWWkW]Çthңҡ@ 1-L3v+%aݟ!3WaїLc$٫?0Z6.u|Iȇ`ns>LA~p!XI-G u+ S69 M\1}},\+txRz@ '$X)=p@\\A(򒱰s7%p|S}7ÛWϟכGU3>z&[vjެ丣a]hZHDDDDDZフ0,u"x?bN#Nc?q}7Lu+L8󀩂 MJG&IV XzI^96.V@6W Yj1abӾDHDD{"H P70 0 =^ UHQ:aD*àב}r"e az^ Xy!N'/àD[^:x!Y22K`wm!i<A0GMoXg"Y'N$ t֛%E"""g%N" ]i\r/OÃSM{W B pK8ԇ$]ߍOwd +J +mprAa׃ ;7J (OڳBթX{My25ݘ[+C{@_poakT{[?A ڼ9TªBL†皐_8+^ @Ww*hf).CUe%VSʶZ2gK|L;],eCwFAO_䲦եk**y6WUDgv$b"Ҿ D =]D_E*ۇ&b7L)ҵH:z>dTvc>waay{s+*%ED{ qQ0d,,`q3EStZ4X),;4%z*R#Z-HԝDnU{Um >W^XO}J8F'侙XX)*09#_nA9y;O t$GclA\an,+L!cy;/&U[9p/G飛Au֒Jf:uU匟d sQp"?MI fEw4vow]4/{bYk81jm,]8~D}}xx/NHwγsf[9ňÈLO=Ⱥ}Y:VOg߰⇗Y:~]}ڹ5ygD& Nlde'*+m3HM0Rv[y$b.H8K?H* J :u-\̢:ckqt6F?F*]O.=jWHQ`mgބyFa9eU 07 / J\PEހN_OgfO R^;B0JFxMcf?@HTҲ3Vg`Ͽƞ|\-Rw]xx3ݻdgᒕ \Hd%z9y[g,qfoѯp{erNÚ=kY?j%DڜRua?Mc T.%hH2Œ}i=cF۸TJokE)syz^bC.;P))Ұ#d䑑JΆVR֘!]XwkrK*I+e-*3rK*n8)Y99 s36ډKRiQ</,L.Ż  C@ }|yf#N^OTZ4GԊzegdN#&#و==L3A;MH1b"s XlX\9؇C3#iz5X9`Rz" $~7Yl=\Xe%=5cM[7n$l'I>gҬ0ڮBq&TNlCѹ@ VM g'!-hʪpqPKSY|"VTVH(fB Y/JJ.i\&5]|MLF,}zSTZԠNBVW;!?0)', .3+5<4'G68>0(mނukR(+(&lCZ6*(..&ֺG--<\k]Dh۪TN?^WWà(3D=i޵ ?%%%\|h4lP1lהR5SGj7ڶP(uip^T@yy9 Uߩfη _K ̬hĶO]V\&s%rx}nʂ]+V- i|?ELX0[~&oodQUz-s̜o EB5U:=R.O) tOMY%z; ]^vDDeq(4kKsbVjĈuT+6gW#y3W6%y8}V&a3y|">U?IuB\*fnquΏkƓ$ pf7?cB 3&6ђ_}˴I(=^E0sr>%Y5([1ig7{7>AtXʪctTUUթc*h roo.QO쮂D^n6|b 9Ν-} :\~\f줲 skWPǤ0MދWhO0xDG+ƽob0JQi/?7\]]qw ~&HTX\Op.& spA:;/ӎ%/zWkvaSӄGfirBϦ/)+rA| o$#zQD/?N13y8!]։NGN<񃮊""%QzOtÈ&7>ԓ[Vonad{."BbvV ӑÄ龄QgO|>ǘ$rU<[)HeO'e0q/SakmTN*nٗ yl+d&9î{Ŋ$5V(,eWQ^el'; $V% n)^k'dm Odש:h2Ctz 1B>Q}q5V7%:&=,5 1Y` #<L{Y9tR٫s EI>ץ$gq=s=='7~Aqʇ=~e %t_՗ݸ".OI33R#H]HTTB^EkJ˄q03ogXylPS6 RRz#>=25z TJm!;[a2,L=Ϯ@rz:n0Rq 3>+5{KIDATVHܧrgڗȋJ&lNҌAi9e?gOַmsDDܾuRrw 1'0[&2=c $?1oYAٸ? .ei8G8C EgCA`mbƪ)AQث̌[r>D'پ/l[>MYiY%+@.2as nm]šijQYOHR/*\?B$-/WgfjTu%k}Vq_}qԸٹ4)F=~y̙Y5Ikq dw9DR̭UT# 6Qߎ~mڮH{=\QЖU`lߘ ^v3}G| c_mů1j\F{("R+ֶn$Jjӷ~ =| k.d&5ȃElBQ=Tl ThD"pb6Zc R ޡbBq|gHR\})*|q+o|r$}&UՈ}.cab ح3egtRs&΄es?Ke2F/|v5G0cmੈH_IsM49w_s/$rD(oMZ\{\k6f8DV9[a4\L'fuE~!̱MG"O;TdjXi>X{  $aLھٵ6*fΎ]<2})onPRqrM>/w.['m>1V"8FfnvY퉈tWjoY72/$4Y_˯wN&9mb^K?qvVc}D߭ NWd嚆qu"Sٌ|f1$k)B]cceα4n'PxۓYDeԴ7O^ynS /t=ߨKܼ6x #z{߻"qq)㈈&ߞ~ɺ)c̒lo{dY: uW ʋ8q6 r4mB"h|Ǔ8^u> LO'+jOZ D| e3á jv_H?:jV字nV2uH{-Ew fr9C8G f7Z^ic#5YN$ȱ$hy  'h") r2ߢ>]cw kra|zer.D^>W{" ŸZ>"""Ʋ(:1/> PQZud-XV[C?C Fxdd3Ǵ}q$9ׯ_΅h>>R5KŦw䢐[p<4l†w&=ʁLe8I 燈_)ՖqϠ۸ijABcm=?R5K-luܼ;#Ǎ[SBlSF! M˟|8[^RX\כOs\RSdދ8)޿ņgakmAlr>k '&Q ϝͻcc(_31m .WH`ʅ|t{by;anjL`N z89ˇ{e-GߥK0[|3gΛ oa~ryqJ`Q)f23b k+(,[΋?uK9ɦo'^t~%uꝹtm"**u/^~Z+X +@*TYv{NoOr,<75o;Caq&s_3 [k 4ye70*n0Sճ8) o?e&wbLp=޽;>WS=+] Ӟ ϡӷLyaa!ŕWuZ{ ^XX4CgL.Gax~R* ]%E8r"4   pR9`mn :FO/Rn-OF{ cP|S$ v da?w΋,M,y0d} dۥUelog}LIhV&hF\7܇;f#98Iw%J:s&R3׍17R_Xyєku08cH+<|GTi(TTjyܶr5lMrF!֖Z[No3c4`(7a܎7mƚ|Ծy9ƨC0dgBvyb) Vs<-3X%H;sc59S\\Ŧk=K۪YK N}|R|(ВU`zukm$ Wvս%'Φ V+*\TXlX yFBsW[^ɈWoJjuiuZb%t6}.S4HRʀ3"Μi4E¶AjdbsQ4@uHl;-  zGl&0;kؼ|,Th:RJ;aƧǿAK&ҪRg_c߄Ҟ}3pvAWƩ3 VMrm+mI-ʠRWEXd&_%@|J>vRb =)E%퓧Rif^u >?XG"6#g['lT)}w^f}}U\C@fff(]Wu71&.")))!-- J}OP7e* E1{K <2 '{!yb)EM'<*`?G,fXYp덽@ ye8ZRQ3.t>$Ec4c :s2hQٰ/hiROksY>:y+{+%%{E\$))ݠ ,, Nǐ!CCEqq1{존zz>}0lXnDNz{5AͿi6vO<À!"1[h5\^^wsg~L}u8j 77ԕP^^^繡騪SrrRQQQkٳg2j(d2 x{{Ѯ]R)vvvΟ*9+yg<8Ά;gφm_sQ^xu$ .[o8y4C d9qZ8{jϼ87˙5ghN'4zʊJ#'ypY?>zwqurl~>^ӡgeϟߡ|jn_2tI۫nd靼*~?\_cwrTUUc^5=h5oVWr38=Vۮ#+[ÝKKKMFXX3f^ṻc(v4z g/2` _p&v6 6llxGi6GNrlO<gW'  ND92x@< 7MbaZi^wF`0K |hl<Lh|<d5ن` Y>LFjr:=<\;Q_]8}{6h\z\.|z=Ͻ$V֖ !5?y<Ͼ}׼)[]QJ+ަu}3f k7:3\T*Ҳsy\7 A̞/jJ4 Vw&LkQ "@VV~[_l33|t"rE& c|A b|SRm;1~cE}B#a̜'P.׳6aB9BϢ_ɉ|K- m퉼zw=0<)![;mpbyc:֕HW¢_[ewwwJJJ8t8::*Mk`0((( 22333<==Q(Lwvb 5233^+'gN @>u<⳵\.'g6m؊^`0MφkhєmڰGNMz4/4 5AAc~ w㙗gDo ,-U89;T 瞇`),4AC42b^Xh//BȈAl?.:[Sӎ\+%d5ߵ}/êUZz%"BݻC3`d=O:+AAAGYYYZ-=R&=% *|؛~ic]|mfm7 =0>CnB*~˗,U}1vQ}PXO|pN=oVg̻fǣA='ĸѩ )H6w״U{!ϟGwHbooJD:B.^`0nЖ\b"ҭQTWo_[uAJ9)J 899ӖJb"ҭQ(Wp*++ٹu.{]ggg[uQI=`nnf""""]77nȨH776)tZuAI=sY[[Bb""""hJ):h{ۻa N$))=EDDDDDDDڙL]g`}FIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/diff2db.png000066400000000000000000000107151360462764600231060ustar00rootroot00000000000000PNG  IHDR2dc[bKGD pHYs  tIME A!iTXtCommentCreated with The GIMPm-IDATx}U}?<ϽwwBDK@@Gb4łmӡtƱ"LXhҩh_F[؂$T@ Hfwls~޻ل$f 3svγZ{5I'P!E rwUS:L=8KTEEdHpM7[ aEjGV,?Z;w=ww lʕ=0V6Ϯט9g=} R,Ű֖ `$)7 q b$>@*sxg@6L-6q;Sz{{(7@#8PS& !=i]# @ Rg*:K]*?,.;#rk5Lp2[d]Dd޽3a!cDoqf2uM7P#5V*{|zsrEP6Mj}}رc#p 5R2ϪUp$h(yW\;wUrSzT~7pU vvzu9:*8 Ғ$t*+>v'kxFb+/ 3 k{v}=~el\vJxL81},enrA=C/dXRcvbpv9t;F(}>Nl3 IIqla ܻhϽwF<cSM0ۏ+8/b473c\n8ĪzBʹJp'&vI Ȳ)g%:4AkDw}'DZq!-﹈]K\UKUAo6@hk"񟟹*sX^2>R 9D -R ";44^"mEٶb&(y.}X +-Z{@n-wqW+zFBd*X^ )kkˑ8'>}Jy_i%U"A0-u'7#ToeԖln' %Lw-b-X _hGўeݗtU%oE-&iVӧ^yq 7֭:ΗC/v]sV_}ŋnΓ)yy?X|s4N~T.n"/[Zg#)qk7+Gݏ?&dzO/ߺO O)_:5]y*RJ-$lrOJ[z:=a@AMz~FMpP Xt?imiiiDIr)rJ)'VIFZ|o{)pjrQHQsA͜9k_3an[ٹ|n&׷Wes"8HRKպ:WU0F( E\HD*F;a֦=nuɷɺ|>rC5AT9eᩕZ-rZ("hu'gNͯ^w%P/G/S51cJ7L)J: j 1^F]#I;1m窪LZY,ܴ& UPϵID͍p*Hu!}:~%Jq_@=H<{H6 Nh; Yx%DMN@6>tuDHJ}d1R2F&YoA\?ϡ6F lF&`fiL*Mb‡:(]9RЉ| N%uKbo y,̙ V@9`.8-yP Z(9*5 V&ZGaZQA!AZ71A0c$fF"2N [Zy9GtVڐFmJEkJPCӗM.5eNC2 i$d֐XEf,p&8"ʵW SLQOz!IM qb?s 5@#ńFkCX(5Ebbb,˰ZKLN!ۏJ":g:@Xx$J~W\Z‡W>k?'o^Gܵ PV:q>Y}۶n{.-UML5)r(,!MҤM3p+[I6JFڔ]9-"{ {81߫?FocSCu)䩯G$Clԭ|ל&oIQk/H2a26NttDÇs2B Wj(U0LMk11q5)&/̱Xh ޫzqP|f SU*%"c_A6#v)`uę8&0"RJ͞rbGNֳOvl߷Y+*~&:UڈdqFW{K-hnm@Vݼ04{ u"vC {P!\0RDjDRnʅI_eW9:Yplĵ\_4TdNӅ]g쌨U *spcu4W$mG$74Wݎ=R9ͤLj$4Jb;˖Ȏe:,J- H8 dgvo߾mm ;v 4 ƘOc“k/,c;9˒JHrs_gO Ȏ;5W-i 7^ I249۶mMu35{ܱ҆8B(g:cU189[(2'<fh5@|_c  l6QJD)Vkߒu٬nog^"P~ t8Pw ᫟| Fsd?mlÕQJb9MWcZ_&Q_{4RJRu(AeWW (0yB/ SVT#!vqd'6Va.ǎ#LNm$ R<_mYϷmROȢ<[d۰z5سo߾m߾۶m{.WA,߿ЅЩE87sb' x.)6羄}ca^,~yX5 Ȧ<7ѾHvRQ>UwbͰDV2871!Ĕ$,7ݤvL1gjWZ$R2vcP~PeȣdY10Ӕfyq&f ? g>󙑇z={ZZZjUbʗ %%Rۏ=Jf]Zj-4B)S!S2ַu{$n.too7.šٺukM,t r05KqU蹂:Vr*ꕌG]r[5V1% U|$+핼kk]NeU{'|ݮY5e#D-sr\91>Y FyKx:òD SR].<; " ]#I,j^=<9wiBQԢZH#\tϣc>||H8vJM(5őz{G)oa4  &bIV$K5!33"vgv&6JcfܺIy,؉DRRggo)k|mdiȞnDSDrIkZG-2!D}IdN@:3I}v[-0Zŋx!_޽{Rj1F^% H|#5kQjHR2b7{vN'Yƈ>HK6c>;}NzzzxTNoٮtTqߚSHY#||iI^={8grЋ/cǎɝ)cyb1 qāq}sZh_Jc*>>3År^ ֍*Ҡ #0F[.?j3,Q `k4dP {M`-3H:I/ɛ#C$ex8ڜq,i\<9Mr7w˭߼q _c4h$8P=tiա^?y.=UbGv,]0i|mK‰MHAXkIϑH*%- >=PDʳjjfJUJQ2Aw:7RMmR"3^V~KULENF*ӓ-cpb!@AKNɒY>mcZ^('{ZL]sQQ_d6x %, HLJ"J)Q)Ov*%Qm ॽ7l0hIeY(²,#X*S]*;f ;Mc?`V罋x87͛7ߓL&?P1F21F d!#ʌL6gRS yv=֘^)I. թAso3盇¤lٲ{RFЇ ~aI]  C&7 ΍ K<>2rvHy}?C)8 )?00f&[T[=5 }/)Hm1OL1IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/model2datadict.png000066400000000000000000000072041360462764600244650ustar00rootroot00000000000000PNG  IHDR2dc[bKGD pHYs  tIME 2T!iTXtCommentCreated with The GIMPm IDATx\mlu=y..iR##dNŮPIMA- HQp~ AcXGQ@&MP9lǐ#ѪuŲd)\jfggg7YR򒜥Bv8;λ{vl@RHOJR=cJ!}Mpnx\jw`jdzz!.ر}@&)jXMT5]65zuRy\H<=8~؀Hj98$5|h4$lex@>ڤ"p$vS"v NڼnBlx諭@ s)e_ABiQk35 }[[s/lix'/R^xt[,5nq k='Nxz5KCH.a[IE$`4xJ_̖ص9aή!ܶn+iQ,^g(Hv7[Dw Fr?z`Wo.EmJc@ʷ{V/ ]Jp؊Eq]lD.[lqH" zOSVKZzW^,Pʛ=-ϟ*<9:;BP!BP)$s166zzGW|:s}RfHUTjή8 CUl^wvCGy 8RK}a|=M.cfѪLg𢡊܂<"b@P^:kj!wDj5!J)^ R p!ǿտ㻏]_WPb"[\\,MLLH)%!BH؅3W .w6\F[:(nE:u~:p5V ?xsG dfdq@H@w#0E #yd"ǺpWF lv(('X' Uͧ+B22NƇsBK_T@D@XQHt}H) ,6 }:t}T-1D•ڼ B (ac n)o_=J]@|8(@" @b_iOo'G~uwҾy8wD'?22.uB@śEٽB941 \ob+l/~'̉yˁ@?Иͼ]w~%]h*4A)#`e ^|܋߶>]^{ fξO}i 4M`P1y?xl؏pU> ww_@74z aog/A%6/~_=.l"g0XEO,ތ7Whx IkrGg}Ŗz詧cƽPJrq^B}p}xs9{[{޲0ڟ !.uo[H)s=w~ỏ9ra]@<499b\kPzw?H]Ts!L0cǎmpfJO8fjsa`` Pc D"2A۶N;AjJ"׺ M099l6,7 s4+j0??RA)@RJTUd2$྾Zbxx8b]˲;w\aش!1 bhh(,4ߩG6a}=u#Hƒ6: R OXԯyCݎXBRT$j5ieYT*mXì2("O)EVC.dB`aa\d2yX\\DXiZ]MHu="QyT*AӴL&?)tk-4#H$`&RT@)2L۶N#>nB^5b*j)Z ȅ jk}G\^Y\E;# b'b-u)d2f+:%BdYHf}|d2{B!%f*SY|ZSU= Sk~~>G2< (ZKKKR9IQkRư-JM>22;3#iP(.$JyD8p~DE(yP0RFjpr]7j{t[ssfJ4MPJq*, ]VZ$˲`&DL&Gy$Viw.¹AYytRB8D4d܍o)Ya --;v R)X'Lݓ&.]jƆ\pm۶vY0mvVtX,bu˲.k,Ouյ{N*Ϊ?8At޽{LO/OR>ݻb6ۭ: IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/model2png.png000066400000000000000000000073041360462764600234750ustar00rootroot00000000000000PNG  IHDR2dc[bKGD pHYs  tIME83I"!iTXtCommentCreated with The GIMPm$IDATx\{\ysه1ؼH01FmBj7"ҨTƶԒ* D7R" IJC$ 6lp6x^{fg}}c{gv흝G:{s9s}+JTR_9ٲe]7`+joRaCR"Jj6nڸᱦٲe ޺tG-L38w 7no:̋n^|`j&CޝzNa{xyXl)P2`g2RDCwA@"0'@4kh & e$#a▥03ґ(Kk*[??m_ IMgDk@hgs$> "j樯9 )%03Z[ B4!e ͪ@y&Chq 83k0i"Bk驧60 cƍ_n)%^{5R),Yxwu7l]v=yOmܸqoS_!FGGq@Hk<&X.)UBOt);Nn^9.-J^QAZ)]?zI O̙3a=si B!_mK`F y~ժJggVa{LeØU@ s1Zm\* X,&3M#aWy'O?o֊:Y6*rHI?|_j;f)D$ "Zŋkl%lڴ Gjn[욣Y͛0s4VG"7\e)rSlذaߊ>KoNWL7{tQPgj4,"ҌsQV"fU`["ubQ %yvxR\+kJrV {ǿ_]tz (>ZCC B>9^5~I4I-/ G? [8%uv'P0H!5L[0$)0Űs #^]@`=v|UnHPp < a4 m믽0]{ +?G>.8L[ Ӓ0l $wοs>bهC]{佫~gPpm ӖJ`\qK~w}}$=YXxAbV["au+J2s=PJׯm֭ZCk-$"S),S{߿c= i2ߨ7'יw-TAD4%m۶qK/=8!mB )LeX8߄m(>Nwqpa4 ÄװT{+Eߑ9Y&ɛCܴt>z7@ EX0q;G&rJF xRaU9aiL =\wUzn){cQ w!\ I(˂D 1f !lˀ@L3R$ s X";>@W:-`h̨bk*!Փ e\m}4` ^@mв"dTI=savHX1.D MK^*†H#fy~d. ^a@)UL211CZ0Ɂ!*RI\΍0+uBaNimQkQnq` ; + q,ԗOvO;zf/ #P~Ξ3e@`41;aSeQȍUR*sP,B*=TgU= Zknari*f%;i'L+ z,Afd8q$RwU,0u)od&P(l}N@1#Bu E(8L `i%d^Ttxfg&xz/77M@#]aH\U@޻Jfvk8vnq0\T}`Sm3ǵ†քT6R r9q1ăuǵ ޔw & C) 8Â?{hG]qlv'\J)xW@?ɿIi }뛏Okqуfas?rhܬBiN0C€s{{[&LDBc\ z=e;Ž+>"aNo~;b ĹAG;N㿽*PmLc Qta`r?|;StPP^Ѹ+J_0D!KIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/model2sgdb.png000066400000000000000000000102711360462764600236250ustar00rootroot00000000000000PNG  IHDR2dc[bKGD pHYs  tIME9'J$>!iTXtCommentCreated with The GIMPmIDATxy\Wu,M%k,[b[v` l-cT R ") E6#! I1T-˒X`mFHi4{OnMK,S[uH=nkѼ״UɨV*ҌJu~JU:5|fQ96Tc{w-cL|H36+7b3x4#sZ5ts\XU5g b M1Ϙ"6c Q!"w}=96lpvתTFTG L0#^pA7Ǧe׮]wlܸsZD˹H? AS9%..yͺwދJ^OAm1;o)EXTppJRΘTLwA $bdyd:d}t^H"A\/tzZk sBũT-2@=ndMiqN % 4nXl6;E)PͿMygd22WBwro >3s s.{7TҲtڵkëZdӦMƍ>CgfjwJ:: fsYO=gLXCs+9guE8[K4"s ]#DRmO^w#" dcZ= IyYc@h";Yd5{ǣΧ\v5w@D0{mmmn{V2+amȖIlĖ] \Jimm=;ĔMul޼ iZψh"LĶHl+ҞK8 _Hk>." hAͦMmEذaÇO۔'G;kurF \<ꦭδ:m3+(f}ۧ2udWzfUO!"E3OW'T&!֏yEQ+Z!zW,106}qȫpުW/P DYÇ bLɳ}Vyf@n|p0'.ɟKNƒEǪn%o<][Gw~GwlmY?s_roY7"t 4.nݹsew7kCΖ/moxQ9RCQ¬!@0hfel7{=^5=7ex3'ڿ|-% sL. 7dZ |@]p_}gڏC/0kBAL6y}ǟ/Zt5j퟇K(v/oÏ]O: LVb/_2awO'o>3E0SoaknXyۆOCҒh$x_ߝ8DEg 1ψ #>$￧o4"C.c4,֯nW-J^Nk_΢%Wڋ\;Kt7#Y[r!Y5QvqdZUhɋ]Rƪ }歹O\9 4ۛ)<%$h\бU.>No Z,};nl6BVZ4T4߅|N|kD$&hG3^ ^g e&ZfȊ[poP|] %+i@M}c\t,R" Aj6 i#1"4*jsDge ikUv(q"-.Q}2eNBR I)[FH"ކp:8vT u zZ{#I QlɽY !k))t,2ia2:/B6ab$ib{\$8|z+_\_loooB0k FKN)j"<{9WiN8wbauDUUls7nyf{ݲod,]񪬯H QpiL$qM hRh2ň2rޣ-jiM_fd ޓdatj]Y,"xrt"d@⫘d;xARDF?+>ӄwb/bn+aլVԽ+:{iDn} u'Q)xJtٖo}+fT1N ^}Rc*2}UPh1~SDzNJ#@W^)c3P|XpM\I@UDC_S, 8kc$Ԟ~Kk=w[ʵ+|J)vtzʱ)ُCǻںSAjъJSmԧx-ɗu,w]Š-D޲. bp*cxh@N)&Gʪj[R2j#pW쓀,qki#J&rR-%LS&.{Oy˃g{Щ"s{hbb⁡RkQ?oM[-1CbGqB"WB(ʖ%=#K:vfC'J3<ӣW<ԞY| QB bqd+?z/~]mk_u\Fwќ*bDL`YD)lW^ʩ#a^>dZ"9cPbǧf%=2DIO˵ ]W䌨U <<\D\UJ)F(~ˈA'huVV` p!ZWC`$wWp#WM&58%tl+RIxBiÏ ~$zm@:@kylp/wrٌ6.x2>Pg3F+&L%1a"ad|il7Gu,u6oC$rxm6^3FWqIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/model2sql.png000066400000000000000000000100741360462764600235060ustar00rootroot00000000000000PNG  IHDR2dc[bKGD pHYs  tIME62a:!iTXtCommentCreated with The GIMPmIDATxy]}?MztժU#FpD!./S2@?H08:r*kksFGn_j*e;wu5"= :;8ri+V,?%"23/_#+ ް7_{ b@4?8 ,G0ܲi-L kFHXZU gbelHŁV̞Ҁ<#U.$R@fO8Kll8c,`ͦI~yZ;J*#lc>@DDdDA(pb#&ZRH ci%zh?vF1޽D"1h0ݍ1xÁ8X⅊Z/SSS)S …W p`|Xr+VT󫔢MH^? 7c)'O6e˖90hG1]G@`jO = fL23! SYe/l2MH8#602P= u#nfRjH ˘}sPz;FHEk ]F'Tvl6.tHsNU,S caq}{ス>_a,;Hy_cǎ3ƌ1Ƹͱjkc"1666Ćhu@ۡ˗Ur[+W\""D,_l妰N\6H+h0fd LaQ1T T2h)MHt䬔hed4}Duc#2"D_&g]a(cNDUCZk|~\ b6}$3C*Zkikk8ydƊٺȚ, I6H1)2Ad'L`vI_|ŕƘsEDRo0(USC,硇Qy/<=VJI}/477k׮{_Sn~;2]4Ţ=߿c10|W {} \Z#e! D}b$98T K?hTBЇE &r}Yŀ,z P^2VV,(!+i2& .A-8vྏȎ}w_?oN Q\|#k=V#]In#w(mp}h8:L[s&,RϽc5JlzMs]TCi{1/|4/\>u)/>èUR&C;\ͻ+\_+8uUaք+eǛGirc-9}wk 'lزmδEl|xx)^u m]S^I+^3kZ;'yi'sxcl@o\f qGk8}wc Ƙb;h1-Z6|+2=X^{mW :MYsusڵdWWWQJ#p 4gίcyd0Ržޭ,sG9++Aل)|fhy'8~kάQڊ=S G/ȈnnlW.M/[HeZk\+P˼y??9T6E)EG3"3\\.GA9\1o/Wmu]<<|s𽅂 ˳P(^bv P/ ~N:@SL88}ShQ!> }xQB [h jŭ\YZQV[RJsβ6exV,hVGcluL-^%Eu#8eg_}SY1ъr#O @:[o@@- ,ZCli<>ֲ"B9a#z_]g-RїαkŅ7%.}^RUFh\& #sU1`%;L/XPLZ[[%G̈́4w~ 16셟l;Ě 2B(z2X A J+#"„ hnn&JyZoyPaHԏb1$Z|G+hO(Z-3/8@&*]X\-]fs'yze".DBL2a$!3q²"3>'^C(ueatՖi=HPFf̘q,y“9@ 75pX$ހILܺt Y8ڥPMMMEFf0aŒHGQv/NKoyOfBlOaVO -;`[ؾml*Ν[ +&ZQ R8J.߁/#Uᯮ0J?=/&|屯 S/;fKӮWc 6w C,v(v80qzT;۷+E/owpM]@B1ћ5ihAP"a1.(I#߇.jbz֟*V!ACôVѝ$`D,.U(ޛ5lRq%pEdN2%|PZQgV$o%(wi=z(\ƙ p}:ґ?T*ł #joo/FE|>w?CR{iS\0ux5U*{?I;Ʀ?m!p0ִiӨ"J3fLYpYLO/YL`sO5]U&.ۮs푙=ސJV&9MGbVZf+l5\F&k 8N3dҨ>;ukWa␀AP6/-ᄥaűܹ1TK9-XErJ Ϩ éhTLJ_1*'jk ;RӈJ ͂(ǩ~tN X3ewE v\R$@B\`p՛spƷ-ɏ{O4y}iMq}M@=%ם ו@C{{W g{9-??SYH^)[)vNt*z`Drb&"477R] q=߾4J$onmd_Ju\9*:N~˳pReHW安 E)Pn]rb1f [٭O-O \r9x"ywKCyݐJ9GSEd hB$2QRt_.jk;A:>e`(Q〱-qѡuLLJgiʸsHT7k\r(-(g(_oO!MO/]D"qKɈ;"_9#" EЅtJ)#}'I}77?ZkIg ]=I:?Ż;d˞cOm~ dȲexgV [g<( ikqȐ&eFsT%OWWoNQG1Z !/Ds sb]Gt}a/@(}b'3qIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/pgmodeler_docs_logo.png000066400000000000000000000421231360462764600256120ustar00rootroot00000000000000PNG  IHDR}}l%bKGD pHYs  tIME 8 :iTXtCommentCreated with GIMPd.e IDATxwdGu{ow6)e""HL1^6^ce0L20` 3" PqWզVUn$ lOO{sw>M |ۉR࿗?d ݒNًv`qol"d/|Ǘ_k+pjna,,,.V|Lߵvo_}OsLMM׽ 4.P8v }|r/_k6|=i)%+Gh6rP"B JHM` `zZ(P}can$IsSCzh=(JE[}$fs8 `BOҌo0AԀY|$yUB$NdN$ I 竄iH5(w|(奯 DW*f[.irGЇ= 5hJ]"Pj1 Zk]j6ܳ7cISܹ]uB.rLCFF/hc߅bvj!~FMznwBvÈAi 4=|@ ]b~}=S^wr%?H)2 5ڸ /|P&)p :+-v)]ֈ~a- f']}%uwpϭ7P ?IQiiej߻Nl)JP`=: O|"JR#xUJ3_$ٸ;*-FRI2hS[!k'`m4u10h#c2 ;'\".ƀX;AD#k/0S&aHjD^ĊkRh(F.0^~]խ5'-[r:y>HCY󰽘M`]j6⭀1b{UM [ F^ʬ!m sUg텟AmQIMIA˕vBa>Ss-o{7^EƫeQ&?HJHgDoϏ*+A0&BwÉ|a~Ï`>Im2G!c(fqa2\4KPIJ!o,vn0;wiudiJ`<@$Ik%[nwuHG:4לHG@LoZs^lS:nS%G.F0&AUs>ʖ[IT̩8-.z=Ҽɩ~u$N|baaj6h#Uh6Y3'Q)Wlg[lf=_2u i"YӽԂ6pV.b/)jt#h,=؈EOv_`wnwg7rIwvnqLLmʟ%8N8D(KmM.:bsHЋ`W~ogM.*rtYr7N;G [ Yѽpaңy,5,̹6QV)1P4L6b?p?p2RLm}>/:50;;sgҥ&4[w0z..=d9x? ɳ I׾bw~'[j3}Zis,K_pqAgޕF+C .=v]{P,Y?:)LO;s;7K=MLȯ}Xf$i oPg<8F$ L挏+ v'܆[&mf|Y^݃č^ŧfA+wqT`CBP蠸̽;0",ϑ)'XNT/|%x-\K.l&ϛ^FEn&iO'Qe TK*S!q>yP =bin{L 33|쓟bU.z=lc D[y}6 DT韪 U ˆa~nɕr pu|n#%k\yUs-ehxf$Q0mwYLȹ?8kûBی!i#.-a,HR *mu$9VSWe5w#a+4e-M8/0=5^ suϻnn"5mqyx* 7nkT~ئ^H^+j7 SDՂ`E Rwx/7:55\͛/(W٤ӵ~3ʡPl<*9,.|مp݁Ju} ,H=0"!hDUy =nGF.o9XkfŊ7+b_ˈP}:C8|3JBxla.N8]s^i`~/x[l 66Q2bál?'yE7_{VXf4MA13V s0J4;\ٿc|rEr#e`uŲAI7_}l"^[$*3qY/ C\Չxq< |gn]xraxxy$ LR$rf 02}]C3[w'RK bM䊕yQ,.(ё 6k&2^ B;E*kтʷ[W1 Yg͜D6@ EQEuhz񎩦,WF)%z̮ʃvhd6Kژ.<_6>zl1)`ǒ-e~C]gd4q[g"yCTG༙7W&:05EGvQ;1_ w8cTT)pYnjq 2c0xWYCTkD\4X|@g% uxqf7.)!ʵq]f6j._Y)櫫چ/d %5^Bi6>֣ʪ]Ѥ_j1|f(3NQ6"|q̙J3Ct\R&*DVT?aٶ+ 5k}:~WLqE3Ou-h-ۘSvKto^[ȨO7[G4 .CU B0`}xlEX豙VqWd.u.b2W?PxB@ Q`IT ’}`A`fCL\. qq:f$IwWJabwʼ FJAN(N&2ƨ(Ы|x .m>Z/| s,(>PrUg"!M", ? E3lkyq`XufUbۚ@;mO|zѣJi݅QD ,Q0'?7܁jw ]]|㏥rH A  T uQhTAH ˯ٱy,n/ާ7W_4 Zš⠐ts-У&C#QH(r7F .hb&NBʞ!q-9Εx!IP3*6.[.rɧװ^PRQ>uxƧjΌ) E6{ߧG>b/ZիIvxMUB6F`8ӎ ~y۽J4`I,9!Z&Iϣ۝~M|^v;M*e&P 8w="i?1>B'>$UqED jdcj5FDkJcH:mYP .Sqx+Sh6ЃfU&muPI¶2W;AUtzh8r@NjH!&\Q7x (a{CZ|?Fj776l@E* $j2sքJ^ջX{zӞ^\1xQ&0YQ:ce%6K!,i i8yE]mMPSV'`c®610.MXB蒑SNs|q+!/j$-éĞ)SO|_~) Nx ѼO O=23lX{pyiH0aqNRy6D:&HP(#(4 CbD JM"B_/vc֦V't67|ءSOC7ΏϢKUN/ E24@697R#Kkgr܉'$I=@yx?Nz׫iv(rU򕏼Fb ]5m.Gk <) LG2"*J2U(P Ϣ3頜wJ5 Pl(i&n)O}g}?1V]L aYE&fE⼳IJW9pGպdCj~J+&,مx7\ٟx/y]Nb0jF;xXN1@IKi Hj9+RYҔGe 3Ox.׭ LX_: &TWZS\0h91 }u sAKaQ+ Î$7\ <!Si?sQ3!ET1_#y +^{Tc(JgBlV@01zVmBE)1W(g}crı;S'M8@Tt1f-xu9ēg1zo#TNRAjxg흮UsMk4$o?٩_)x_ūA"@8M>USj42Ι(W>Cwԉ 4czA$o3$MY$&VOƬlïFJ98]-(Re$L)Pe{Xʻ dgS Qؕ$,y1s3DXm|o&o6]1%*DDdHW{UKvV%5$) &JFojzԎ |3[6ӟCƖ$ w8h1e6u"Զq@ K\qOAuUN+$nҼJZ _GHҌeKWUu $AfDŽvћxBըPʛ 8 M^OEz cn/2g <`'50b$![## 0Ox fq! u8Bt ͫ!{<}[7Siq 3ѱ]?7 tT䏘Z&xQM$*RܵH))~A/3 ͻRۚTO .lƑX3[Bcȟ LcodyΕ9/SJjChpg?q> Eg/y-33 s͚IC+[KRij-*wOZRp#.5)v$JR"~@ yT'Iʅ(yzfl޲yn]m+1YNta/6[-~}xNxqIѥ=^{/W]3,C>U=׫ j0> Eayh&C-,?$ vk3IRJꃎ*mvi ̽ ( Gҏޝ~F[!:sÕpԻnwWʋJwa(Ɩ=<ֆ,;,%M3D<_Kչr]8q>ʼ"uP22^IR"!GDݳEYaajd'yw@)W&/VʽM䖵Ggg] yw$d$o6O߮N-f զ{ȑ6q H Hn WD=P4pqRۺx*Pk#J`B^(6PՁdM"wߓ TؕdIfѰAPɃG==G9rY(H"j[7;K߽f5seӡ13Mh}>ral}Y%o$k6*426v]?ƙhE>_vΔw̽ ^.ٝJw~A$l4_=MQI2;у g٪(L 3wR+^=|2 ;^xA>P-Yr!{!qj$iBI1ss"E>^Q Z{$,uU~4i3G7=7C[41ǁ!Tʋ'KͿ!OMXLzWg Y#ճ~r4 h ifpV?(?+U>rO5ݖE(:cN9a>_az}LQ%wlۦΏe$yJ3M:4Lc X\tEt1p]KW`6m8Qo7|'7EC{<ܠje6B~Og?Lx -|o/n7:*0[\32nrTma\m _R]=wo]lܺ%;FcF!PyMHSq۳ݬ5BEm:ѥ5]kE-tA0{Ba\~?EaAH!zRs!GXsϓ(Ҭ_ Pz Ӝ6m:0`ͼ/7hZ,Y|B?B5Ob#.)hiV娼I!IC׏ҷZ,hu?w^vF@;9Gvc>cBB*.PUje$6CO}.!G|ig~5W֩Z3ijÝLZSO( ];|ncb~nh8_^!_6^Zpuju;[yJy2\+{.tmwۀT7wo& Z#=ĭȪhʏ=azz'?O3,Y_wt$oh4|@_ =jmT8^ @RZ%${\}U͈Z*# ZQ*n**؎ºYC@yi|/eqn+ҨfKV("7_;6mDc-lg#ׯOMoz)\yEƻ_yP[[$ق4@L,xg|]kjKyFO G>,z͛Q$#Z.;e2 ch?,|8@0u3~KyA[jԽ5翚/hn8opgryS(YQlIh-z/?ڼ$YM"2Re,~5S;{.t%egsrU_xƩ ꘚ{oT(3UD:)S8QmXOW 3^ⷿ p2H9_[9Oq~ M}y[>?ZvECC6?~ }Oy,oKI6b?[\ih>,[Aj%{Q,{ܻKzv-9jz=shάP3K._X+A5IfŬKW^M&†HI<3!IH +NW(hu8'>$ɪ(JM*,#iprAIv1m4)viO>CƎ Sw蓯$ $EelhĦA ?E- YIjIHG.迯;ssRhݻ5VXc`Nw(5{QSx0-U72n siC:r  )!kvh8z } M[a?gձ'{Ra꽹&9G#Iʚ/BKW/)Yz5$iF:4B::F&sFcy;?t Pl|]3^vRխ#Tg*uR|nu?-9RmtqhO}>/Eg1h j <@1w?H 8(#qqV$@)I3l4:TSagOD%Wk籃ꊮ~Ү^ ,˶'hID Z $©BIJpZm}My!':[R!$XJ24 yr5Q-]Ed*MVa=y \W\''حfY ~ODX0ZZ1`Hyu/' 14)Άw <ڞ[^Zzn}!{7(;rLw~>R:A<(cHGHǗ-YJ2:y{1hoʨ^\W7&-Ojg{}w`Sy ~VkOnEN_!~ kU"b̏چvɟ?2]͇SG ȈZ(r_78\P'jCKH'/A;Mٞ3%b +-._=k#k'. YY孴iRQ.}u?)u ~}6G7Үi ufI3>~8+"ukM}Tk-XwǍVaK@CXt%$ã%m!PG]XG+BN=A-_5l*boB, h],h]M_b F5TF3dmU)MlyE?$Km34ZTGYgm)551GIV.]F2:[HF(mbݯcػ"MN*|ݯk1K{VJLR9 S]d_t-KVkã\VyU@B@a?غ>FB(Wãɸxdbmvș"TPe*'waloU*}uI(ڒ?ݶNQqt%)[6reɕQOmv]0*˹rLngFGdAYe'4[5<'z߁jjI')E_w)u?؎i``¶/Tsz~e?v#$F?z]j hmnVnRK@> Tt'I.'[dd7i~]и*CX)k~ ](ty K0xbvۃ/OznVYk+mI4Ma~nƱi,F0';$dhtb)ْe6hk4S L޾Е.ɔȝ&Ivj:]Eus?߼>!牢/a`/N\'N{d" Rޯ#C2:xed`} {]ZP.Y9@HCd6O'T#CTDU˲"Zv̻T8Mdl/55:[DM+M:_{qZ!jO ]ܽ>9h2뿇dbm$J؆IܾD J ȨpN:2~}ݥ U"W9P!/) Rk?" V&D#Fko"8 E&&1%4,#_B64BQmK&fh0ЫqH ת(jts9ZIӋh释K!;YKY 7OSt&hFUm;W[\"IRJG?챨E04>!kdb},$&͛n4aí (đZzsdqގ ]lcUD~NG]pېpH}Y&lx' m̪Qr'iXβVpjMmQifPɞrڤM޴^Dn ݒM7cqݧ[|h G.Q;(sݢݶ$e6$ S/MwNRE.4ۖӶd)et&뷼O\jsͫW} 8{1_ ^r#N78E٥4:*GvH_7AdO-[,/2ذXz@<~)ݬ]SL췚(H$ԩ7~X=DlL-_1A Yژ9rXb'nˏ=onKQ@ml'47aS<_$;X_M7^'>1E47Gً+WֻodfzK^ogik2 sq R[aT1nM5ZWUU:n/s̛̼g.ӯYo~0@K"y( ~^+?2ĦSX^}W!n7&ĥKbӛ=[$FFF[&F꠶R6 Ze krp$E`;{Z BmdPUd03#OQa04orE?b!E#ňVdFف>C:&9?)HbK; L2zuvgmft ]cZgqvvEEݵ278?Xˌ%$Ql[m4d.DAB_a'Y]Etqq$QNc!uy3@/Skɞ]ΕV.21W<;n; Z&] ;]E;LQ"TOK7O5X`4Kl7䠕 .ZL=$1wFӎ72.><pqև0ހosVr/zʸ_14㉂UM-fHŖ>|n2C(5*I$MSۛ.\(_W&_A{|NّFySTpgZn-'}^Bwv1fpJV9i6s,s&^֕AWF^=Nh[W[*?P#LoQãys>!/IDATf1\B\qOh;Nm}*KE>4DhVEHI}gE5TJM~ }}fȳ_w97]BD%dYRtQ'GiM{lV3q+?-W{zH6JۜYVμy>M8(_-ĭr&k4ƬIip Mm /_NjV4MmSeڍ!XtIp?;ׁ,tMF5,zaL+Dz~jPBRpС}jr0$ͥ+^$o,l(+V?Z^||i4u%Zw8_TI22kouRheO9Fn{ӆQKh-[Jgb5L:O)K̹ [vCbS8c }ͻr#n; IFld/*Ac0sv +A򩼉j8a;?Qm6mw`ޤli`hxh$MJ nP6x.4Hv)40z$t|b'27$aAmVFeHۣljgffh9"еJY`4VnazvkEY 3JIM;-kQX1n7^pӶ;[Zp? }-lѰ_*iG\ϻ[uF& I:jrӆQN0VU wUK*5KS{\%kNȶ\[4p">/?2[j{ Zlr };f8 ~\lnnf3jSU컯wƜOF&VB/,MkaGScmo1NPփK"9[h IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/pgmodeler_logo.png000066400000000000000000001472451360462764600246150ustar00rootroot00000000000000PNG  IHDRZ=bKGD pHYs  tIME 9kiTXtCommentCreated with GIMPd.e IDATx{gU<.{s BbWJAlB Ek" {AD[RE,XZ\p@HB^k3ϻIso'kϜs1|8qǙ3rz;sINǙz&|||LǏ} /כٙso,[-/ijPgcO^SlO|}m>;'릚tx[֧_|:[[[ֆ|̦ٽLBvUQš~z/|W4fZgc O {C_Vŋ@zUW})U `Ug2=}||mى-}Z;cGc\O90#u]+yD;Çq~x%U-}'Х\|K'zƭH`_{݋{4V ?XάQ_ VG r@v"TVSm$@Y<^ںyR^X)"[ڟuO܂^ 0tfέ `H_3|!Zphg9A˝lԛ]k/RzQIx,<(p)?RMa`bu< -LNRĎ dpD`t!WARuX,1K8|=wF p@Gw~dSWE}wv}40͠(wjj!* e4J*B#[|W'i_(D$2nf\Rÿ|M y ZrXQ5SCy[^^r _"VK̴fP?T\JcZ?\X5~ l8\j&Oqj}_7peB 鰾:t^ 7Yv&R/UϊAljAUQT w6%Ago/5 O 8DKb-HZۮ)5[yX`ZA%"ny~-0Ԁ!#0۳V#S@k/l'|s0}fZtJ5дTRh}=Ь -?%L /8*#Qo& @71lt>7CPfp]8P*GM(%׀^ZejjAl5CK0Ev-t'hW2J0V2k< e}?9#GZp^kl OnԲqկ柡ZYt8(jPY#hmgR2)k֛kᦗDC큿X3ä࣯MS7`t{GXE\jqJeXtZ\Ϡ"1ZjqT=(jݟj6pqA~}&3x HaMꨕEXOqğ)7yt&#l[(m6O{}o]9bZƢd=Vecb36poL&d?iTUut=7GsN8?\Z ڕ$]#Di8C&"xM]Z$rNWɉrPkQS7*KY_[Z@A~m[H>FcELF7tO{+ї\RqV\>(hf\Qky[9Z/y؉IA%QtZQl~Z5=Wt%3/ʏuZu K0F^GՊGﳬu)ń ^^ؠ mve?4[=4~vÒv)?v@?WA+L=X%P9_T-tbWK1t½2j]257>n|UJH. r*9 l# &s}6u!X|jwm,|ο 5 D-3)I=:HSFe;-+wZ,Z?U*{4{e{9е\r\t-{<  k{x=|9oL浞.pa`*- c,ĽOvB4ihvݳ(Q>okI%:ê?~;~?B8wlX;j,5l#<ǡCSL1#DįTXMhvf^v0ݏ{t7#Jԇ.ףdMT F7[tR3r 0'Pi1'Yg һzj{tj/ӆԌՅT@Ir xGPGhN`f; @pK vc~co?l{"5K .vt;QkmxVbIic>pȯ.]ہo`א@F l"n:X *$ iM⯕GHanaD\هah臭3IO\j%`Ac,p0Cİ{?V+y30=a@7)ՆAMh¡wې3ݝyǀTங{`G+>eN{7R'82۱2| _yifY1qJDFـ~Z0p;B\ yX_(_߃u*6<~ ~+.|~q?N;In2)hsT#VR@Ԓ&mwFiPtd>_[oDG?ZՀ`U4\_Q̂7-5v/Xfg2j/V,l%n~Mo$J3,G¥V|X-Wػl\ve^/%}YOCWW+V}EIf%!Wi9 0NaLN ?y+n#pΡmd2AMc@9%[Aaͯ + a:ň Gi2(-+I*q^^L}̂Qo&fFȫ,k|7*c0 Kt[!? <%6k)0R{/382o '-&r-s0<)OcfksL&SȤß x8|םλ0z9'YO*xRx<,p ^`{pۛ^sh°ZAmt0&1Qu纷e<(kǜ|Nl9 t&O^^2モڟI9o9 e=n,"y4,u=]/#Plm/`=rVJ<:4^Νر;ǫKP/ʹ̰Z,_4<ˮ,LIn2ëNL>p5ۛ @%0eQàZ45Hc.tSŐ~.itA\7%BL񑷾naj1"I>Q<Ԓ&?pa@ :m. 6w [ {-/8&ΔGP*R,W[]2w:z ~/c7|}eLGkz,hu3_w G!LLGx/s~ey@- hc|sSiq~z]DS͛D r&5JL4vAi7|5tb 4,a,RU\B!`W$Ͳt7: ? E#IGk.8 =C!]5WYHHdX! +Ki|+x<鋮~5\.X,"W95֬Lׅ'h]nAbH0t,@@Uٙ3;~ΦTV-yUŃ\~7ps0 Ce@'K]4:(4Pw^ZRR_a~?v(s5tpI.zV~v2 "}/6_፿۸?lm n[p):F8FZ+_ϻ}cXNB#$oOK.;+E [[[tN&tN򀴖XRɉZ Ԝ'gDI~Zw BD& 1VNϽ7_l^opkZpn]'@{o\,Jf.9c!u?x5>뱶Q3!vAڝ楡ڏ9ke800LPPwMG{8N3s{!3&7ttWDC{^T(A$Q* WRr3_K9Y3vV}Y/nG[גV'uXt"<Ǟakk\Gb|A;M =__$|ճit]GF-]6#mB3H噌~z?HTBfx+`_hbɺ&w܁?gѭ@[#F$V;EbDh<# -=W;*`XTZTV{I{~YHڃCfxQ"~ p3Õ~.|F埿W۱yN|},ߔGaZam6d2t:E']Rd啱dޮ&JrSg|N x3H7 J;'Ajp&ϮtEyXA5RCk2`b* vPO2{N^m#N|z6D\5v_UnaT4 ;qĕ_|~#nx&>0[AJQw͚w܁Wx3;kΦqAc1*cP~mW# nۯ҅εf4O+6rUq{'jlX P1((Iz:'#1Ҫ;uՄ*lTMcY1制"T,Ƈ[8 /a|{;pvf $M={xի^nǎX.WX = ᦒlr;uhWQ5UUgȥ僲VVo}[ bs $n5b?ϰE垐KȄǨNrUKl$g0q" }[%R2:N}km dEټ@YGRÍ k =yhØTm0_pEҊ*ӓ Nxӛބ#ǎر6V%~0E[@CQS @+אrJ=V/9&r@T`/]Ƿ? ՇJj*|ѡC:FRan)ǔun*f<)?]ϪA*ZBtZ# y'@+||cS?v 47H5H,/w6Àc OY({>aYf&FK Mc< č$S|O*+CѨ jw^G&6cX~C7!LF?hV@)!bqw~'e4*Q T߾+>}=P(/-nBQ%Q̍R[:*VK=t 칦 )Ki =# 嵯M-,Z0=ՀaкZ唸j_)d8\+(eoLTTT[!`4XdT~ۨ4(3S2ڊL^k|OCLk+Ei&;K%򗫲+Rx:@Q&:oIV*0#<<֬d+x_Rooc\`ٯZJx jb8K=^$`C"ڛY-/.߮:=MF缥BHgR6W?bv͊6Vr*JC٨tL'G.kK[VBKH;eD#fV`';$qU2?/7hСSk?OχsPk$:B#LswWD8JFu0~Gk!,9,,-;Vs5DƍTg*&.{rGlZH`# !h?{>I.cGIA(:[?qM7ckk [XJeMy}} *h5H9oc5q*okf}۾Ll EXZS{u&liRJwߗ2d~:XCYq_qҎl: \ƞJm? IDAT~SG?_~:]^*9kW>)g0N1&8YaQ7A~ZTqwwX.$-#4>!<bV}x5wko{~dT I*bc~x]qp[{psɔZW#;%9=&s9 lP lZzp?w3bR MT'ǚ6hEC+w\wJcRi?q'p͵b=X؃ukVL:t$O& }a}͢n; 3RR0 %ȣjHgc<CR뮱bٯ ȎTuʆT30j-;,Эw07|$X\^pRCEcaX޻F}x{)@KO&s Q~6_6:шy296͟=n8>)*# ._ ӒOm j}A>묳C"3X%f#D*Ǝ+a~t7Œf(DZ y9?1ªG" j bّ:`,)oӥ ={Ͱ!:tAOhĞ3?ھ)6wR${>ݱucpf/}}|;{jO瞃 /X_߹[I1f";? W20 V6CGX4xkCvѐŤ-\`\]^K\kڳy 6ϱ`:7Ȥg*(3̇s#V%߀x˟+Wa4|m CߥM?:p Kx9%}upܿ|㧌U-:jM&tJv^A"1%˄j6)@~V Y=+.3F!4.iOe<(9B<ˬ6ݍe<]PL=g%1m5t41'_ ~_}#*I%$1|a9֭ì@fZhػjIH@IMQsVkEA$2pC-ݽ|NYF_;"j<4oՋ0 T?FqF#`&u5 ]=)hid}|X"[f# c'筣-Xnciu%abF m4*lQ=q.m׳14j d ajdvrHy.<);{n-Щ~-x7]fn2&IWBvw t⪲Ȓ!,Ɓ4H>v WI N6Re(HI™*aIVF5 |( |fQa9R١R:;/\MS6@3m#;G 0OV_K֌ƛs2b%J^EJdc Ðe lm'Vs}YdBTTD[~CK8;[H΅omJfr:OOyoFTRsޑ̶wh ȿgB1 H$mȂIGR${}1M-3X N9k;4Yn5{F*IfX.,K)kAXnZbj1`VMCثIR3JxnMzk& ,o,ϣM}N΃{f(@ 9t堜+/7i5l#YRf+4Kͽ .•W>0Eꆠ?B0wǰ}|f . ]n3ھR?J8|?C'`&F^ЛO)?%HӄwSBQSAH 3GG7_'lVmyrtfF;OF=z !4r2g)fS e_{xxh!]vJXk5 <,7t0%lH;zp:`v8/uJ;~ I mZmXQ]Ǡ:`{kfvJKS##W`Aoˍ$u oV2]L˛y~J6^+~ $e:N]tGz%!qI[5þ{6-妌 BHY mX΃Mz\^)dCC5b 7Kd7gcVw!>*f *47m/ϪvO! FJ sV>Jk9w< ۥW_n1I]3욶\s[_x !N P"d4k`1*w(w.RIhDNA1yUDFSس9%.:ZU&Qk?n囈W,T1UM_Of\sއBQ0>:GbE6]f_zZicPi{~tBS]CX_N:Q$zNkbBVŒ@̋D#j41-7(pmu(b-h @z9- .$X7B f-v2W<[5Ȧ#XlX/jcXgS8al1r>NpC !'teғʖNlƲOUJсJH&L.^f9SQJyCcQ}g75k9.@UEn-5fڔ}$a͚i\F|s(iɧe$vUHێlC*tSR̕NT%",7AvK^ ?ar{br{_ k1Dܺ򶋜T#]}azn-A?b'Uֈpc⊇E VN o \ZS)&}7]} 84=TC[sl ֖=\)¤[-Edrk|[p4Rlʮ AoݥdGhJR[Kt"VgYN[5)Z-+0}eI\kqnf QJ3%r]bh>o 0cSvo1,nWBMj\3|`~ /Hʴ06mruϲR&+8ڴ}HJlӨze H=Ł;=a[t BU`Gk7DЕW//,kOWm|c̻ $/{6UFg@kFMֿG2GNM0릒z!ʭMnaxc6@k1*Aꮃ-\Q])Do(EU!}\Һ3W_HSY.1n:6{E潣EKhvD7Pw ˩|{Vo#FW㷕zT +Ű2 }ZCwy|͎o= Jkn  RItB#fNFҠ G{ޅ]% ҩ2Dw$O֖TfY[fҔsZO弁|1fոOdjBw(&EbZyFNPK# 5cF2R |Jk%a)KQ[/`5Rxcu^H(aL§+I8"VF[k.>W-:p'gBFr7YIH$4E6tip1_ĕD# Anź4XXM1üRJ:G,H=)%F8``…%Ha9'T"W%6@4V*=T=>2;&zBֵf#-=SO}fѕ3iuꉕxfd#kM-V̋&ulLmb%V@R(Lgg@(U\@:k&1e>Z}FvuaLfBE$rk4p&@IJVD9iխ3uTd}x\h_UJ3 tϩ%3gsDcp,C^gHhM!7IV /2Lhi7mS2J++WbٱP«HsřD{h?[+pƠ}Ly$L SA( e5r:Gk&eJRiʵSbU7t14#PhUJ:&Yf=GF )%晅6jn)\o%xm̏AQ@#&BDٽ(] $_ AyV] i凚{jX+rhS0[ajk %x i4ڴmcZK`XyB?CZ@7c9ˆFL0ݿ`yeqұKS?Vtܪ~D$ v"q*JUL=4V^R$BHgy< IDATd+LAFzOߛvK<4Ky١$Ta[wV6X*~`d08˂{QhTP{tJ+F̴ 2`5o};Kၕ[-k_'Q +x&aItX!W ˈ(p}᧭Ƀ07}dxцӦ)0q暑;a.1輐m%Tsљ:b#GE#?mrNwFRpY\,E/*kƄXi'G=X-#Pu~7`VʠC04Fރ^SlI-FwWU$|F-VAHՐ=ea_Fb (-?puɜB3FZX3M85ǶHG !`i择(8V6hЃFYJrYxhP𯌩*0Sk OdZn*#ƞX+Q{E]eLpfX)7Gle`ϫ17Ϡ/bYD \,TwjIkP|Xn OfUkk3{_2ZFϕTW <_/$!S`-ՔWp}+听xF٤U h~GנSPS!wzi}Fkb{p-yƟ5tWŁ/g{Cay7?́@#H8b>R7ŤSo{[?[iM̈́ [v ͆T]L3o2 &hAb&eHWiW"P1ifqF-񱞪͡&m֒իTw9܇# a`C;{IЉ,Ʃ:c&x?~[#MfR(xM8:u$s?JO7ا'뉱b)୤R'2BS'u&]w?^{xӟښJQKJRm7Ix _IyMa +7{=W{SAD{Diӫ=40ˣB)ͻ!$EXeFp /buU5w9,+@ιc1tf7 E :xĭo0piqkw_Rˠ=>zݻdR8!bV dA=@yz{tF|S7^'dQq j5`2.;4c#єD$5HXU1eRRS e5]Lu/KE D3K):\X}G**nk )łծ,oުݞZ*Q \z~P41y{mu/]"r`k)>i(;=؆AUdf\u8;7ʢA *:MQ@xJwmH碵|VhA#&YЪȆ=KFѼAfijL`䌹 "38@anṖ]lY^eVc #zbEX+ͻ ejЯl8`~Z ?[^{x}=к%ZtɁKsyѮf}w1OiPHMD)qdYO˥\ʰF2B}T웶$&!6\Pf{-\[aa[ץE" hJs>,1}1]_d:Lz}7]n6c`8gt+X,7̬po'wq cD樰@:ő#Gw^.JHv(,/XwkM6m>ixD{ll͢ی챥q\MȒp҆`T{|QF6+4hq|^`Ĕ`oy#52`.MHb.}e˾q߾?52kއEbbb~`1]_LfTOzc}`V?Q#S 62R෗:Q}^ L2Q5]|w}'n%ڵO#‡5/ N~m0 ͍,de`q[] eTM=U/m&L(9aXsS7iVYe׶NAqJmE}Y\h4[I.=Zn[FV:`ٯ0l1L ӓV܀sο40xF 5e )s݅Yn)NP>M Ͷ,oUo{=: -Qj)! + 3V2Fv`D1b~^FD $ɮ+hVn[% p~6.]MVSxߌ+X.HY2k%?(CIK 8 at#-Юr:j:ll}Gn:Ipv4ϱ ;n*>Uە \82 {k`;pxyZ'ݮڔd AkpCI`cc/s{JY[kcng+HLMցcyVL_wʺfn p mʟn0RL#YMWS]N˔ڏ|ݱ{ك5\qke)ga_yُc:Z5EF#xj@UOk0 QƂ*da z_T^;55n5rjg=vc&|nW3qwږZLRg/dLͅV M?m~_fP5Ur,K&.̅f9+;Jjm K*BڎLhbr  5_[w|Ie=i4n)8FnD"n^Y2jt}j]7 s ~k+0VAbw4OaDCHί`%h\[y*2Vh7)IeV%ɘ X"#/Xy6VNl'Jkfߨ#.) t,iXgǬSA8mڥOD+8wָ$2}PEJ\$$ʾ1JK&p^{.!ݹZĕR7>w`sXA왌l-9O'pTI`44ed:/ JÈgF ^tҸX[؜,X|^F`ɘt(rR5%ɂɽ1VMM6]* `̈]cuOoW$، ?VlHL.329%)=}2:zV4>CJIɤ W%'i(MȦL.GD&FUv)k^ { r䂙y_ӯb4V ZVO3[g )V1Eiv+o6f՘gا ޛr\ƱD)赯t=ءP,=iJ/v @cTX/qO5?Ҳ:3rf D!_IՔk7:xF7-~}=(&W_N`72yk&*;bƝdTJB5oۤ 1`饼}k^YkP֌M?E5Ǎ^xՖJ\uǢ VKeZ+_L=m& [>wUx/jA3 KgCXCTjB>kVm7eS}PaF_eleD4ΚXW%=mUb<, F}%7-Z:ޥhJ -5 %a x7)q P~S3^ 5ҋ"X,2K/\G:z'g5gܖT֑㑩eCĚҹ՗se-m4vO. +d՜Oi*yc狫DI." D'/1\XJs,`{XT3mJ^K? Nb)y9&0e4o=Hn$:_2ԀABoGXm)E.:ȑJ.3cp*N"mPf[3$nw 1ҼȂf&NX_ߠUN +˸D%3gfZV5n9 3qB/]B|;1 =;< j+;>G@mvCMʵa05bf4Y$ i_W}"4]`@QOS5M9&iX.89 .< Uaž+sŦ L|"8Uh.B)O>khI٥vʢ4-{+,temS\/YcHo8^PMOWv[Gr@E|ZoЫQ42N2Zzx.H _d:rģ$*y=ՈږbaF(yS8`Qډk&HǓ|H/O V4C}^ktҨ' ,OwjFpcvցqC[#ާ,9ܝ d} = W<0Vyp'= =w!wj쉜qG!mk/gg5J=egX%SH#Їwj`|7%FTMw_xH5!v5% ~pRq7Wl4S#QQH)~1 QO}}tp]dR N"-zIp)RwSCZ wVX+h </'4\f qlh\u%oMEXXC_D,aG^zQtKj@k`TWu.`gj I#w܎_]Ѫg(u$^RVe!]p*aݸ.ĝww gDJ*e[%BtlQ*! T )T}?: WqUչީF'q'joL hLq1^(qQ"DQQ(AATL5眽?k}Z뻡~z3t%68pFI%6VQFj$U>U5u9/3k]&w] cczqgj5{u4!uKՌQ$f\"sjVJ6Å_..|0c<듒K5gwAѢ{Q>Oŀ 4dmk51\ޗz~YڌE9`̖JMيf`` &N13Pòٵ.]Z=-G3|qper3F]ؗ@eQUgfON/ȼO&8W{FgVϖ`f'K# &jh.8yH|eo^0o_iÏD5ZLjggl2aeF8CЌ`2lםa$KKw{e#, Gwsu]#kI㪲bä#Q!LB ך^#-Hh@P^oL-VBwMWs9 ]9PYGXoofe Ϯ'l>c`oJQVBEJ.k̡nC >|f:G>vyXuڦ1l8yT(XàuW2N5t4yaEve&5&:8;lf)KR 3-7{#`q)>z!Gwbk1B,ZD|QB$ջfv7;܎ b`EB΁ P_{m)j =UsO9[KPo(z-Yfp"YVb_DSFY҅oýyR>{aODH+#`T^V> `!PFr g”Y9yYТCxjB7,5REW셩wq lSyvӎr G#lJ!k~οDf1CKUd7݁|ɁEYTtp @Q8K'#z+I$G@޴u]j޲d$j{/*2) %<́_t1ml G=pe6vܗMƃIJt\TkjI:yL1zrfC,]DfMZ!kd饂 s0|LxDp$ IDATUq*W!y 5*8`5 \MJftyV`iƆmơj}D :A{׶;_/C63B-ܸ卼U^yn['u֊w`^N(qY9d$I6Q3V [+ojLp6MMO* w0QVȢ`[S$ c&j-ްB;ra{ PQ5'Cr~u5?[_,/DA A )>ĒM&dqճc*'S<:_8 @'|w5.0*Fn@U,~EXiJ}PpoW Fn~aV2ϜLdobV=c9~Mg#mwC23m#q&jw-{rrM"FV5>)KVYU5\=@1ctȃ o 6`]m 1??{ձk@0*6c!/Ϊ>C]G2?;vJ6Wpbƨ3~Wi|4ɖrz-eR'@+鴾FRM,lc f[0 ` c1h^juWD%xlٜ12SzwYwz!0jٰ22}jw +Y\x㓹ƙqllx;MiἮX[Rfb΅^ pEMRTu0w)1{lz ~5NڙbqJ'[WS:K“&f2?9>޿EQֆiƆ>DlD6X1yTHǛ8k3ͧ`Ahc賒Kr")KkY'Q<[a[T\c6&k]fc'1fۜ'&f!> pdVs&{"{>t䎳 FK27rCnRo=\Y]ěVlK2sE }e߻ul+$/CN$)a!Q 1g%V!.֫!7e P@XbB2sч9R~Go9*+dzӁpL𑂺6mUx۟(R}ddIZvYәu+HC!)JuXZW]ULRq/|EDVCRg)2ԾQ/ʉR| /lL[=+Hԕ[YV 13ާɫD8ÍT 曮x)ދEHw 84l|$[&; p-3E=.2J V:kZ>u)n8D9̠wT<uT)I ʪ eM'YK l@BTݸgtqKzftC@,\A`uҋ0#Ͼ7uF.TI,rX+$+6ρab/Sp9:Z%/{cʽKQJ*k @c-Zd^Me!CfGشÞt)BHFe[ێ.E.bm=J|;Talh/ cG=k6Teꀃ?K `0'1fpӍ?i'x#=`KKo1>I&2ʲՖzǞ#~TiX#n!thL&<؛CRլDV8YL]e~Q 7 E1Ԁq~4 knj^{h9N\^ooڠߎ7l49liE$gɷp#ݺWYSZ5UMPߌzב&=3w \ݡU;azN8z80~>W(q[>6#&_x*(rWu\U_[G7]@scMi0W](V_, |%b9ZZ&֚v?qiWT`VJfA&xKO<^|㐽l/MjT?1: RT<NJQd[Xz3$ AB{y ͳI?P=B6z1s[,6bတz.q^3CҔ]pZVuC&>]e9o_p 9WXp T.@QGUEnqvnqL7 S.N&# Pg(mV$WP@/3NW<7[n 8e|"))`BKg3گ΍}zP3Q!B%>XO^O6X;vM(XdbM|ۨA ~3b%wi粮͑%IHe"΂dMr-gd#{=}ض-GUUgNqxaQvdn.M5Si6X|m .ۘ_?CHқ b:`x5wj0Ļ%x?]~=~eRD!%‹!1ie㟌[ Hg_? X\X-p4hvO?n/om F{I?!UpU~IyԔ2njC"Gh!MB~h).vk\`8̬zFFsCG~ w$2[u%ȕe_ %&bni EӄLcK#pY"[POુ}ݵWOz+{<,5Ҟ hӡOlqomz U_\v| /y->P~R==Zlb+}y j쉱mV ,]{? ˝EvE\9;ȺYKE``Ӊ ؒ'r.X=Gf6d~;w!̸ho r_3 XKD(]`չ*M7#R8]nh N)mcnՖ8\^f05ums{c3<Y%dfM6Q[( =-'~_2Al7̿C;Xʴiw/zavި@_C5Tm׼un\QEqu1vRiFT./Ҫx!1myԩQGU!;{ЗရSǢ^E)k!C~?A͛A,G^."%9xW \T· ʦELQ4s۠kZݜ| tཀ/ׇGEYS?CPT{ibIf=  *DgZuo2% 4r|}g_=bbwOTj| ; {|lguM_cgK=3ꩨyH p*"*I0tdz+>kVjyy j:֘qzЃ1:pvZpܦ}w-u&^0]m?0;ئ${#r+A:zfmh[t]2:*lsa%u Yo~9^LY6:sVj3g1&P>8@Ymv!?Lvo"I&( 3fQfFBiA#颂؉l1jĊN~tѻ5@n6ai5];{`^.?jo$U,Q "2>,e )+@u*pTpUG:g,̾r;$|gƫTBVi%<֔nA$u= '| whqq}4,-.t%@Ug}𒗾4p,,7pkAd) oz3<5ഛ!Fq3!', Tbc*V C Ka\B00S7mks #Br+]Nٿx \y1>PΓWt(9i # l(gBu(4P%">\IEW㗼hb%>UcvƧ?lIy$7[J2rҴH Hg?98ج@Y`Q8%/{%͆KnOXP#AsJ޸'jGD:t{#"Uw.\=$S1qfIk!spjS l;d!y${uđ*USۆuh5|%qB挼T:ITQV/O'6s"AQQ\Y33(F"R҈8⢯!Ϥ1*̃Wv@IڽIGs7:I^2t](PVʲDUV( eQʬЋ^.RPNf.6:o:+:HL1ZpQƑЕZ r!=PlV:rkJo2b䲚PUy͵>a;܅oy"L)Byy&,˯ZRFđ # PDy̖KH\I# ?F­w"S+"W\K^[XoMY']uO{RA?!%4a(\clD`caaw=mہ@(EY*JU_}Fc3y}.00S*1M2pr5ӨߌJgo0jN2!:̙]B bRKN?.EP 4ܒv 9豊NU=QDJE*[TؘYSiu }ݲ#wazab GT!.b@EQbEk 撲Gv\rp䢇WzP_G7J8/]@dO.,3t>|}cѴ C׶h{E˪DY+g|([)^Bزu3>M2K,3[;.:?PFO']+Tjl{ IDATNe+{<",cۥ.p!C0%)0##Λ#U>Jvʑ(|g:gj4!bDw{M^5Gʊ B 2,0y2h" q¿'|" ٮ l%_9 bCJ`6l3{Stmд &|kr u5@]ذa>Ϣ* B~5İ*3:l^#GHL\۠k_C{&@-1>1D_ FVZK]&jVi+,͗1uҬtUr76uqTY$Hɯ<Ͷ0>9kL,cQ Fƺ> h˝dT쩋.;D xO:JP/*0C2 i=E@K"dmۢB5oMӠmX6eP5NtXf\/ \Yo\y. ՏF#g6K*20X8NseacIx{A fB;*uʧȯ{ƣ+Djo6r[zhgk:PW40*"jDJl#/eRff#d \Q{~}_r^Fagy*T9!IX!qDҌp ĞHI1h<>٣ MA3b:bqq w5F}q'|A 2+.*Y9LZpٷBYTfG'A\9AJTHB Lc*0@"pyګ3F&V\>>uԣsv}6pegsN*"r!w-z=/Pԡ ow>m9XB()wRL*⊾S19[IK&Lq^rmڵGn.(07έIc%(ٌtgVC;3X̿4ÑPGC0!p Gyƿdo+ #Oٶ[Mt Sa%g&6%S % t-Mv.#.EQO}~P.V,..bNC<Ʃ|o7fӘLfpƉGGNA@Գ#DFu=vb7EUQT{"uFN6@;Wd}YK\.pݻt{@@6ڂ OY[!êtޘ"$¹ lk4qEZVZDˎHTF1`8y[C"<4,b nFl>~7n)F8/h<3'}B5ob_Z1};onp{_^]7^; *ctq$v2GfyjtGe Uܣ]zp~1;)*5^3@u V&b='h`fn-qƠ=OshֵwL& StjKwM9mg'tPGrE2^dAjnabG3lEH#0 N$/ȅ*S C1h89nI)" ,~[p U)w J1!^>~hCo裏>1"0}sێ[o7ހnO~S'fTe:5v`ׄk`NxaAxmȆNLtRl?v>_{, G&|3K袌UAkoǜK{s%pj[~`c:9թG7E3^A5SuN(!)77QedtnEUChfCmJ ,󤖋\Wc8^>}L"тaš<"OS69">pG={,>Oaƍ "4KSmۆ[6o-܌kW\qο<s1(R/P&y5jaoR` ?06u2UWUzee"ӜmTS--٭JJT%Ȍe,te \mLm_6 ̎C$(>6Z 6s8e w$WdtH4s_i3~z+t P1X:3W_eٔxnZOdz_F 8 =RaVǯ[ѿ<E=P~`W\~93 &EEtQv] \&:_y_.ֲ)p%z"ʍוUSd0+X6;y%arr-k(n'U֝R=l[8"7>LGѯn^ɝD3ҋ1᳇WG!eh!ʍAôԅʚYIus @P! G??J_ta2ҭ |7G<G>yN:PEt4D+7gT~úDt+qUW*TL4jf֢(cAXbLKqp"޽=KeV5FeuP΢MP CF~wm{/;B4qQ ֺiزgIh'~c G}qXY3꣏? O@U-2i(]UJG%FYV3K/xڙ s,QɢlMz?s:Vh=c X uN#3%cxAC3];0HH{WNA6\ղV̮~r8F1ilft4{[ )#waa8crҴRq ʨĨ AyyM /9.8a/"p7xFm 3P~5x_q˶߁Gd{~ja)-uo?O Jni,t G5E'=Qn* ׆C=.8ï3 +u W @ `V%\Q7bn>|k*ϻwNpr{69;d[ԇK(j,rmXD2l݋%5g7GN9Y"C۪*i"yW;M((8]@V) 7 x+1;]S=7tW^r\_&"#mk|TC~\Fwv-.8|ܳBqBP>ƍwg #D4]?qq/t_ܛ*E #K#N{5v7='X`wX[YX$ӂq>\i}_ExZGL59Ub4EC$|U&MnY'S .%iGpyǿTDX_=J\p{>`4.3׌~GgyLϿEN\sqRěp\;4<$l΁24p5+)DqE dN/56;o/VvqfU#5ӈ&]eQ.R~+ <r'h^\SɤA5e8i+)#ek9MH!M s̒\Y"J??O'A.p)9峛yo\!='$S@ࠆEPJcKo⣔lNKí=yϜemLfusߐSĝyYv}j^]Z>PQ|T8>=5zŲD$3ơ(CN@˄_;߻[(2㒆 E|:(\ A\ Ԡzhv!+"Gp%.rEOq)2V!pA!DYL~YE^XV`ۜuz:^8Cu<@~Y{m3̞*}0O+ e;60&yH}LGxDmsg}n=bL8n$x3\ADbP($FB4۲_8? |>\ߎ,^~ܶ! J kcan0{v=,Du/od sDX~=~߂MVՏ{z)>Vi |%{w3{ yVFƵ ^S+ Mv%kiw#%l<48x~n7\^n 7vRĕ{d/ ڑ"}wuߩj~&fܜ(]|PWzN9:rb́Ye{~x,f8swȡi36N-b ~y7/pBKEŔk*ypΥ(T8 +A֬;?xkFAH%Yh`7n1p=6}l߶9^V&$%;Ofwɪy1h4A10l H9i*;g6ī0idvU'a<=+x! +vMzPؾuX[]f{<s(I53UQJQG?ز ɑ ոsO&m@1"&Ia #9AȌ-wӦ N+2&)A 9A1hN -;U: w$ PJ2 ';:1km<ض4;rB=cnކe_F`q@_v^|q]{u[6?{.*oaw}磟tL0d)~Y@5hTWf&p c$oL|v[{g|:rI[fuQFhu!A[ ౌ]O3Z QK?jC#Z RzUB)'kq1JEHE^4RѫuGtL.k,zoSFCw셋2ƽU/my|_Uųvi:\Ql[gH@T1|,,dABf!#6+#1։C 1I=;= /4/Iuqq"x3"6ҖWt!tyK: d3v Y#!<Kx\aWkq#we-Z߂ѡ-<;#x{n{pG[t&;lۼf7JՑԐ@5-ǽ$F`Pxkxj-2LFNv$hUmUܻU IDAT߈k&yyP{SP!6'(})V݅4-痡t7IY5==lZC3Š^\]/q:+yfRy%U k8%VsDxů͢ВSxHɫZG2`/캍*+ ز\p[^J>୘̂& r]X"*6[3rv9#[9eV*A 4sdtoƢZ|pCr O;<"3s&SDfߔN9+y PhezၬI%k 3[,~\`8T&דZ<k^.O^vs$%U .z ȗ>Yr+'f׭k*mUJrDܥJ>|2veQUvݹ(jLjL^k(jj8 ~hݹS_ +J˦V+IlYʧh|UbsY+X⺸~ jL((3x' G:'{ey:< ^/LD$Έ <VMߧ:3) Q`VpZ0}8/kʩKVA{Dwc*G A3!|rQӅet rTL@4tiبr#N3{1Eçb!fimZW ӧe߻Mt+P78?{X\dz^O輱E*Ʌ{U܆Ba6{bEs^ n,e,3j7nͅCx&Vq@ث*\E^z:Kl1 $GamiJlڈ9._{T"Y6N6qU6OK~KgKI,>ۣ_>QjDFi V[m?Y)+KK. L77m3B[p""8q0&`W랜SbbS[M{UeA)Q>'ӯ+rٛ:D-l;{YPR;Qsxo+`BW`St*Qz {ʫu׬^~DՆكow)o6k>ބ.Rס;ѡ3ELKjulMP 'p h47E_:R[y J/lpX CDv 9vUh/9syG;;/8u:dcAmK'|&Id[XYM)ao.`2=ǜ;\!l]^M˯2ᢸ \_=1pjC(Gc,nJ$oTUAR #FвFAЕS]E8\NgiFMgVh9WwN]6mߗYyvEM//葖{1З%ي|cdJrŊj5ʄ/ 5 qx۷% EF 9I2 KϤBkoӋ~r3VJ Y=E: tA1pb~L1CJlu_U3=eQ)uf1ug68VńY(v& T)E8M[H )G2"`zo3/E?ZlJ+bm ݪg&5Ǹ/O;{Do6VXLΣ P5.l9 F{ w;pdm<dFhv0|5?&U6`}$0-yˣpeA"呔B*Y{9Y۸|: ɇ'2*LX DfI?3+v{)/# PxZ0Mw𾿂YSIQHE$ޮר8Bړøux~EQ!cn ?jpPDa-cOnVg4 ?z7nҊ@HdQљr$ ^6wUs_c9q[bdɔ*&%vk+}f;ii`*F"w6@l_}$ҷ΂SΛ:lz#᧋n"6`,D:=?K :Àf ǂ*vDUweu U0O,"r.k"s|kC+UhS\\P}iLЧ- l@H6{^JESJw[^_vљx|rR"W&Gy 8Gc;8dfDd.lmB<;{peqøø>sQYyws.^6EkPaᘫ76'OVp_m9Ěa$'s5΃ڊMtA靿rI1#ԑ~.-qQaL,},h#Ւt^0YPw{đQokړQr;{ep(Q T8h=m=,_[iӝ-0zOF\p;*e㭼.i}zYܳOZrM҅&B!0a:mheyq.ܶͮfɷ rPU|~Dcug7鮱 pE*1 P'Fchr8F13/Қ8=m~11ZOdѯ wՂq[M2̌L[Ua?{fNZM1%-q,xʓ]z4b|餞Bے;eUǙ e;lPK/Rpu,fף̠LP (GCEU.1kLz,lڸT9TV܃N@0SWOrH5x=0Hs!-;E.g؜3C`Xh,e,aySU86 E_DUֲ~$#H7(# 'B5Cqr.8+}lٶ \mX;0~~A7w+و{e-WLcgft!R.+E2|8]ڠnyg+=+{6Phz)s[̶{T{m5}G F %l/ȹ${(,D!cHCut2Yg:vlA@3(#33fgQ̠k{YʜkMeyPwdL=_: !d! o<[_bz< t*D`!z5rtkZ,>G   X( j%Xϔ5TT,eJEBF ZhY)12RoDHgُ{Y+?{ssncnw߾}^>1,,-۩ jLc<35#WLo482ly,: v0NP1emRQUG0J9\"_{=f9'ER+Ė* cqsn*!H<fUJitgsƹh#eG,LǙi/V)XPꪪuN3U T`? pQpEQ) P:okcF% Xhjπ#:|U1ۘbt.+ؼU(IDaH5D;~?σVYmdIJq$[򦮾t<ѸW'cKTׂ䠂VVpE "hEY`~~m7#*'WcyՏE\kv~*A&q)C`)S62ȩ'b; :~1[̫/|W^M7suvogqt㦒$H%~8< ma~ɞ}PyB]dtmgu ?j=~A;D}xN[m̭͈U`i:T%wöx>|+,a* ]dAJ o:jv"͇{ЍZ 'bcj8'zΣO{ܶJmdǞ]-زefX$I8BqN_[`cF!#jsf]㶍@ziPSWSM$VUY++]?7zl:FhZ=/'I3gOwǓ^q͕-NH1d;2S19ȃC1sR t:;2WC }, @T 6TRL[Lc}8rEY@WA( (L`Rh0L&JU؟Zl{fC V;rIS@i36v/۷hسfnB1ί_cwGءJE6)wOǚÂ3P/)"ȧ;l~Ga7WЩ?SBS\.!]12i aǮذ6=iO/8`Yj8HGU1p|0.qsO1oHS .*<}hMU=T85/9jdžz_lCnX#ga< 0!^%#1tE7_dmd[?,Xy+a?ti6/p/Y/ysnQ*Ok"3 :4شFyqW{oW~B=CubhoM\sb nia%Ni(I24H)}L3b|8ĈzKXy;7Ь[t ],A#vn"kjo;v=jBi3984z\H% ?d~/3ڦ "`=h\Y3&cA])3-38Y尺um$guvS{LkZ5" YpY!,Ll!XWa!5:l>GVQuN[]<`cvto1;b!Ug[k898@?#yNtTO-#bB$<ԋg iO}#eb?;]HYݕ̌^=8Fzʪ4p8bOҁH3q>*8)y3YOj]zm ¢y9Lt\:Q;lGs~t}z`~ny8FcT+Gԓ`K"lÓKQ&L-b/dGzB :?;ww0=feڦAS7ʣ`VH@ <7muSwz=F'm4&J,&DzTDI0ya}wg_PxG;pKubiOw ~N$dH5FxQ(Jr.c{5-$Dq2mېG&Khy1 )p L>il6aljU'GՒSnW+KFFw͂9:覩@ (':Kt-+fi}RsbCs ěq#J^ n98ߟcmg( <\rlwNYY{}3n55@}vp/2gq7~乑{5/ 6 *R`;& ѣbcEO3dZuHvȀ|R*d3A8N0 ,W,#:>"Mr`2<ő:}5&er=%6u(N5J.& Xh(y;-ZYQx bp83كp)P:R wH|?N{$đgj}p6aqwe5H?z9]/2* N:?}k$+|+pdg}9c!&]Fw.F 7| W~]hB ,%9ꄓ@ '{^sɡp֚H_nKNL|9J\d=a .y+֝b:3Ӓ7{e o*jrXPӹOs|1.e{ uBMqx-O pE/ԳsY@ɔ4%pgK(z24ʞ Hg!r3CWV>`_EFxblȍ*v=-FEU ¡Qd٥Bpj3lv~lM-BoؒФt>׊\lD sq n{WBc::Fp,{/k^ y F;%GR$MuJO~:[wp/K-EYm8mʥZ?ں0j]^R)܈s_+Ҋ‹dk2|& %\Ղ_yS^iu5\1 M{Ό\RRV-;LӸ'(Aeb0D5^E&[/q7;S"蒸pSZ g #2K/p*!co.iC(4ҒK#M5I=G sGJwsl#= 0b+qkBąۙ9Z)QXN]w`G Y.xL5Iޱ@1h[`V( Fh@jG#30Yrf&69yULZ:U2 w'# QԂd>@?zRwt )j\)uIgRp0f7o׽ oEDOs1@+ ZHE}e ZB#3Q ].ιvttpGVlrP,tSdg)u_+칶άQEyѶ8:2RZڹYTϺ~VL₇yF e9;1-ۂ9s>TrhNxhr0+ˤM=c"hlڦ7ܑ%̳ؒ0֪T#!/ܥRV\^81'!e%. Nf6`x! o4)%%9 O>MyU4UP B4#`8 cJX"%kD$LրaV9?[^xVgmDdl_C`Ɵ"N&tgg=RO M"zدn<y xU2#4 < e\j1t@Y<>:&={6`1y;.iOǡw]Xa_P@9O&z4!j+ػ+af4S9 B4p*r_9%y`cƍGs.KւXz׃3Lzb@aمITpoq)-%xB@<0@Qm s;*ה/AUc=e CPQ@| *]4yvFli~M& j}q$==:3N#=PuSuaӍBg <H3 {ۂV9{M/)UxQ 9I۶mo~Tʰ򩳖Sr_hKy!HGUQK0zB 4c.F;Ou52CFb3sJQ ["D˩;m n/=밯vE +RKMt]KDm{8APp)='oE K`B5r=qF#9=&b2_* s8iٚM٦X̭[%6&)ؽwQ %I( y l,뙋n>_& q.ENX9\2=u(@2IfYT,hI!]1 ZA>@U|/d;Y} k~e㙢=X 6x`u K8x?{pI[x.KLQ!SxO?j>/c4]E>A'hlM>{vp*=^ K :bsnUD A*[5̚}F,^Sg,@î[ M4_)mzmg]ض"-_)3܁>d*yt))3?ϙǻꮾw.q$>oc_}D_+{|7S[E)Ro@_i] {ܯC<Ͼ2V'b7IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/pgmodeler_name.png000066400000000000000000000151651360462764600245700ustar00rootroot00000000000000PNG  IHDRbKGD pHYs  tIME .k)!iTXtCommentCreated with The GIMPmIDAThzyxU[[HZT@ DB}DEmpeuP@:," $H#ВMY+.gVHGA<ԛ{=se]G7xE?4H }yĈjjj,4wi (wb DΝ;#((w+c999G ɏ]yŋK FGyšk׮۰+IFe!Fx<{w>GdYFQQQ8x;S$@۷(Et #۷ߵ!v 1tP@f9^ׁZ\.fFv;s>1ɓ'0y @o2>ӧtaaavC@|Wޘ0anW8pe}ۜ:Ǐ#}D/ׯ(20>11%\U4&j˗?lydg>@ׯC\L4h4ξ;#On޽{5jTh4r]2`hb߼yi4n8)55UMKK#{MJJ덪*DĈH.^_ٳgk}QԩSΝ;?OMRUUE?4_N\ Fp8N: @4 >|˗[kkkǏ>}4)!]UUv̙"Ҏ9RMSNرc!]ee%3feZ'4mڴ='N !rJKKr/sǏ>#!]uu5x$^zf}/VeeegffVeddTfffV5ɲL6lX ߚ5kiSjYV{mmBD*m߾}__xnS=p/]DDDuuu .T۬Vkw}WgZ|9sL>CjRzzq3x%%%>GZV4tW_}`0kljF.** ].vuȐ`ɒ%^vȽjժAAA{zAGY"""RnZBD{1((?|¾{Ys>Y.]wnݺ߿CX,._ZBBak=z(''VӽwDDm9СCGy/^?Kv] _?!"k"##Ñ,ŲO>vYFDߖvګDD7?$Nۯw#((h/ "[v~DDYYYgb쌊ѥK̛7Z/̙3=,,쩂JOO?`Ν;RSS37b|m޼yE!IO?z1+W<ʝ6gΜ#!!!#"">X,fѻFEIIhݺuգG+?}EQ(//{gsLCCCW+6qڴiDDV vxn.Iݻw_WQQ!;N0aIVaÆ}ݷ^%"z78_ݽ{+wjժgfҥ版=z&[zx&v9א!Cddd8̙0 4NII) "裏nnw#735kdq' }ŋtСf?^J0;[6lؐ`^JJJѪUNuOr&˩DDO`h,> "rrr\ 8NGMMsaqqqҥK.[N3@9(򪒒 b1FҥK'ӇϚ5kҜ9s?BEQZc?oBx׬YSJ Z,#/ipBիKz$IRTttdϟg|!"+FJUUJ$z)00'xq^O;w $kkkk.,#,,3t FzjךL&QUl6f2@W\q Aet:Qܾn{lttt'Bj@h߼@:1oQ$IYe]P @EQPUUpCӴVMScNiӦ |7<4 cL$ӧ/ Ç \S0 VŸezM&ucNc.\. B<1w\Uh4z$I򴶶j={w Y#.(x<Ɔܹ3.qPI׫\.@]k1544|rngΜN[wq2}JN @@wz'`_ ѹsgSnnnfVV֮={ܹsؾ}ȼ~b۶m_7n\.W .r*p]yZ[UzdEQAи,IATN,$yc$IirFFFodZ}x=c \.O?m$et:8Wvv< [kk(/ho\.ۧ_EQ|-I& '"/ SʕLeGAPAn@<3~hЉXݿt qFSzz&5+$|0+VUUUk vt@䦔1bD#GEDD%wn$Ni@*eӧO?999՝q_X(--mͭZMF/ҐЁ\F ve?am۶]UU*..ohhonn[.nz";;l?nݺ,//vzǿa~:n1bA>\w}KJJV^] 16$UƖ-[REÇ_6GL25//"p\ rĭ[[__1ھ}~pĉ?FF>޽{ɓ'<{ĉNGy7L8KB6##ã( M20cw{:{ 8p c2ccBSSrܹ-zJYYىČ <>`0hHD&ׯ6uTN3Q՗_~Qun[nw+G4ݷo߫fyMp)k_0>8{~##G}˧O>?,,l(i[w̙zQTU-^hţGވ}d2ESABEEEcl]3fYfFGG M]`<5/^thmhh/((/3歹s^֭[^4M'ƘPSS>uTk0X^^b޽ٍD$mg|pg֯_r"h8/\W$%%ey9A'>ӿ9vX/tzXEwN-u`  {K~*EѠiZAxxxf0zhTӴKhr}byׁ@ B#cx1p@$I\`_pAnz^殼jCH"YkXu?yA-(MM }o|c9"""_~AК| jTUm6oMKK..PiCn|Mm6[d9د|5Mx<1X(ةJ[4;}->4 Ӊ~t.IQpSU*EQEQt⿅&KnMӚ%IrjTUus]j?) +i~ pW^gƌo544lաAƘHDǎ;766nݪo8ܪiZS>|QZ4[u|薛[r Do"(.6p:j'¿}򨚦pu`4_]ܾa3}Cswof}޽G뭷\B#<<qƫzEQlO?÷_읆%A )v~ww+*C<_0:t弨N:u8,,o@@@hd1/cLEQz˗/۱cG\;~׳p H :Mrxrح\Ƙ82::(?e555nQe=.1fv:f"R9zQ m2̏EMn EƋ>]:~g/ Ȏ:`zi)ʍb?Y7HBg,IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/pgmodeler_splash.png000066400000000000000000002531511360462764600251410ustar00rootroot00000000000000PNG  IHDRJ@pbKGD pHYs  tIME 3iTXtCommentCreated with GIMPd.e IDATxyԮWU'{s31$L@(  ܭ8SkrilJjˁZ`A v(V1R$dI %D /|}ﷁɫ6.P?=In'-L"$_7@?O@֛w ?qc=oAnEYKdy\nUE8r|.}L,_> *S8 ;zrナV =\|H'fQz8tgн7iU. Fó/M|F`{D$)ހ Y>M^wսH"xUOJ B>3*ý\̌gﶪЌv ?b6akk mۢQTXrz677!g 3KRv?ՍH.pg>l?VPf>Y$U!,1HDb4p_Ӷ,6'lCDܤ,^=ӊor uS oRAHb0w/N| =S>xRg$$OGU0l8;]i4mcGj{|/kCy4NB_$9* b< O2K`m( =?~/*.NB"[ylK O; |2ZppufAwI"PsA,!mKޥTD[;E"Pz>A4.n;#J\"wY$){X3ҧϕ\r6!_a}7}?F`YE0DD9AH`f@@~Bia%s;)0[8`vLS6'T8~^̧#p&oqxD)g\MG.XWwLj ɢG AJ6b+%YHBA77*.#fV)H-f(t%)k)XkmW#%`x3ɔfsr`@DH 4 @ smN~n}"'d}tlLk. mC>r8< m<7g"$m鸑~pV5(qt6 m7"4Bo+> 8[dUzmc2=7~6kPUU8v0>J@&. ,BTG;eiӋHZ!S!ЊPG ,"cD_(~O 5g , K @Hz|AZ1HZVRF;0qZ* SVSc,'cԙeK>( LqQc:4jPT};J>wAF%̹|a0D5DG!mA/Vw_;ba{{KP6 )6&O?+?+kUC$V>ÂTjEXga PiF•@L@x) OֵGe3's  R)ed̿f*f:)< u &=މ) _Y#55u4R7-k"Q"NAherhz0Av?{*F7|a{+Blͧ[m35˫6xwN} c׊#5Hhbj οҶᥗay/9Y8'$d6G(&N(P"QB>%G$e m/H"LL1F%;0 .>asFX ~O=Np?{e/'cTv!Bc%R:l($1, $wv` 2ގ!\[z}TkSÕoؒfdȑ-_NiJ.t(%B(2QT+.J=zC`1÷$MBhk*4)@+h%]$FNq~w\)Z=oUqE‰P2"5s)Id5RFOP^F̋dH ` =z>"gמp6zȖ@s d"sGr8w +RJ yȕشm$&zN?`!@02`ޠZ}6̦J$~ue7f$id.b A(w@BD 7)0bd bC )u;'`̤ -ݞvWSlB Aaaz ]p yk;3.ɥDfY 2D2! +;%5sYT#)ߓ: H@ED~ER OB@HsZiWZ߇Y 2%Q)>GU$27%w\A``H qQ<7vͰ^LZOjp rh!m :|\nA69` p`Tpރ;|ʴAP%cw-P |Sb%crPmz9H&RY_y ˨KU`ٛb`O0|XzUWى]ix>(Kz7C=\)KH;mk!ggV,RoT49.QQegW:1X9c1rNKPͲARgyHj07avǀcGqƛ~ T^ M)T$$y;t7eJV *d%>"#J9nGwm8Hoyu:Ȥ:9"Y5d[ YX>7-jgs "!BD'sr iTu, רz=U52qNO6S$j,0i!u&t"k8oQ/^d2TUUeiHUqSOgN#fBBfVDq@aJE@LTx$`|CYP'EwIJA{Q/c|{?&Pժ8GJ#3th3%08mAqx)ǷvPǟ[8VP*}q]wC>> u(EPJ5JMQ5FRhb̌je o.,}KPcTUamcv/ǹ+dAm'C4G䔜p1ݒ(fB\' `>H`tɅ-RT ݙ6`G?уav`ԏKAb8Bk2u|.BO9\_B; UTI-O۔M$0mUfp=܉pgoއhK++Ib)~8fRN<؋ ɏK5$Uj:p*柾G?Z3Ϻ18 SUV$ɇFCђz.D$ <ߊ} 54A ş=BoimQxqaYF|>}xyëP8hi0L0"~AȠA:s]Sڂ0Y09 aL܇敨ꪆp8}Čvm,ՠz`.ɀfJFw‚M{4?Ufa|9</di!H`k1 {{`vF.v.:y;ALE!(9A˥K0Ư翈 D p Gon{߯bq*HŘ=& kf34M&\rUF:‹h< `2a2p(QUQGVdӵ$` (1r*u"߱u̦s95667`8x*=+4=[~3KmK~@U9(% P67 2]I|mB8vO|t7@-`\ L/IQh[K!P, ْ.SDyAE셎yEF`@_ۯCҌvHamYQ&o[Z#/xzxfhB#qECM|H˔sCJ KEل~ᇎe__-]x.*"$0 EC>tz\( _0lШ: g %}LmKN퀶lhDË^Jf)n/DFۇqôo˫h$1Y"K?IUU%1Ÿwr`fUߧ3(ZeF9l.w}$v/IiҜןJ-5Dr2syR`| MaqI쵌q>_nH 9h%]TiFcyW󱵽]TpmOBeW [ vkf~f)]?[Y~\0e!1Z㐺o!r)pLVƅELlmoNO ƓGF\A<)EQs*9\ %:H·iwzɏs,KB)0NSL,_^7Gs wac&z~z ޞ])'fOg}X][5_uf1u̜Peј3rkas3c>Čk<%;]4}բ:eBSM= Hԍ+n 虗+GljKK"K1.7FwI~jלtW{ϹB"͉s`Ԓ#p&b) >QhH>/̧҆3 q5BUU!?~&=t?}Ve0X" nK-.ʱfәL;;k ԽV'&-&"Mcnu]y^ʀp AqOVT@-7jB~=cM"Tr;\Ȼs\~ѫ˿8>8 %mg""zd۷ NnGfKwv2 >1-V|b!)"NRHIqs~9ɕz2 ҫx{{뿢q4)5K+kAM` BnFE l4$czmS恳m8KGIщ$T<k00)$m㮿'S6֊D۔.n:p߽{G8=.ܩUGM'R&Tc0)>)DxI!GV6~T֢Z%ɫɄ%M_a7GUq܍楨*Ta>L&XݷM|z>/6c>u y!`i8Ç}󛱴Bv^GWz**u69d;D;,hb+%IKgAU '0⬳]6G=; פ Y g%%֙h~ So>gfBItlxDfEӶ$q2=Jг5˿ ` 7ND1PљG"[Z75PUpM2K'nߊ.pɥh4K@wM3XST@ LلjrW,ѕB$؊S J(w4\bkE]EQҒәl㌯?_˿ri,…T~8zFL&ͦmB$$ /\WILTY*IXdY$`5$BaFM$zKg|S0T IDAT+2t|OW|:5_h' o:؝"3,)򌣘diTpM?ďi#K|5#%e%2mFl6uM-$זn,V 9dQ+)p3`/:%+f;?Ϫsܘk%T]O[PEsu?o_/fhxuLm!4R%-,%da-׋""K?SH~9ϪvYu)7a0^ vw"ss (@7bQTS=i}\}(FsBb2@DG̝9x(5oCڤ{h&l /˥n-*2 7ju|cJH; '?[o&]f6hۀІٴ`fȣs8V'HMx]@@a. &Џ/ ǶFȖԔͫ\ώzD:&6I6.$/̭%RE7MEHsHg`1_mDhxZ #~ R\//ca}so_ŻX۷H&D o4f~`I]9$Z~NޞlFTꈏTCt'o,UuOJ㨼:ڣݷuIl95Fؒ9:VZk{͸uHH]XN$΃w*=jfYӈIeZljJ2T %">rOILmr,9'"2O5 ϧ׿$kå8vY~yT׵ʲ  dđTԈp H  0ODBTự}@αq VP6n!G7yRlLƁk5lWEiی() d,fāj*&<3댭,K.B>Nmiڨ~[J&UE@Iaݪ$Q$>SbJ:S4R&J.^KiA U-%CQj Myo7$2LD0N#(}իauuV1.`8@/*_nO/`3T6s!`u@1:PobTHs/mިEOߎGQ׵a:Q|`16AL!Ԏ!Vt;LBD~ؑ7uL(pNl%VB-R`} ;N2nEu0vz\(EE9^|:JNnqi-ًq Oval{n IJ\rtç>yRUz*L~'_Q֯I2 F w AOXGt&M6_C8\D01zP|! [[ym Dʓhy¶f3֒04D t̉˝Xr:"I I.Hf?Ќ[ySO׾ :֡:΅^](uCkh>Tq oƤڌl q"}Ht7>OA!qHԣl ρ?GN:Zuǡ}hi!"wMGf=mC00X Ρ[W DvJ|g_v%.%5+#Lؗ\㥯x8q$.d[I4gƌ\ced?fa紂 z[px{ZWJǻɐZndj e 4ns҄ʺLQ:ɦj/)B| 7 mx*%ԁ8b;mp9_]?z;W= PS/ae= *5A"TK?Br]0z0\^A@zJVUMmzT-lz=vM~ys 6w%bʸYo 0d:HE=2:ݎf w)D|} ǻ b8u_9,C ӡTi.`&!!n>_#KB~@"ypl_rd(.R:ܥp3r"ҢsV ^ g#Ō\8.HśǑp9 @|~{FrvTCo s5dJ-A,PUٯOcu4, j?8`"x|* α'},,ae*2M{=ٽT!h&ޡ7u $cH#G⭿ 8z|Gb"[P i5)\`-\tH1 )\/o +3pԌO嶶pnj48ߚTIhnIJ,&hù,h35YXm"Pg:lڷ5%sfPki[`}÷|orn]ҵj߱ mcm_z֨P0AXG^P$]"H\Sd#WjyȠyvSgq7,WV't-퟊h>$u)'D"BL([}; fi^ EQT5~1銜8‹p3hu3 #W0%J> Iu(tRþ`?I6XVg99&r~ǥ@$(DerD%)@)%vq|˛!;6GxO[`X!c)+Tj!!&怞a1 !kP̖I(@ N ymnOrB-N SPw1@o3ˮT&MRRHG_(4ଃqpFw gĥ >',- ՙ7o} 9U0x8 g#QIGBDCɑ?rہM6ڴ#Ig_drـZPdޕTfY]S 13%!f1 k6WkOG=&=K0TX:v8 {F{w e#Q2{.]+w?o/*&Q6S0 2K0Vc@ B3ڥ$ s2H<#;%#;opB=P:lB;˹=KFঌ/R^w=0.qA!ɥzX8.G %hdW]mRaPlmA!\nW;Rō5wuCcě[~P=GP$hqBlկ6Y[@-Jbrf r1I+Y#,7m`%ȉthYK"/S R4;WCl'djqf8fVJ.ʀ%qB aDYJX`ۆWBDCdd;$^% Q+3>ςdL/펨Z1d7}Ϳ-K66׸hc4Σ%+2D?m;NZ>UΞ(Ί=rPfс% H)& igљ1:c\x16_a:"Q2n|Vg*"T5Dtͷ~?fqev@nMOZjf-5 [F*phy߇"\l'F5a3*. ]WrFeI(XUwʡx| 7 [lZ!cQ6b>AKKCwS1O9K5WJHM@ vfbO.=&+%wZ+x`lމb?ݘ!)( 3M* “;OS-4S&Gy0نZ+]٨xWKq~Vn[I6:a-~L1I#c9eNtY_:yFL] !⼋N<Dݟ%LiK4m/FϢI84Cw_J*KP6"kclw RuBc*j%A| ><ʯEhZoS: l7&h-M.7JX[߉ }̨,Xź5̆ > X2yoTBLR {ϋ5/'3r=ggSD_ͺ>1dGsPlb# KeHp u|v_OB(YeY"圦T"/*[s͔x8~RK\UƞǧI+Q98&uC"xz#m:S~'O&4sFh$.AGS <>Eb%NR1"X9z܏mj<(ģ\-5_ x_dZ et&MJwॸBYb RpZ!斧boQ ױ3 Fce;EpA*o~ҹX|!Q bߨiD er%^r%(=Ur>qt2a@Qxދ_t\|\ofbIp]ѥH#.Y;L]|ӃY&OhXDVň yƞ)m*h6}V>GȒ IDAT=a$}677[XXt: Sв҇ʲU7Z&u22-Pt",rF/j"'<')5R=9LodrIAS] ƌḨUm%Ka!T#IE;&$I.AZW-1䰗R{d'R_%ϡlC.;83b-}D-XWp4vPs+\Q h$=:5ZS.(rmEt\7rJb,lY-%#zuv)SSs̊1ޅh0e-'p)w)I\稽ܭ{n_|ZdA*o ʤMMX ?ʃ  ;8\י3̹l$8|@p'2yK$_%Aq\YD8BrigcCaҦ88vv~/dN'PBD 툛@$60t*AB'גfp5MLQi[J\d<dexMRJkJ;=U⻀ԨAڤ'd1 AWхt%Xaf2³^rT>#B^pMS'AYfwQb/IJj&^)ҡ+,̗UYl|bL)hLV κfhǧ & ceem`Mj;YLH12Pwp wO' ؙ>C*U {7G;I*)$m#`ߍ[;uYcJLsr=t'l̮4Ƥ NxQY2@s1`-\4(!ٗ<+q9I@jfޠ,6w=A-*q7(Q:TugN.!gJTBymjVvy2QYXZҷAefoʎrkU_)RLW7sy%cܙ4H,;::wȷq2ȂoЙu8b^ìVMb=)Gʴ],h]dNZ:Z2UFXI-W^,' ^<}כu춡4- S8H0 !/DdDvKop sfʋ]97N 뉚 b { RZo_9ꏮc?lTPGlt SїH(gACnVb8!=S`L'kJZ,/QLZ[.SC|6wrusA|'oo>Ӄ2qc[')86B(U C Ifb81] / lX: |>LIѝ;wmN_Dܸ$Z#` \[/TыɝT7ӂcر"Y\D0(0]2Wȳu (*q֢$Ɠ8'Xש2Й[dԅNAdE=k@;/H]z.bY}+HA6\ZIAE;d@N݇FSl̯2{M|'u)x2/ע+Gva#I@ WI|Rn{Kd,'6VO2]_pui2b)U0YnTPUe!dkgL Sdً%ps 9ڎ M{eFD"QEZA\ 9`pf\|: ]^}bTvh-B#- N#xln{ Rڐ9Fb JQ$v~kNWD{us ERL!dڀvvނ-"|KT!Cwo5v­H$QGVcA7a+{Rm-.1)p@y[q 4&SU)Cktt)"#N+nR)=;mZjooabЦHN eD}u:w4AH xΩkNIɢ G6\#y£d#j ~8zôm}<T ֘QUm XcExzNoYj>Y!S,=#ݳɧA4t| RL<겡h4O}S0P"n%T_/u\KqKi6#mhϧ܊ҵ"ɶ &nj[p$k;W8J8R'df0-Oq,Xl=k+^#6r>җ@T[.X Ef3]5LsDnjϝvq+Qv,2'n cuP)b$GM {ad7>!Iĉ,N ]J~K[9h~ddҜ'#ZFViHGH:nâ "|Ww/FtY8v{R֬TkP ~:toE`awW̳ηkB3P\ITV nR1w׀K3]s(bnRXdRaok6ObBr k# N7${Ό7 ah{$M!s/PGEݷ9+H)QM*(A/F2^Ia˽gHQ) '*r98VJϖ𠖪H:[M(:zD&꺒XPs@ 9KѶM!aĀ6uhX8H&ôCjݏ71ҴĉDjs^:=9@޸rK OYSmkRn]E,B2ճIE%؉iv&Nf"gxSAC>~!dD<".&Gy Q1Ʈ0mӏ ;AYt3Z)J;di ,6ZPPU&+P0Fed]!EC70^$څ L>.a6rTʇw2MX5NOz&U!X,d+yQcf㠇? X JOtTuo2GHB҂ԿL)~K'x & :)=u2\N< N0pZL"u~Zu zOrz:M=qЕ?n0qunJThm.<6oކdLci6ƅL*-Og)(l.pvWHA_bG_p}VbxUi6^| x2v3PTЎU]S1tBsB`c)SM#*4E-M]ͨ}( Ej j-Hd8 QYbs4զ0gѓ;ڟ!9](WK[ U!P\K+8όL4)@3NRcLgOf'GKP=Ye2R\6#.6]ԗ8\VCQըilV,lpJRǤv[耪YbG!SJf YsѠu>A( ;?1 ER] #y+)A]ݙ1DP1^փτ͖.厊dZ)Py‹}\"$Lg<_ !``PV@'./86N]/ ݦ Or0䍩 2ȝ@n MYsz zu?=/,X XF΄=x[J;YKtGoNMLe8e?r9ÅzLrܴIMKLBP|LkT豘RىdL,,6k4s^LUFS`0XA (Ι ^rJJt: !mfih&)7sV=L[e]D_{/;Wзd#B0S?uooU~\k!!(UPKRZh l6XS*H/bC0?ks1>7JI~{s>Yk15Oj% tTJTI3tJ뮫 )7_N.)$ݫsE5!;c/tI{|Omv-.ѣ #Ou-gAB o/ ؗ^'K,J41#+\4f>@OSHΚtxptvPWyH4 U(+Qn5iYJaPrpGЯ(GIGj)˹^ÒiF3~w+&i~"l*FY&u14V8ɛ9o>'ڨ9?\}mŝ ? zbǨ̜hw rqa4lze߰粜L\f#z'( a!qf0u,/ }u GO(4)n g\tIRZpY#v^2ryD~ˑެ"$OANpܦ TP ͟%Ra,:R)!)!kn}1y<B|H "\c,|drZ"׹ӛJNNB1]R&8FsqJzb.*G:LD)wg.=whHuUe-Z*B6Y{2ub-~q ?[+W|+х*ldn[8ş(B1X>!i@4dĶ넡%I!/&ޅu/~o%f;0}oQ Fਤ0Ɍ+zqg;ar9 ie(<<߆F8?.@D(Z@Jj24\L t[= }"\f`4*C!ʋ;-E-# Vl(ŚTeepOZ1,) ׎)B;;*7u3벖OH&F =E;f- ž rӧЎHm\ٍhڎd@2$7?"}%Kb<]E  :ܢ#Rex%8ؗ}>y;!`>_#ֽWo&i'īR 󠽑>arTĩB!9s.uJ:r&-mO,#M}N[֩I1҇4I]]bd'غܽXy(,Awn*ii\lu&~9޶M\{'_?9Bݎ{i\D[HbH+" V^\`|DmT|2 nC(,{'r4*D@ވݛӛ{ W7̓Ct3p8j',m:8v7lV4|Ni'hHu47oZlW0x=0UIoI\\FfIt[润h]ӷ*l_,!y6NiCG3z1;#n7ءkе78 LX0>* [>A0̈L]@Kr棛`'p#r6G;qnjv4-&Om;-JbStkLapqB/T'* Z_Y:f :dLF,pQPEb: )Rp_f g:X~֘ ^A([t1E]T.~j= vm=TK,eZo&+7[[G*t0  }:fV|d#׹n8w [zRqp2Ccٴ\yc FW@'=`?T_@?Dk2MNZid*&ׅfi Lkd@3Ȫ{'6 ds( :vv7o}3?-{E?t@&fl 8o셚8V.jU ߄n8hGwbdf<L7r_% tc5t#-Vٷ2c W;}1wJdgu@HЮm`:$R++k8?ԟǐ%\łeyI]l jp`/k6qfGQotbI\$N1h ࣳ ?;ve %Qm茹+NvBUDTעO7!6gqIά?ˈiz3^K8x:vvBSQ6Blcz MiЃh${4д`&cR;9+_LKN 6J6LRPPN$ā0@ WamE{ !ر|oϊ2YGccogX δt4j2MwgBiNGѯf H%*]pxHDGo_3|< "OfMWߙ9.(]1HTmCbvu{W.Ua{_BpHT@X@o";E1?GMVɏHsR"hMڥ@2 uk5Ǯiܚn IY;G:4- FN֝q;C)Wnh6 ǰ0 Х>]ӟh EQF'ߔ1o,JtGO[:(:5"3eeJTr_KX)ԫkx^3|הC%.X(ѰTg;*NhH 1b}+7oc8Lzy1kRw5-tb&Wz).셎v hޔk#^@,eKhUC+=xg“7-iR-[ :0<=H'q>՚Eo8Ѵ_on SU<)?^uge8[=\AJd\szGgkKN&TNij{m(D׸PZ 9wԻCP24q-h%*_2Y[D)z| .v2[?û7kN!\Z3E?FBhjRҝ5w3jVs1#Q2SD( ^RE5^ 1}1l#h2}D@2Pd Kj ƂLLnT˰w8dʻWjP۠;4z0TQDе#|/A*ZrGq'*ڨ4]Uҝ4K~LZ~.=xK|i ibx}XC &;D9 )e av^OTXb\*[ ǟa!w <)mki RTARq*O#FvN,r]TNm!)S~W)oX#GVN~RaOt? @QKMu0Ro\ōfʚ_np ը,EKY2[Libq d Jo\Q| 0+ۡfUr,ebZXr=Ou+9p;=* k%v*H յ 5SO;F3Q3Eaww4 տ"Y 5c^q%{E( op|g൘B^JECǰsDfSɤSΒS]\ę\W52yd ([8I jkR|^1NQX΄;?r*ٶzv9azK[vs6qw{|C1݅x27pwq 9~T~ylu;4.w/)[1sF/CkRLsw36*є.e)"5ٟi+,&^.@7@,UӤ߮:QbڦQ2e# !)Rwwd;Hv"^iTj x]duu /- P99z X*p<de҃xź*4_K\(fa4 %fPh/_rg MLZ[e<׌zzn=33=)YS@:?aj ;'8 ߂Gu;tV7x5,s\%yN4rmhjZ8}>?tqfv@1El,LtrPQJZv/•AG=4~|5(^lgk6KPf3 cjsΒJMʉcx2ȡBCԎYm`B]U<ȊaAg%=嘙6qTT#[R3uyǛfk2_(LwN裗`3K5>Yz^elrb\8ۅ_#ÀQ+2]C7$ߋ*DwX5%3. $uqE01D+(}Ͻ(%@uwtRyd)A4GgrQE=6E_]&ԺTedҿeJ`0)mF~߀o{ds[Rgt1/8t;mE*e3,39l8%4BGbQTȥ"*mv)>Ԍu-=׆,"?ՍM-Xzh bO74k /K{,r:`ecK_ Bs  .  (w Qy*26{ѯĎ[>CJȶc{8LGJ \ao=b BA4'{ح%CQfЂ3\.J`89ɵ% &/^b;uwWWK0+ ;RyS";# `;.0/z l%pJ' R( HOKq4w*})P@0Y x7GX#vPcu6t2SOFjFf2΁v0t5[ܩ*Og` ~[rvD1o=}T~CR.-?s6?7݄tK{2 x%/ "Q(LjabE,-@MN\=@ &En=ej wsyYFs(^WeG$V͡:I<J|h^'guڒ!08b'@NPh^kY]vjeu7ݯ+Kj`Ĉvl3r[GH=Tռnu,=&atx ~ }i\&IF;3g΃[N+bB^4fuGr"mg5̲fY8feA|MhF~W/ 6X#sg;ŝ$BF_\ BL+x_o~)cdvΚXN-*'h79jlErhhP x|qŕd1 !qA|֯Oߖ4Xki8HLY~YgPGxrq4`Ġng= Vf)3:.EHBdא9?i~0 n/'=E-|iXnU*ɻoJhwXhrUeIH!)e3~Fz8kJoL%qL7oF?84H|0=CcuýTwjZD9!F7; ʨh jrvI}a@Rrr9(.dҙ sp ,bJ2:f\_H<dWZqyFU`HPs#f. E JչнR]eDᱩ':V'jcN3v4~.1<}aր.P 0 L1zD )MUP5.o>GX);hFڠ*ŮjRgg,O} 2Y[; yb0P8-1슩d+U#GeĒ+1_[R9Ρ:QmG%VK,gmY JoZ3(1!4R좞}̄)/R`@\+b%Q}̜PڷHBo=EJ ~-o"}#5F%zƾV2.-xf[۹'k_/PxLgkk_o:z 5vNLR(K(7 'G(OaLgtg7n |o'?OMqdτ9SCV'*X9HKujULL}6Dr<۞60 TPLejtTi vhLԳQf(YJ';'g[- u~Q78RTr- -w0C2"qK4KN(n(J IDATZ\w̼cݺLv yYt&LKzWԕOy2jM[߭MRA.2h&Sc"`oۼfKXx:H^0*TGK݃ ^c-9OAllo|OiG}czln>:2R/ vJ8){>FX\n_#_SeDtwete@o/I9y &8vQtiB2M{)g.[SܡGX7DeJլ"z# Ejz"P)%VͩcEQ!M7BLVц7=$p]#VWVqů'ox5V H]b+_/JsZ^f2MJo矇ի0!z,-&9"J[NaB_qyq0{"hDI鋠yZS;,\j-g~0zր'?mH &ږM7b3Ь'z8"C2e.9^)0re.EET!J,ycIQa,1~?v9n;H-swZhw62;ug(Ep[tkV/ep؍K–@-vE-h*nqNI'*p}}+_9훁G׶Me4dş*i!`eu Eqx7=h2#vwlVX,٬m x+_+r&9;[x# g^ުY0GGKrxD<|ECh9j("M-0>?xS_bmĠFbkr༔p_qz`ry5&e۲JbT%UZP-`U#a i5io qa=|j#ȿ; HN b]nb#.v1]Y#cGg> ~stRpl"V76ql?ûx w~vw0 cPr h\8ڶE7/~._c}}qPC <|&N?R Sgc6pV^Rӹ8^n{Ϟ;Zi>&K/ɍ 2itm* ia wjrKQY^{YIع7h'{*w0Plh6E:‚՛JFH>q̓[9lC@f0]K2[x^aXDw:SNQW2ZDsKgi%lNڮozŋzG;~=/؝C,u"+k嫰F)( |/?OvwwU<#=Ϣ'*cqGUi iU7 yz1Рz"I8WHG/ Ɠ٩|o.Cw))61!摁W_yiqż#`Q6B&)DiM Jt霶Q]~ NYTRKWNv7]`2{ykOMq.F41,m6 i?0z4Gp{ 4)ϑO/x=?]X[dmv=8MH/şgp~:?hs660\rPZ%pI/cƹ dQd_ fbm-EVH\4Y"`+X)XUa%TX$Uy)х[B4.h<{э&fu'tάe(trX<< Y**hbRN.җU`A6/aLBK(߿;8}cE6:Dli"B)m,uW!\) JzY' T@b+/4/G C/m7N HLf+l78@Bb* ~Yŝ}?wIg?,.)lUѺ,aHzCyO%rfu?[+FɆXrX w נ)B@@]bTb'@ =ʛ p;;9)<  ;iekx&\>^ΊQޞ~:0G{~YU ^z7 ;۳~g{eZww|o5Da[U5 Շ<`vmM#!hF ą^vXhDHY0|.՗]Z;\ Aڜ#Hd:JdM.#gblE8_ٟH:9urGonQ#YDT4v{e4|GV>70uE>uY8\uI:DžTF30:4TEYH{:o2, 2RlTJ"$Hv`qX L.k)s;Y,+e_I܈cܕrY=tz>:+pNuSyCYIRmHthB4 mf0tB7B"qAAsٻ= 7\kG9д:QF6b͐kYX={џ` <&T֚.!M Klcx{m-7K#KsB{"Ն,&NuqOaR  qXfkԨ|kQT╜Şѩ sU* |Td~]h~5Q(]o}X+r pVKayo{%r/l7G@{W{ݫfi#6B~0Gލ/4Mm$ă$XжM6-n v;t#bh0w<[g ; Gat핐EbQI5[:k9xզ*$q=oC}H}{KLAVڳX7`)9k2Q_Jv T$ L;Ȩmq! loX5qP6;D؏)n3 $P]Hal5 B뮢/04$s4qE\b?V-2 aYϭ`%H⌇7߁M̷ ͢ю6A{!0$L&-v9h!'6B >8 ?phPCkulZqtkîܡӕ5/9/ww58鱒i S H ̭^tn*j&GADk͸`T9 tlN[mKTza͌Gm|8`ex2)SAj3 DKv+>؎h!ùV|~&]).=jv,'_"΋m$ƈE?ǵW_D[_n sb<B4Vd$4c /bF7)Djyj/ohxmU_HR9q(9 E I0#DfQ8Z[(2 ߛ\CuF%H2b`iS1!B@C\,ʿK\,^_0Ȑx7/IGSϔ#79,=yޯ4"[3]zERMWLH%+v:Wɬ`bHś)3o5Dh&7\t!_4)UTԕ\BaڍC_'yЍ$Gh9~riݮG׶N哮 ى'r#0ai ̈BIqo!o4`A1~Lj"q1G3, H'pDC? ʐR4;Jgc( ({ށ8]A(~oBí>OgaQezһxbqS WVeODY"|茬g3D8罓/hF5J_"4Mu\zť|+Ggr1-c?~'BXLw@!0@6?>{5{{#9q"}Ϙs`ӍZƈT`fGHCd):c?V. 4̌Sc锚L )n2qiǜv@"BqȝfCd@~RatEٳ/_i %j4 d'`XX=5ő0ʀյu~?u]yiH b# ,.^c|۫_T\L= iS*쏟ǟ{kɡWcXaQpCYnҗj L~3h]r5U0 i:a@o"Ж?wEmT극"\J'|RXXf"ЋAu^:uZPYJ ׈{c߳ blX }gt$!APdfŦ#iF# 1 tvne5Z_G.ꦌ6Dtdq@ڍMtmhc'SO }Zur`)x0D qa٣>'yH'RC⼕Fk璥Q +ǘB|']ע>I(jf:şc6pMYGFulΑd2'Wu JH@o#ORҌ9\hzw\c9Y/XXm|H01,>5Vׅ5kfcRe9f'f*"I$O >Bi&oFa4F3"h3 ڕUlWج[YGne:ڕukhWѭZ9=d/X\Jzao|ѯlYX#M#W(!ȤcVQ5؁EMY(1O`UDOVېMٴ:n0#&`7FO&a;*!ĔH`OJAj/)~!PGFwMX]Yfӵs`Фi =z]F?dJx6OM\1 *`Wнh sc1S  kzT c-li*;3KS:\ħ"2 C"nMoVBI)@lG`ׁ!9tHx*1V$6lQlURysNV7&x慑WG$WbU[ZQ@:[ R Y@4M7{iFBж tկN;Mza=Ay .|2Y]4t<l~AٯGSD! ILM# A:q#tFsĥ::t'V^/ FbdZKG!E&)Q@vDXEYW;=ת&wFcˠEd :t%K "[LRZ u@dױu V~D!-k纲OWx>>98x.p444<0BŅmD[xk_if7:QO'~'q)taA۶{kyӡxM~7G+KvԨxy2ZjZ\ye<}1Fz%DMԽ6DUԤ:J&7,ÒeT++oP|`~윻 L-W :bc+sޑGNs7San@m?zNT' j!!z%$$$_ @axފkB*Odg_wh'S&tpG߇.@*7hp̥MX6$O>?5XƱ벌8kY6KW^q~4$5KTJ!E|+ ڿyDZr"_deeׂ&p#x7jǘk,HT5dIvH0l'cPD#2z#Ev+m=odu -/YY?(q&R梑tM [+oJO43Ҍb{)/{p# bMkѴm+;;G?gou]Є)H"@LEBM˘U~$,3(.O~LF㱈3ЊD]up1/04@mF5I|b J#py1-,JKфէ rʏ[q3lV제$BD滘~`t߇ 8fEg~~& ދX?*)>LBɔwR-Kv->sɧu#:x0wKG q@фM]L7jqbOoon4.F\َZZN>7ܽNW X/6K2y:JTBv$?9Y~upW.{I8LhRw#ymO;ٚZ5ԕ( Os#-oQ2].ëzijl)tB*cUqFX 04L;}(qoG8Yj,.מ9`4MHpCV}|'8Xaiq?m fvƇζ}{B~];B׍3 <%7Qj̫v$񡫁+"+>%icysq}StUB$pmHd7p:N肝M$ fR.5C_eoa6(ػ! Q7 ,LlTS<.sG5x o9ފYO3 7d *VM8h-ӒO.W3q(@&'&ł?tĝ-].fU\t6EfƭBR5 !-1$tHIp (lB/$=}?b|>|>Ow O~ʓC3DQ7/~Vշ2(1|+>'C/#<۶d3JܧR\O3x3Ý2hT5YZ@YF.Pmܖ;n<[P@ eUUEN @鳍AY?/|iREVoO&x;MJ/%&J}!0l>;ު//+6;$Bh%8#8k?s 1E8NqݍU d\QiH]vBvs8G:R_,ϸY˘x<[c1=~/]̂ł{{{X-4 & 𲗽 ycplD!4:ʏEXYYKXSȽ_ܝvQ<̶*׷sNUݺ&!H[E~(Hڠ( 8ڶbCTnM@@ $a ! @BܩθZ?i}ɽ3"o-yD4]${2\ё 4zYפC??Mo҆ h:t6lF& M&L'4JyQ3?A:3iJLG>2iܧ×`Ώt5H B7ȋύF!>e~15EqRߞ@Ghb;V8E|hOJ`r=dÔ سViUcwHۊ\5"sNvŧ)t1wL S>m4ZH2}.F2N"Ui1bk XSqWȊf6^rxßqrP_܌\"DDs # KI\0D涞*O;+Ϭra/J  G11e:x2xxp*VWV{n G#+R6.mRM~[ɲ ~+*`~ /Jf6geqS 7`dy&BE ρ!#:38*tDdJ(7sjO!pn S\&}`X,)7*L2fc R* ^!6aJR$T#m)j.Ҝx$"aF'IN}V7dȬYQl\B??a*Y~>q{ 晑h Ng%?3JbD[«^*EQkMxhx++سg;q;&1>яa<(M܂-K(6q+Ϯ{P{"HCW49@3uν./\_rkIС4I+7_3(RGF'R-G#TpA^[nI){`٨OK2ix{ ZOQVS_&8mHD M~w8P Sz vo0EoiI_\YYlF*2Iˈ} qewх"W>O`yWEԁ\b ֊VNVql\~wĵH>$pNBכ"׹@dqhCzXk)0nF|"S7>Gn8M89jI=g-|`ap&Ą 6oCW^'>σ< V;0dY[?9xij^xy:E +J5/rõ_;oʪX:^ PV6oތ ԕ袋43yCJ9O(Ag1o=Rm%M"ƐL!q_. 4 ʧ>K&+#sϭ ",,n‡>nڿ}?WMF 9W|TQKѱJpNz\W> {bnuIR UUPOoEzL'2& beE~/eYD]xfjcGP4&u扣5< ejm̀4(LB LTj: k:(:mv}IG>;}\xc:D9[< GOw)Cih]u00}sV'$xK/WJRo8xqn?goܒ%{ch'GLF,h0gbB|;soWgy*{ƫ$콰k`n!]e~._(z*)D"|s)^} zI[LMTU/[ /`G nXNVZ 󛷡S +Ry A{9@f{;OsG$fCjg3`xEa(!""q ''/IHk|PvNcX,@ː`t 1s|a |}J4px/ݾCjD2s#Fu:IJWNcOeF١t`*z%Ż+FD&C$Z&2HT0QN;2f&ˈt#b6Z'9㑘/)(y}, /ዯx^Ay0Tʎep4]=!x+_|M7\dYdrd[Gꝕ$OǒrmǩO }a.9=A}߿L>q̹LY9LYJ\}r1 b/(i~CYU4Sr_ܡl/шhQb.ʩQ+\XR%>@9D1lV|p|,Kf5Vk|2RdB, Y%L4aOmA?BkaFEŧyBU^x igBI{I[qSE dg'ƫ/;v Hz>]ϫNߋV{xB2LFغdz [L Q3K fweoO8[ s#O yG;b M再f=ث&#ȱ% &ЬW\H8ĕt)va ^ yfNF+]$䃇?LNiㆈtD!uA'EL8vHJvq^4^AȎScM Iů']ՀCm%ͅO?[ ^@QzqL[AݯDQ2h!މ̦h?08մEpˊ, J")leFfghg?a[w¶j 9fk ``Js\bfwɔQ٥T¾-EݿT ™yMXv[^1@း ϢSZ;r0:ؑ@k̡= t2rPYZiYU5LQ a|&S6|uOG?h0hfSv~ aû *|8㰷H"~MMJDHHcդdש \dĶۻ (Y>kʌ-EC%`]O6ҍzgAGhO^pm@9 8o#)6iPɐ$9P땾/x&[ BAnSѾ+EQ[ތ42}E1(XRR|cĞ$QNd*M'G_l2k0[TO3.{q Yz%vh2&# 2v,`YE%&Pd&l喷<΅$uajqi!v}o`+2#W`fh~gI2pLfq괸f't[$ы5wʨI}f b%aA:!QG.+čV66c%90UE> W\ }'i^R 7]XG뱊VxoڂTm4-f$%$ad96{_cnq8Hm z2pť,AyIHPy< uyۺ=s3%hB2Vl/x̑-0NV[rQ]ٻDqIJ#;koDvFSLH3"5#d]柬NFԆJy&brncHaATBksd9O~(JHՅv+5)n0q)ІPH9p Q'ڬ GJhQ}2w0;QltEy"0u TLQE 2v2[{,cդ??ξF{8zTeOݓU`zI]"UMd>@&ol#[[">A 09bXr':S\*Ғ#fp$ ECfb`?mRQ!YYs)KW8KʖVQF1%tBSt}#923U+/[}$vj,2xeXz<0X`[\(LY y^1ǚ-4s NѕO5r\ãb=;YeSP.l=j`N[yE>J.OWd477'?:8$`b^ YohŸ(\e1_ '~ݸӗ?C`=j$0cs y.w V&S@Q H IH+W IDAT^8]tثІ> 2]%H V Hk'in\n7@%)@pK$,b$ߓ&C{XL/;Z +8Ȯ!b ީ9TG$ԑ~;Q-c"<5H}Z?Sѐ,gIm9{-_ =$wIʋ(#* ;n@ܡ'X Y\X?Bmk*X}cSy#@Vb@# z]#%a1XXzs0K.Mh1}Fel:Ea LUzdZȔH,㋊(YOVIڑ1"n ͍bc`-y/ef|hvo!qʉc%(X5Р||ȗRd(+ hjp3ų_JMAѢ&MGaY?A7Mk[(a4\U;o2`~ vnmќH'mL]&SזhW UJZwG:cl!jH@iωnOM!"oHw8kǢ.,\`ʲ(DށNޟkhesUh~?gy]{1j1}v_f<3(.H]>RW85!BH^__BEm!^(a!xʳ_fɐPe*v[}MLDI!4CjUoq s tח?tU Me޶ljԲ 0eETڕz0eTT^ /%ԉ}NyQ)KJH*)+h:黑uF3.E^{-cްmm0nyÔy0" s%3wM&+>on6f12iB-̆"BVIO{v$j$(N7H I ;GK2{vƗ?F4%.< M8'IZ]ݭr$""}z4 bCju.\Z k?Ճ߮kq Һ9 #2j fzt"e0y%,aPXűw)/N i,~q!Ң}] gL*8"ӷJ#"gM% ']Au0~kz68)`37{YymWD@k |V=ʋg>w}%ۤd.Mύݸρ`zws0b p'>װ:ܓRacq 6q gLB,jdۿ֌aK֋ ۘ\ lQv&1{̓@B ,AU{0uThYZ۩p/Abb/ɺ=fV悒ͬG %mcU#hl&/wR=Pʎ =ڶ=`iuy7#1ht[7_~57Ohw#Aq9+p+~J’UjT~0b$L1;K2 !z['C-Y.%XܴV$W:!Hs'j[. KSTBE90eA.`W!q[HpR]+$?t4ZF,ݯ_!v#aRu }K? ޮ͕ GQ&oe2viE:&X)Jx8LedYU@})py~(d6s!ka'2Πx.J/c_ '}94̡e^tKAL'w.eE ?mBp?@Kˆ]QTV@v5 [,8FTFJ#x1䝺b=N]]Q`Td4. sJ-7ay}s9* }:cBJ q7cP v06'hy?TPZ#k auy'~eɦēQpJ!'^.UpH)j<aʍ(2d31dCdtDU[X^TuT֖pe\h02H^k`#ŅD`k^d^jƑ?i`9KaUl<2 3)5S |d.P&̴"X1A.`Kn,P;%u;2{ތ|ik0I~ AS?_ y#ѮD% +;0"zPPtECw6lkzTӕ(b[QLrxLcʼnK3j1udzskPyNdT;l[WTn<&?)O}"IHG%1@R 7><'i:>rWYЭge d4ҶQَj&"ɘ`~VQ5Au۳t<\Y8?NUOQ3[(VSRA |z%P2h% c~㒥קz S: +.9GT5c7 6 yIA6ªQg#e.b)2V25Ol_Gc.8SX#8v^wg(M1.x, ZnIA#-0Z܂s#}+-4h[07Ԣ҂8R-Zim=[@u`KDm uhZ&}F NdLӟ#^`r1[6AD#tPW;zQ~o^W˒Sxe=!N-AHy"jd2ke 5kM<3F}mI;ِHٵ־k%Ȓ$ɟ ?܀2~4~*{mڌg]`9"ka tb {ǃ_D6r~_^?G^/r΍i24}eqWFUs-ݪS6dNJ$W옼1ņfP'3wW?qT1$g$dc.9(eMz oz H4&cH|Vv^̓a&"4k=Q.dC4X̟[e>̞4slF?LnqΥOTؗzt;XԨ%!J$vzA͉$߃M!Auk*at˔^ypa>vo;IyY*1h2\3_Z%ACєGE #^Gq!Kv8ijq~ WjUY + 񴠶s@ &˭zds09}-.䊋2ɠ}^zEۧܒNxrzr*֗tC:),#$IFPZ wFԸ bX_}Ǻ5uxKƬK%riIYO^Y Bsd8W'ZM"QQ|!r@ay׽ɗOyÕhh.hw^Eqr}WHE(@FJ]{N~0JuVZ,M[N~eyKۡz0-(-kPUAg:#{}I.:mQg2t 5\ CшPPjjȴ-| #?sayy'Z6[y+>zcaqfR$߂)3h6E{ƣL'6?:R#]O?YcQZK,?sґF]eIގ9`/rrV ))G-NXXzcQWKN2kW;iv|tZ Wq=PҚw9q&fTo r8&؆QChKs++1(ɃLj jŬ+4YTHNg7m^۸_Eݟ=!h)&1sv[o d"FWVFsWKՋtM!Ѩ|w \*R$ؽifTyJ!Ns I_m~[hIom ctRJ#ţ8u]eA{-}06_U}0Ig5Mz^P,, vI`r{^;QnNؤ+R;/d6|Zlr:SVs"S@^8tg㳤$89Y9w c/ 8 $Ik\R9AgB:5w+7\-:^D5]7HAaz$u WCtєسn~ ŭP9GD':JH`i]`'],E|So3LĠN毬uўX>3U\jPFV@%/\,PLcajap}y% h!L{m~7&&*WNjP(l 8-vU|3ͦX~ېo;ɛݒ$}x>gp]6KJB@45H:Jh$~,$"۰ W.'߸&3*Q"7E!erg]TDeD7dMz0UϦ0]Ы᥋ Q%E% nH0Rqv:aK\)ʅO%/0[:VRB)- -kns) aW]n'нrɖD )`n~ŎݻS\#<1&֘۱+P Xa?|хذq !@63!;Lk BeB&#* 72U߇3SE[ۅ`le@=H{: $ֻB;U`8e=)JP_##/YAr;AmD" zt|H%);إě\0U QM$8e߾ }P44F@hE^ i˰13B1Qg*9E8[~W/$ibʺ'>n]aaqI'CBY3 P3z2ڇ nfr %Ȓz[,Zn2'F!)=MqCqjvj#HR)icf7M #MVDYc։Y 'x+ݦs&E"ܹl!0d,,bׅ1k6| f|چKs1.1O~a2_<8ܗޫJtVR-`_>~_ JOfm'O=nzu"Oe ߃e8.4iF:)Hl[20u^P~NADRcoc+A^o :z,Vˤˌi("H8އUe߬y5-q{*(!}?d"?+VM.t둷5ޞ)k|W/^$Dp <{8f:*hcTHETb>Q؟uds0)X¹0zM*IwZ*Ջ#Obh / ʢjUHб}Q T["4ȺAzL" ^"T<^_tKz ꀭ>W6LQ`;!ܒjC8KFf hWv $#"[D!ZCIъ?S+u >-" &M>0l6%T=L#J䡸d͛$oJ7Hzyo!QK<Ԛdy ^Z|cdG/~lQG8 yw qRF pls_ÝXen2PokO&H0ZލG~aLJGØɻSbmOHqt7 IDATpFU!"c}~ 6hh[FS.RL'~d)Q̀TʒLa.=FշQ#er[e-EɖbR ,ZN aOh8Y˾z=ӺtMsS% q3]?"nDxUX,Q{JIqnI#^j F$@%7| lDP.m9NMaߧ#"c\XzǞ*t%a<>ys(Y{>B17rF|_o` d p.ud Dׯt}B=?-.n(]Wax _:t{N6֬A;ksAZR6s U/N5 4%Wݤ(4"H~#R{O!ᮻLB7vk'`.πA'3ofz}m@IrC,* S 6tEb~^yH_zˮi3H@ǂ+! Wg>ޯ  hf-qA,=)E,#~CL\E AGV~HPȠֻ^8ڏw]o蕰UIb~ EO|^\A{$XXHoqJ qK 29y-0D,'D([U[0GU5&wMy6iif[D f6Ca@Sq/EKW`yqs:g@Qs=G-gV0kfؼq+,Fd5꿏 L㾇9xsp#,I2 ň h$JlĠ^{25*cvuE#]U%dBҰ7q0 F":|}3XK"Z3m)=1m,C>oB :RcDw1r .NŇ3~n93 =Nƶ()K"I&#dkrruυn]aOD |qi'#zꏽ@nALz):Mb2®2{=b(!# Xb@p8 h۶i[Ojm(x9G Us+喛}:Oܕ#Sd{={9ȮmH0A} t- s( d*IJijDJ`~^#d f~G OXHu7a~HR?8(ԱG4nRdH!do0K."ǁ`׸%j@]K3vACB͌ w;XpGE**PREcsNWl(ZcW glq)\ rƮXz<;aŋ1EBgK[6> Q@pϸŷ1>ϡ72 7 [߀O5,!Ul (K8'#dtc%/ S"כq{a++8y‰g~=QN Q$haScYty7&+h'c`9b#O lVv%1]/(;pE fK2=zQEƏ! RJTddkl9B/r_!2 ^Uyn*f*v ȐTYU/~*3&,ꉽ19h$D]_b )3.$<~#N[TU{ ;4W9F݂oM8E/xydD23#@Lm$X1m] 1Vm|qۅ+T~r.K:/,-"t =v >cd_1M_nM(uot³%:AXC? xe7R&mQ^Y߅c2\cP CȯkTbkd<Đb>7]| Fn^? )+,zu/v< k-^Sv-Bu9?u N| V+ň{ȭ%O^nxltt1fa:n)/Id\ Tr]l47{\}|3v<,h5Mmɮ-m vÈ?XZ-%lbqB2'0LXj28:@/&(\KayWٶtltuW%9=Ef:A;:WLӶhe313VH#ͼ ec X6cr1rޱPC=$+$pƧ\!GK "Ss;{G:KwcI3EBfSm;~r1oW.>Y@3 l\ %D$Ol03E'>&=q.\w '7ZOIf(yԴMirm(o DO~,|x]Mӳx9;9UQC2-R\D=&^]OM0yZgdWpC5;xĭ&KWBX0fR,mAIɜ\:Z*qB-smp`zWsBVN_F"W|oCNx.0AyfrսyV.,ΤFVw =X!u!c&'})Vwn«!Ĥ#3KO-ㅕ.Huf Ci'"!mk&.-iFؑXcU꛰N" CVp8ȋ Zfڴ9:7aĽsq .,Uy^g?yN>h6lG: o@~|H9<0X-m2&k{7 SGB_`I WfωQE+fY$`?Js9>wԆ\ǯ)*vh}ܰ^2ꂫ`'HLgC@FCH3 7ĸe6,|z9o7y5m$x8J'YVFL++ nݐ,YOrnGC,j ]FJ# '%g f/f(tńNo:^`x(<F3DÝ].,ΊF]y`ȕ?+]3v%vDp׮=;^E(ÎEƓ\NQ (-Э'x㿡($-(4ӆGNS._EփL!Eخ)2*I@g.܊:CFWu_""5oI1~  _T-m1yv0}2I6KDnf6 ׾ S!$P٥(Kpg] y1D;̊|̭[Y]z"E]HaH1"&bcKl(h$bƈ(Q DT % M-l{̜3ٻˢDwgw9;_y)jaӤ*Φʫ;n0YZM 勉HI(9K$))}ODS ;HtA4<k4D2ɴEnOjA\fs(\ΧV[/`D65d6}m T#ĕ0r5<<'(;3QJnJMχ8cB4.G0_V~` PMѨ@0EJmX(eB)GA ܶ@4 D7'&ˀmh:t]s$\ƘQC*{:=!r^ IDAT _ S0"}u/$)s'iߒځ1h.)lL"\+(ބ2NHn*HJk! c6I K9X1gFCj4++'ǥݣeY[\!ԓ&i@?i으 )9zʂV@R MR8:aWoĔtjNe/wQ)=U|㬣ƫ(uG$V(%HD8N?|g #n"E6sĉcf:$۶I`3N4@9= A`7+͛Q$pM@ tRTVNG /`,mɧRdVp%%0,UEj0^0;םL !r`e>FX4sHҾ _yh/dzP+RK˄ I`}0n%:QBt0<="`4oTId/iO;3*f^PGNU s$%&F<)L+ V?l*qNS3bqPQH*Jaʚ˱9 |ܹO.$dlT`I>]koNAAx h^/44^P=jkkuFLZ!҂6ۇ֫U|%U$^2Ȋ$Ak dKh2k8Bj`i:`ƹ$F*`"k9HR{V4YVRГ :bx1 /M$bx95hj"1"7778I:`?Za]wirJ@1Ӓr! J)/JB'h*nx@ /X"[fmf;LoP $FA x|@M螤OF3@t$it=Jоr$F%\2 -*`Z#VtFOZj\R4T*HjS \=<%,pL?#"$fCiY$ywƖ[m)2cFN`x[Yx< I"y\o08oǐgwu"Sn.KS\g`tp= a6dVf;4, B@zg2HyGrDV%5G "m1̝!1b&_{8>8'L3TPSoi0_cŴlx0ToDZfnmp?(ĘN-%τ?Mwt "D5_W²$9 9 Bq$kYEO.n\lRſ ;qMLjS\)dXz}m@E߾}x<٩H=wy9Ӧ8Q5Kg6wp<$Hx!sTͤVz}שszUp!}1d%M Fƍüyd5uuuC9 h>{Mm&8p ,X`c vܸqqFOַUд 5W?G}#`7^cRRT\a>J o/|32DV48R#GVUUH 뫽~0oA2eU9P:ξE$H*QeX("/z3YMDTTTD"6=5\ݪ^_mչ0pI- S2{! } lKf~WCCC49y0ߊi0'pJ4 M IO)-j 4z챴pH҆|jF nA652dSRҡlj1;?gs"0L |/3tO2+_DГuV)f"D_`TAFSYYɔғ4McB%N^744uV^SSáDK19^|@Ӵ3u]7>TQv޽uJ)gt6l"~"kM ;!Dxz9!0M/pTn&_ƆX3, d&.L$'ou<Ue`gȓ θXgϞZ7m۶ͪrCvK6lmCQn^{-by<T>X.Vɹmg˓%6m6}߿̩S9/$]zj~! |͘1#G,^vCeee_ ˜ii*~I3&cuj% mT;Fݯ_?4FfɓgmK޽z iKt#b9!pιix )7RVVvoCCq=Xa]pGѿ$+:ھ}{2`yNiK,++\k[nti0ꭾҥ)C{wY˴~H 4+Iihw}gzSNډHifbx<DzkSጱmھ}*hahif0ay7eXYY٩e͌F,ʵm$&rs~8 ܵkk˲AۤE!wy򫯾EúuK/-[pc.2d>5q<˲1bDU^ʾRJɢE:t5&-˒e3L1]e59rԱcYDmXz4VWW/ݹsBb ~߈Fah̶m+;;;PVVvI4;[E2Bin;vҝ;w=h4S*BukI&4 m[Rʮwܹb '!<ǧE"۷jĈ<0 (i}}WZ 4A_8VɜY۶mɛoJm^Deggۓ'O>ԭ[`0M)ՎяFV}}m۶E׬Y+,cW\5o޼}]8DpO(`B)SҥK9!xzhpryO?kٲe>@!P999^N_}Yg3f4_ <6Y߯^:a_.׵dܚ]4x≵HB dB~I&m9r$3gNU8>ijKb[neߜ9s~G}fq_B)= @o0a6mZ>89ֶ9߮ws<]UR;*|4:tЯb[o=fYOi7tFAL{AžӧOݷoߑ.oٲ%:gΜyr^o;OҞeee|ڴicNK^xcL0. I<Ǐ|Yg/<<5quԲ,裏(PRRJ0o< /'O9վ$k~LcF2Ώt g5NZ+Aص.4hU(}~<ʆ:w„ |֬Y5F#~qNC0TcG$sp9l9r$_|ι'ҮUiӦn=z}gy&+ eF… oUYCt̘17^}M B@ pziiiøqD{O>d?z._̃GS'N/rymWm_@@ IDuF"z84aK+H؋- ( WhY#s?sN 6<9 9~Ŧ%ʹ\D[.+bz<U$ns^}ze֯X"!qιaޗ_~,zit 4iү Νy20Tei욧z9o#p\g4MyСC%B{˚0a\sN>cN:S}mSEk=u]wއ,XV##DN]" gϞ}#k @BI@TFӓRj8z O>w]I _ƍ 2~)>|x Ce^=t萍,>eB8z^,##'''W@ {…_z ZHZyLMֺu_K.)R+r~Gi9Ԓ#lwtٲe<qw{9熜KXdʔ)o s2.H>;T999KJJ0Bݵk ~OW9r`֩} \r%]fΜ9*0Ə?5;;{i(9dȐF"y2á~-Zmɒ%5"13ҳgOW\s#`m[ pAAAD"q/}atU6F[y>9䓃^{mGT!G!-m~ygݺunVV~_3'`ڵ]qY&TCs%}֬Y7|^zuPaʎ;ܔ=ztErὋ-p…Gweeu_#G ^ve'͜9 B\B^5x*kQ X >\D"ݧOU';wnξ'?SqbAqYmmm7lذW_}4Y\pA)^XϏJq9m=_bc~Չ9Fk_o͛_&%9Z@(حRMM-cׯ_|*3@ P`YV^zLBO?b޽Ο?#G|^{nI{]wݦ/\resJMOmƔi9w4#~#FX?#P6`wn+eee=jժO]QAcǎóؔ)S b@ p7)5k޽{/ Bj.޽{{Jq6k#`ڵk0 bvO>^ox,:P R>Z4s+,YRQ;w-++kӧON,~ԨQKQV~"C{_sκ:HA9YYYy %#O1 mc`xkS 5s IDATO4-Oxɓ'ˉzVӴ_eYgee徛oyx /5ifqqq/J)N:餎B7\|PJ;1&VBϣʘ袋6544 7dȐ:h?dȐۋ:4ik֬bL_#pLK<Q3zW7olJMAb2Ѭ={>PK/Q1mM X|ףw[qT?l+LG1Ml߾}L>=Wo!ȑ#;g͚J9Mñ {I3g\S__UZO.] "One3ʱc.%t#^]Gt뮺 A!k&M#|y1HNu]1 #{*X C̶ʽG1z($y饗 N:DQJɟ7Egu 6eh}ﯫ[`cR(?lذWNn0bpB"~۷ow|s^TT;#Z-AI/[}ٗF"7xc-,]?S#bR!Pm۶|>_ǓN:Vw2Ji]$Ģ*p@ 5?sؾ}®a9ӫܼy~ZBH@| {homgܹEPJi1c`#CzgjDuZx\]SL 1ϠڡChv+x I,C` bSOG>ë>PJ-!Ctmڴ=z{^.VMWր{?{ߊ+رx}pThMyGy?j% Djj`sTQO]vzU(G~:ݻz<8ŋEY) TBuX͚5kPKq٪#mT4(?{=䓓(յ^{ܹs{^Coҿ&iGe=޳gǷSofi2,jόR۩S'nP(Te˖Y1ShyUb}շoblDuzPҥKg1E8":By&#MBH-[|ǓdD"DžPg#!L z8>D=S\\,`0(͘eŏE؜Κ5k̙g-{<:yڴiϋɖ3qK b뮻 郒c1r%ڶ]DԡC*͢4lbay/Gq0 94++O)ai^xB,s=BD}>{ﴮ]:&/Tsm61Mӈм:tyb3!01yx=i"Xr%1ctt@ # -J7''ǧܹ3ЧO۲ 0Z19v:dt<x=#7M3f͚r_U*! kb_iHnn7㹹yʡW֚JÁ; ⏤ߥF\G!'Djkk}곽^oPӴ4~,\pR*!7tS[PD/"ss4M3svcܹ0 yJKbmCNY}UZf21ևBq`0W<[YGϐNw&!ĊFiUMtwR]H%wGt4B˶mD wĐyX-IP ^{gyf̙3P/A-3"bMF_}UMM7ݔ#IH$+F`?#4Q"S <֋2h/q( ˲$1 6B:.ک-h栐iZ!M) Tg9XaÆQfY\Y*MWpy 2f̘POA$\ιWBf^gXMU>C- };|b4!ydSE"Mf%,ip(W66fڔfUYY I$ ӝ(Ȑ ZM1{;vLEU Nae)ha>,W_}M4iF,+/Y.lf'Ԕ_-n7gFH=,1+>xNFV s"2R8G.W-Qc+@0׼PlSwv ]7e-m>C7N[@%~lf U`޽;qСxQQɅ)**wžRs\I41$V6o4M5Mո袋0j(E*ҦZ)h4z\tE3D]]|>ÉasM֭[_\pnj׿uK0T]TTrnڵ6mZyȑOO!$"N:qD3O{ qLcMF]D,p\rWjr0{ltU}{O"#)sB+Ny=^ֻ}#__q2f\"W]u!6,..h4M3jYV8HȹU}L?&ot1&L_tEx0bĈQ ҆2ZouT`S9?`y^6o޼{>{I'9GMǎ;r-#ow#UO0 V^^8s衇";cƌE@xʔ)ȑ#>&搸 6;R]cƌink3=;<Ȑ̞=;vYgh3DZ2Te4ZT'BM$!ej&9ns}АȠMeTe9n=ڠ^%V'4B"  kJlJ79oPSMlArMvv3NG]e_裏NQt7~oHeYN4ȨQ$Fu_~]d͚5^NӴ"۶%>V!K7grwvE2!>lj kz OZ|Xtw- $ZݳgϖD"\oC>[nСC_A2Ě*2dȌP(sΝ; r1Ilk Yn+AHYI93N29u*ZB,MS6sfwe?Npι ꫓-rwhfEsz9cȑ#JWFR<>g̤Dxc)K>OM~HY7j]]כ[;h) ^ǣVlU27xcw߭;|p5k֌PE)5]͚kHq%.]x:u;[jU{F$$Nm"I 4VSul$D@ǔVq:{v|'\1d˰1Zŏ׮ZT>;3qJ|;nj1N)%16u3vr߾}Q$P*G1=O~wK)՞y晿 LD\\~% P0ϥ ԴhM6mŝ݌% RE8FDK5P<۷]vm 3!$ \gxGifK'w56f]׳5MCQQQG(۷jժ4YǛ:Ι}%NJuX|֭k&irO\V, iN9CYML22d~ף$z $\L&-ʗ^zRJDt K,.arcmڴi9sf,.hPehN^f#ԖeEDeAGW79~;=zFlt]W,&%\i\ի|AkN:屦6c,Fڷo۶%pKDž ) fSk1P9|>YJ6T9Ӭj1Nt#f}%83h"&Ô;h8ҥKrl1xmm-q"CӴ:tU_2VR4HG׿5rssQXXk.ڄ [H-~JH2|;'aÆ]͛7/ iݫ$ѕ2^4 &Brh,by6mUKm߾]wڷo3*;;|cV2K3i x\gݻqW"''G[j(cw^>۲,[j-m-JՠA|mK1$-N ð]x#cXH\ucVVhTuH!i"=7xڕmc >+u>̚5 {F(r4 oZpΉX8sp-[اrDBH`СuqO$RAÇ Tˏ4`0.] s`|1tӦMun>?.))()))TmO?t… RJռ:ű -P^WWw6.Ν;EI9l1%}VΝ3E%*++x.>M>]aZv˲qƥT=z4MӬӕg]a2?Sְ><F{D"{MS 0flO>2iѣGyVVVɈkh4z=d!`Tni6 # Xqqqi  ;w+Zb=ٌH^]OD^oiTH9!(L}"H nv!C9\-jg4uX;vH,M>ixASh۶m' QBUM:>S>t`iiƺ7|sL:׿=p@% m_|ţuցsnHPZZz>c=ں}/m/s+at ۢ oW^ye3g/**Ryqo裏bHeJ',}?9um[8.\xnYEjfݻw'eFS?{l*_߿ۨm>} 61lsǎ|„ Ca{x1lZWWVݺu|*$*Qae#gMl?~X}9fB xS%p ۶m|ctuBѲ`NLH$0a„:tDɫ (XbE۷oӇ^N.)͛/я~-[vG}>_0iEqiN Ø3gN*-[>ؾ}G7o.ܹsI@7o|~3֯_+ @H4SuKiBm8 uڵgID 'MO()Zr[X, C~0rȑNFzaaWļ15M:, c.nC52 wڵGV..]X/|c$ٝi0za]MJ $S]m۞F=fȮ۾va3gls*c_C~GVV@ P/֎D$8RdXlXvvvg=֡Cک8`ɌK|ͦM,}7y~7nUPP; |̀qΧEq`0NSҥK% mo۶ݝ;wv4hP(w^UW]}s(x< BsEiN,ʺ:g?Yyǎ e. ս[uH!앛79sssOXIbZ˧=zHLCBrrrȑ#wO:m0"wye~s9*yRVVdɒ~[llٲ}y\a[nUSN7xHpweY<8r(3$t۶{ϽKg,ni?R`4pQ̏멩y駟3bY\0qr?qʇ~#Fj:N2eψ#ah˲n>/?/y[o=/77WS ]vY˗gB!4.Z;ѳ>{ׄ :h^;mW_}{]z\pp'l[uh5 BwơCPTTBw*bF F!yj)UM,#J*xp?e}{~@H(54goڴ.]|ưzSNvSf޼yعs/V<}5(cL>չF K[nȑ#_Az~`rRGͽpɒ%FܨC (ȑ#=4ijQPaz^sȐ!s;*++ ]GX}Wz<'7ns9% 1:tMW]u-K^U믿~VV֟ᰬl[n}577wj.Bycq]׍{nsAA˗/iLk;>JSZ~V?xK/J)={V|9_RHQ4d̦o#pHC$A"N^ >|C0TZZվ}{oVVi%l@>HSĮ_fÆ 5;*V$04; zYY={egg4͐vlOEnBH,3b~a͆ 0W'-1,Xy~8kjjb¯CfRjX>H }rk=a„ 96l8B]z4GMիW]QQ;֦:W.u{ҁ'tRvXd֭|A |ђ>TJp0^__ !<XYYO!YG-R)Nm/1hР?9cǎun[s뭷PE99?(&Ƌdsh҉P+WxcǪ6(`)92B׉"bT)Mpyy9W_UN:dϦA^ofLU:2l6TԜocL;ӡRvFk-`R"" kOۀ%]Yv"Xp]ccfRj"JlBFbP 2t:yw_ϻvkғ޼{{ιwH!TLBpZ a1'pKWS# sPF'f\HODaگ>̑O.ǯ TnZ sbAK$/.4Vy@ˈZLpĉ\.?ecqiƍu9"J^x۝BO-ȲLɦQ\Pf`(..[l'uPv۸/{2<߹lj[d(l.ѓ` de&v9v'n.ܴp Q&?l3}TkmȘmh2bOmtc*J$D A4'ϒz4 )ݴo Q!lj[ȌoCN23*&CW[H`NEt7z4EUU.JJJO?]6A\ w:H͛7o N.*@%2qL5 l۶ ?0ƌCTNuQϝ0FB3ѤQ@X7ƦB#M. FbϵDvkQńv;,a8`k!BF&뀎w&7 cnb8-4ҷĹv#&<PU|!A5j2Z5̋> W){Zv0,Tٳ+̒;H#3Ȯ^ Ǯ]6oرڙܜ9s,Z(vx<p84,gIv=@(k«֭T}Ix<ϮH༖`,`YruV1ZZ6ODL6:u:cЃ7<[!=<*&," 4M-̗g\v%x^Z'HԢ演2+5֢DS)c i0k$$#N/ Mv5!  N!/jKK+/_1fKG㏓/]d v{aߟ(J2hlgΜ9k"Ju v܉ݻw#FEpjl2K/ /";;[դ^L~czz:{EM;ĒMɺЀӧ벮-RzCii){Wy6-'Eb&C'Of<4.lLOK,`Sc,˲ `?_^/\.ȑ#Xh@Jf$EY|C `'-X>m1~QCC. $y@% 盽ߌ 466j~|2e 4`/^xo< qЍ wuאyUWNWֽwEQ 2͛;$mkǎ)S*\=z4N>m>YYYC'4i֬Ycwk0hZ%^UlժUD(**¨Q /rqJ$VX ߿?1E$n&2@SU$ȑ#=vXPsTp'8v#'"v;8oߎ-2Sc DyyL ގw}fϞ&>|'N` 裏juȲ^z . H{/tطoߎz  #h5zǛPQQM~)X?Ԙ;w. =X@ H$7oƮ]t˗/Gaa!Z[[O45VXl$Ihhh0STQQ:s_* 0JvW<7HN Jv:2>&o[eYQN k-s 1b `;RfQ̃4D Y[[[u)\t,iM6Fe; 2Ǐki0^Ws1!}FVVVeɚ@S,NGʕ+3o޼6ͣTa :w矇6H%%%6>Szե+}CՓChnnFii͛7ĉ Äڥ}忷T45uxixL3woݪU{I[i;|2x&AOIܬ=U % /$IJWC0IBU0+fGNN) ::t̡C3'7++kLd$!FCPsUc #hyc&Xc 8{,PVV_ss3>-@ 3f_|ǣԂyi0|KJ+K1CSo1}tt6ɓZ/:Dk~GGh?!aЀ'x{AJJihDFyyv]2ITRЍۘתIXuVuށ0sͤ xzkۦ>/MlJ4Rkl7U\?TvwX`ɪs7= DٽeJ~=yC2Y?Y: Ci  J-|2/^{-++C[[۠́.TWW[.a|A"1ZyfݽǏ׊ R ]ѣD"Gqqa9_^w?n~ B=uOSH*#>yNB1 f&8_SN/υL^*#6Z.@h>fѐokooGEE ^śGss3;$o>L0/^č7Q^^ngá1ܹsTmzֆF&n{--//0&4bqΜ9/D7g5k233ptvvZiӰeaA]VX… 諳fO)Yb_lVP`[5vfj-+2M[̎dubP &p ˵!1gΒiΪQVlS-K 2ǂ`䠯Fֆ2$:{XejkeJ1^L HJ>ȳdPansrRibz<+Ǵ:8y234YYv|ݏvd/;l:xvsW:8,nr翐,C {Vh8Lt旕Y6]>C7'`UI/3q9q.>B>@?\Ũ qW Q,co7FRafu"K&s J=aJ@r9fdj>O-Le0zڷ0vdܲA' ΰxq\i)m؉zm c줗.HFm(+ˊ7~wt;$ mg?j8IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/rel_center_pnts.png000066400000000000000000000517651360462764600250060ustar00rootroot00000000000000PNG  IHDR)es sBIT|d pHYs+ IDATxwxU?R7ijM:(PEE b+`W,XQ "J^BRId{v$B6@ ydw3g&3󽒌 -""""""""= mW"D{=ўhO$C RDDDDDDDz$b"""""""#w"""""LrY_ JuN$ucCLM q0b""""҃;I0BfIJ 2,.L2d)_}3B;PJi-QvC""W(?s3ӧC{9)""""=׿?&(튈Hp eT OP1H遜I"L PD;$NCز;KHjV! vCDQْO||C6RXu"JM RDDDDDz{ lSR|=cylvʸshҼpߊ EDDDD}dkRX+4hZlIMq&MCeih z{:RWg,-sO!9zn{]if{ܕ][=<=LxtaE&ANT]D0r>9pKu; L/K_{S'=H{IIiV=.(ewlf{ _mW :W{qc\_SwOC5)j2(L URWV@]Y>2r r|Oү H]Ye:S_QD]y!J@5ao.d* 3[U UvS,U #$jk-gLRl9Lp<2 yz[ !6 & )=nb)>Z϶z@џ BF6Ne {|:Kw;^3'\Sa)4nΚ%S23cvT&0zSCU eiXx -KMᔧG0$辏t ,_fD*vD&h]}+_J )H9)1B Md> ud #-C);.fq qPШUE.r{s;?v ȱȍLyFv^X @]h(6 4ނzYZCnCnl@Mq&N6Y`8_i'z S8v`4rᔋF]X%ַ,Msk7]/M l[IzzvQP䲑S=ݮt3:FuQHgDa )Ϥ<#S> k3lRuKcU)ʋk4'JMÚozZwj]'ZqXtE]Kk]\2H9EZ\r#%Y5kwQDD,-$K;K/4֔DVH–k+1@yz$h5j ·q.j'7="4[ XF@]_Cculrn!u;:GD m,F- ?d,/,۶Ͼt!}lD[BJn//ޟ캅{rv;NBb5sIzRfǩ+ RxLr{nDJAzixM{/@X/c7`S#' ^ӟ8_dFJKc?=cd̐gahHCu)%93~ɏQr}9#36#䑯87J?9Aࠄ/Oo Bm4>z0ҠaY\J`?"( [G;Sؙ 4ϳgQk(,,D4e``i~ {?}u'Xj^+OFrں sD1 %o]U70Xp(|}}QT\Y233E{tmFPǮŖLX@LQ}ބ\&LvbZṨ,6`ץdffFSDDD*1D95<{XAJF$NHjz kk72-VX,$`MmNP*}<O5V7jƂZLiԀăZ{*bH{Vu v˨8 @'̩\!Kᯤ헫VE W+|P;* ,-!7k31pljZBUܿv}.B+#X<m@i ;HG.Pu2aZ W<.מT^D`=D0Olo(oZ ~2"z B7ǮKQ\BPmQ*ŒRAVMh(ZaVy+Zs_Dlxt#""3nt+""]αCEtd)^G JjFɹPZs)BTֲ_NT"ξ-/t $/Xx83[ ·Q[gag3!aEtYp ~0j jR\_kXێLss)qy;1hw!"Ğ:tNنR GI%?;tOZ5 ^³[WvH0(ˮŖzfuU:UFg) ^j.r H+,$ZGZp׎5ZᝁGm.dk,dt_gS_rnWE`%O\Ҧu}Oal&~#K[0dBTn{ tg~;ޯfni-,W(>Kab@[DDDDD7ѫW (e +"""""" j<=sQ0HP++G>xՏӫ|ʌD#5a/mMzR MbydR .ۡYq jstkjqW#)""""Ԅx_nf:?sZq662vZ#,K;͉0,lMp07B;/PVQ_$&2ƇzНdS#*\-y8ښʺqq0c$>xi2G#31 v"L.~_乇3,ąrztH.aW/qY{&lZ fbbh <>[?gK$ R uQV=MwkkEDDD:Js6Ϟkw%>cL d~:hb p2Fix<+S1y狉#G"y tdO5v'݃HP!HJ(g{%9pcf:݊2|{=0<%wO7/o", OZA5_7}l= O|=.Wk(OOϞQ_Dz$WQPIKKC)n7DD mu1&3K%u۾ye40/g`ق45O,ꩮi@!r(v&,[0#Bj*47⣗cma@rf 6XÎ85<0+';%NP&:#W׳⫗4UO{M^<]K/c3;1fߛXvR{G܆LZ͢HWՓn\&Q?#` LY&|WafѶ\FEdW3+qyMm7Xr׌@Φض,Q &j)ǢD.2>ԃ9Sr*F>GTTSX\ŰD%`1$X-)JOJ}v2EvZ;ϭfck.q RSWz1:`$:/vW9@fffT*z>""Aee%]w0T(_^x`Fu޶/ 2Yg f $)XXęt&߾g(́H%hcE[Ky"".7G‚[ageQXsײH6_!)DBtb!uzAIjV) nN!9>O|Vf> Z`a\ZS["<>__mcm_u g?ExiT% 3UFISm0LQQjC@Tj5Y H$W.S^^ }=^0|y9dff^Fp>ȋ ?yw IҺ헍Vt;JMu-Vhw"{J^V1 j=wE}nz[.$:Ѡ H7kwJ5BfcތbNSc1I8u&ںF4Z-gQD.t(ͣ#v&eH Z(h4ZҲKp@vM 'H6D_?]{~I>eDF|-CWFa@yeji>܁C&gؘٴA*booi P⍓%%c9Cs+1WR'{.f3``i} Gww݃Fo_.*.4C}'l8rbW 2@ƒq|}, 9pXy;C]#Ϯ_j&;;vG'.+@מQGޢzX:[PZQ9O,eul9S1yH%Lih4ZzWHbZ1Y|LzWܝ-xIի𛓄c`JC⒋H*1B= ߾>lxtuqYVo_PaȪ_fۢj((G#TeT*11x)"pݟ00ǡ_Ǧ2\A"V3˞Y<.踢r od(V?V6%펰S=t0ҩvaUM}D*a~XckeZu8~:q7ߣ)#+z5%5\t|FG>1C@~QNezj{Hb>5O}l<_ަOlfLcHr-}] W]%zo^Lj ıC'+wRj)fGBUW=|if_.Q=kDѢVkcʥ1Wr$<ԬR G1P01VJɼ,ٴz&JXUV˾yZ#3Eyz'%i:ݣjx:PT^̦]>hJ>8[;a-TUSXvgÈ͌hUrץ#)ы?v\U( {I=}7'v(QMnt2 PbTn*DD"ֽF[S[CIW]ʆ"k++/+ zlH$Hhi1mokv[@] IDAT'b߸AT^myH$;W]USfψT_UP"J@pĸ$a>j?ÞېddgҢDȨ H`nfD_:Egb@IK*u6mɪ4%PZ[NJI:.=by8y;tFb=GӘ;#Pp{#ʼnēx} bU?eetCZ˖?cspM~dv& {`j )AJ3' OefJ1i&63s뚹7ֳtÌ   Jv3˗{iȤR>|=J#S J"hbn瓔{*B!gђցOH mؐA4r<<)gpuwOGE1(t]&a`*|Q*L005Fn$ An@belɲaTRTٴ_rMV^FRK24Y_Z2zcb1of=* h5$$]I.i h8/~~<}(Of k̐jEmr{}9ݍq(uz ӹ}ĭ7;!Ә9dZ>J#aqR[SiJZ}8}ꊎwtX$R ?!1ޡ?mNch4Fîg|=N@VÉ#x9u<Dab𰁺}"¢gQ2lMi6T7Wk|Ҏn$1UX4}34N4KLw<9( 似t4J^щB`:kVo(pL~GAQ^1_ss+U<;7>gK߃WuAbN6tZ'ё| ϋm? Vrt!>q g~8c3zNci4B߀@FI*u&lX!e444r6= ; fx0ۅۂpm us$/P%lq*}lj&m8*.;Р|{ǬV[8~ DB YFmct,nѬSlu_c嘧-v*9h\>>KFc.H(2jUvϏcke=HL+B9t*#hTk8+ظ5w1r+q8I:_v,kaϢִ{j)jF.XM|Vd+x5mxsYl= [rپ]9"".+@08ѝ,&ԇ?_㫟$$('%j]`b~O:_ XXXt=>ni:5T<)rJ.o #čKlSד]''s#Sױ $H3S6TX{$~OHp'FTm},xZQPuNk 7Q?hZ"!Hﱫjؖ7_~1h4gs#KLP(hy~*@2 ]1>mgPlDd`en}3r0,B|=).) p`MXYQKs#>zyzd^ٲ/_ϊ^blhd _Xvʵĩnb}_9 ks3JPy3QR'RuS-%eXyv`EVOV1ԥ%ɷ{Sa9 @!WDp2'F?k S޹|}XRg8_b"0+?YGYR2KpWbl$|k \Xpk?L0jRJ/+-4{2Zv$-[Z0cageF+pIewE'.+H{|V"<>__mcmYu g?ExiT% 3""""d$HiNj'qQ]q4v##"@!?KlUVTj:Ȣ%)]a,Ls&h?@ѐK# J3h5|3Ye9ۿs35%*LhԨKeX[Z#N|NF'UET7T[H_>؂!V֪q2G5Ƭ $R) çZ&YNjB)ތT*e̽ȤD[<+__>@ǥқ&Aʺ:JK/ʪ*s;.å;]0SO/m?@a$}V) Ń=7ycq>!wGlҡJXnDDn;tni~:~EDTsϨlڛ{!!89pϋ5 ^.Z*Q.HT-AJjV).fSG{x:G#> ?b4faah9"Dxز`v?ܟWFdASJV f):TWlVn^ *.>( bBqSLdH%>S6;$##gϞ‚AZߐp0> +y`sajQfwzv-zzNOc}Xz`l8l}J+xssn2񞄪 +EGG}23J3%-QIp )7LgWh{8*;6cZW!`TVVeJ%nnn{ϧHjuW'Yp(GvƵ@UYWfpmj 6V]T\TP~v8qkhG9yJ!J3ƸM[b~%ZdZ 'WV˱a UӺU0܈zܜq`}ZӯOϕAufJ%< JL;KAAAs_Q+k8תb#(|;Kyy9¨_g177]B*@;wĿ-`:wb?R:-JQȮBWC9̐\/cDW? ڥ H*~ /vۦ<2cn(Q'HMKavxo[S~@K9aa'3kywWG f=&@*w+*ps4/b7a,[6#pMEzRscdIJÅ r1 ׽\>]mOqyyvٜaիrd]05}}>Ĺs|p;Kj^\<3 SN9Zile촵zGX|w%ya,&26JcYxٚ`n$<8태%" Ω=Ζ1Vd fSsvPdxZ} 3J;#; sagrS$5oYRo_fxPElf<NSHh!hZ^e .DR)...^FHkR)!cJe0ihh/ EwFFF OFZdɼA,]o⻧n,qy/gaϭ};aeܬQʙ;ԅKD.Rj0lMX01g jʄP8*N,乷1(ȑ㎩TfQL{J}ܭj!-7'sriԏ.J dQW揽gu9o2faafT*H΢9!8]]uAF/|DGЎ͌' xu^c0 >;&-mR[_˚Oz,A~reM ] tUU66EVX ]b:U{ZRjHLQ] {ZoW?LMȍ; me fJ4zRj)i`% 2>[0E7(dR@y}kDѢVkcǭLfE?G[S~ݕHzN)chN* OKQÓ CωȸʫpS[XIum,iJwA(Rsi۸P &3i-[* cض C]FoVCQy1vm_S[_KZA>nm-Zʫ152'Άφ*9҇Sa;3xz9UP\K Y)M x˞Y󗳦u`(_"""犂*y!c3a?qfz)rg3*(f5V& ڜZ?E斣I1wbXvO;I#t({"I/`/Z-; PTB CZx c]4Y&:撳C̼2L 03$!F{M INq.[ɔbO01l-'sqQPqc :]XUz/7 m)m2t&^ԳErºvCD䆠әf44$)XXęz΄3qL1y ,4"Nf4i 86<+uhZ+7Eɤۧ}P/)ps2'ںF]P^Y1Vm5SP*`U? ?v^ e|K Jx9xR^SަO\V<v-˖sAPg'2;m磿RPf8S"w|g!2""#dw$Rm%h]MiCafl8ʬ%[)-%=YKAワO?ih옐_O`5 n<U[K_)RNDuΖb8{ bO8]^}i Nfؙ"H7kw4Lra N6DT-85mѤ\dWŦ;kS$|qU[r sjuS?cYV5Ku}] :bnbάlg,C?@Fa&5fю<8>@(?8W=+9j׶ifbWDD*Φ;\U (}BImP PnS0c˽ dPpTr=k͜/Mq}@Bpv?̕a禮5Bg{!165U[jo18cgm Dc,MexP^M{lf '5sY,cF‚R}g\;c}eR)?O{ NHwQ[[KQQEEEV(rB;X[l؃zRT:%Ԓ ,I4<-/8V:\$t k늕{-nϋIˬ]- #6UR=* $$]I IFFbbFꋪ~ ]1oHGGGWH&ѯ_9Z+:45xuEzEE*s3J-,,t]xU'o( 5nꪫPp2+˙z^{o?ko̠'IXUrOL^E9-N\uO[^LaoZGE}%F,~|Ҏn$1UX4`Ws'b 9Je^l ~Cw*jN}þ 1OhGqUX2d![c೙ovH>IL9 d;Z̊C#غ3sj/UY-q+ #V/1uj>$agҐ">4 e@ wV琒YŠ2gJ_ IcXHnZ6sxTD[޽Iۜ?}anba<;7>gKa6m"44[@@۠稣t+9Iڸ^zc_OmM-}Ѵs>NwXWvwґk~`ak~1[݁0` 3]-O9Ғ8>6hZV{~6KvD4dc~plpA|+1"r~',0On֭ JDvG.oO6GQnF;Uʼ5%ܷ;7q R*JTL7 d(/,̄/iTߣ󴦪?ݬ-@X&SY p )qk+[| ] A|*!.3d̕_wē CJkaϢ`YcjeY`5Y {]Ó״ P92e/l=e&)"4{-vv__h=)4dCPiرF *^"1z\lu' #υK%ԕ^'<kONFRcAHo뇭5f+({ jؖ7G.DaL?5~zlIDATxQXGVy.Kޏ.NJjȭʃJvÓUCXN!Az{NF eR֞j.Eu )R9; *й3yޡeRjXl&_UY-iKba:)εh>Gl)O?a!-bnB\.iL(1e5'ϊ^bt6e稩h*ucey]E 71&p_Fug掾{~gźmcLg|!Nő;-HHX 1vtfښZ։04|& wFѐ2̢],{y~S{Ax`ݿQ|7lk iTW^ZzMZ!Y)|@U,3Ҳ5uwFkt׼)#n#&R.g#Po SѨ+tE%2U*g3GFD2u0d6 הPYW[RJ2t-;`*TOfafԎdUJ{!UHYJ C!g h4ds|rr3wbHǏ̋a[˹fujfjɶgyfjjkYBƸWѨ03fd7M9TFex  GR)V+pUCݑH 3 WGs]WS/+7jFަO\V<}ue'3r 耑 s,'N0f|3oJ7i$M.)]hهPVGq(8:ꋨ 3 0 8 BK)RK)-ҍ)vI?.K6] Wrss={YMY Ei]~~ǧ8M>bݦռRJKLHfH _oo6{* L;eqLM *,BpL.=zvc`Ozq6Ne&H*I8񷍵xڤ4|W?o67Q*Oى+N6;)Id;OW%l}7gɱ1߳G>߸}GwYd5#|$\ ۈ7UƼ9[(nx;g}KӗJ) LY7WSJ9>i 1llH\ո9JٓU:7{KΠq8|.AQnhZ-|1{-oOYPcV|m")*V0A/Cq:ΞLD'v&b`$Zj Br}<%cd2KS4v>=꧅׼2 TLʱ34zˋ3d;ŪdT[:exTJt7MkQ`0V`2sUWWdͬ;`08v!åʬ?Π]1R }&'W8)PԒ̾|c'ybfݦwt7;61 C]w͝ GW2eDOJj#,</IiyMRJR:z_?N$(X܇b1~Vh4|Ύsg *;a8|sKDhDP0,r0ٙ9PM֎ys:UWK}\*$غU\?-FNY F}E^y>s4~{>u)ũb})jg FFx(8w{{[1v.'ڙ-'K[[Ƽ9[]\,D.\sf ?~G[e6s8ez!CƬ/dŤ JK/zc crrJ,Wj 74@ItI;}'`Ą?.|-Ƿp|KΠTضY@bzeUx:O6Ī%WG'zH' Q30Ui*MP^\lA95`zWhөwg7/;Ui?wL_HQ)jThrߍ3ym?þ?nvwǏοﮯZ^f}pRYF] ;9/-<wXmprT{H_|ܼ~+ѕRVYF?8d<;_fO,8(oVٳgee+離h\oOf_yi|+fs; I Zg:J]%gFDe׻9Zҽ6s у& K[|`!v2|¤Q̾vKPpY;)r?P$'5jx6ΧXs&3|d}$51F\u $GHlm,R%iԒcʲ aOEKcpDŽ{~m,~BSY9'r>z-*g?o[հAi/KDQ}Z\?n_eso{(m9`*qg\c $%{7,F!Ann.'OdX닻mƬYP F#M9O?uWt@pAʋxo hyV`?5JJJpsPX@pp0%%%0hy.8qpP(,,4}hk me7ULߕ*%[vnvŒܗ`>r^^lO5ڶj2ٞxe9)l܊(z̪+UX7u'fӓhQ1 \xrY;I݋Z& ĉ3xNYBDR|Fb]Upppgh&L֭[Q(j pttJ E[<+ɩkTh4bh2{+I+T+DҺ^HLV$ws3 ҢDQQV_y睬[PZZ̙3;K]NWgw$z}R^^ޡ!|a39ܺmA?z26mQiI #55:֓7ovblsYaзj]?Lr*lWUed{]^G#7;63xƍRJ%+۷FB.QXXȎ;pP!555L:tu&t:'$$///77b233>>pEm իWtN4 :]m77qqqlܸ)S43o:YClj[EC@&燧ggwE 8888p^^L>e$vmӦy\NPPTTTPUUvDee~[z=\JEd,-ԮtwA"**td2Æ ׷#:N'9 E*~ {=۞@ LXXIII5rAyy9wvwz,gΜŦ"EG  r]"::cr iii5nM>@СxxxR[#撙iFLOAV[I^V΢X I.-Е% Þ%@ tT* :)")@MhN$wssttDTl 7A7Ò-tuIaOk@%+@ A?#0\,IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/rel_fk_to_pk.png000066400000000000000000000525631360462764600242530ustar00rootroot00000000000000PNG  IHDR*ec#sBIT|d pHYs+ IDATxwxTEۇm){/ޛtiAbÊQ,X ""KHB WRH6m'ٰ$I׵gfyβ993FCDDDDDDD;LD{=ўhO':˞%nt[]퀈ȥ9MZv!5u˶R4D{`jlW+j/*""""ݘ:^\ c*dkd Й =E{K# Yi*ƕpC:^ TDDDD) - Wlc*rgk̻!+b$ߟ9EsF""""MyBbfծt !ޓƿn#*""""ݐ3)- EC2MmW}1P醤eRj7DD:=ǓFh}1Pԩiv݋[8u&wCCOmw]!ny_OAVPTddd\#pɲG${eS.I)A***PTmH<3 KmYy 0|o~]6>`c1_Wq;_ UpEEEeb"""""rM^r~ˉ';Rx[(55Yh5m}e4|{s8vfYz$Bs썱uyD|0۲ w ReP'ӄi)\xr0r>]alnګs ïwߏϷSC[}=r4#VֵZ.(tld{_mtW UWij#}=O닲h|1iOSSTNfTdEcTaL]Yueˈ7s$ ԕP]koEԕbN!ݛq7OJ} ޏz.`)`S!Lj>>?nGBtd 4 `M{xOn&AZ lKjVvBV 6jAjEE|/]Cm]f/=䲜:Gh_Msm,X< -""Ѩ:W`jPU%G`3P_,=R?SBiMȽ 3RbB]Y³/TxLNsF@Ncr(Kb | ^V)!P)F\ T{4ĞBܹIp3`\v* QQI.wks1Vb""72ј:`8R!PQ~ҔX re8 ,]eV{Fq8>NsqUoaok5>y/ShѶ ۮgVmE.Ғ:<֮vEDD)ψ_0OlG"Qg_j+(Ƽ(\ חYz7*#k4%J᠐k`š96>4[JEqG]ͯSu '3C%Endr&%Jc1H"&dטq("s"""7eT'S_]JU^ɿ-Kh)MKVb@yF "r.z7="H[Z݃)ڎF]CCuD4, pG/~Ca XWض/l:{3@hfowgS<|yiDm#deeY!T+,K"+2[v8F]i... ]=`OЕhFyz>S6?nk}$?g3ĜR䦖?:bbʠgblL}u)%X >ISz"3#9#s;?;SGp2O!Px, ϡR F^군:Zkz , u/1aA vNh5Z 5eaffj]IffӳU?<ʪ:lF\g%'sCPYg@!Ba\u>ra9ܩ|WՍ.,-6:7T*.(YYY=uaz6cCLZ[HLQyO L166&(*#wo񷗴j#=Nu ++K?"""rS} H%jۻƟ΍dF2l^eÅ la.`_jSPըvCDDq(ۍV^zݾ)ϣN#\UÒ~e0+C f3h$xWʥYNt VԝDVuG{컮vCuE%ˏ7IUV5 [ЦaMQ&'߿/32=g6BHRkp5T MR ʢ&UzATP544hf C.YqqS?(L:agX8 jY!K㗫jW5A0] jmHw*e8 DX0]SscYuǮR51Bo;07tZ[DD#h>EY0+VWYD{kOӶv T"\'v!<3ϛU @QX6lwCi#p;RP5 Y0TP54[s4 ۯj]|<ݰ ^UˁG 2"""=_S䁟_W""=XD{qJyF$VCaԟ;A Kn.j(ʚE nA<=/n+gadaOAVjK;y@ؓBHb-kiR5y[uqUYU]Bn-݆sS6鹄0vCDӉ=yҕQեԕb<u$[ S?MWLġ4&m^.Uà{>8v{\NTz?o0ڱ%Aa+THlMUG0j792`g]""""""]JQ)O= 񜰸E{q}(֌_^3hPZ3[aTn`ڛˏ肽^MLi~Uwv5 0}𳭏FF)Η?⍧}"| :7cCFafjM{ۣrTžv""""]N^t8J#JO߿_~~e!Te)tl}l[Z[NDvTF].VquJjq{ܕDEs<_%>;`kݣfr9C<ؘZd2mU,oBL[ zlZ3jo??{Koi[ {e{I؃ LNbn2vaQƂ:d]u5c=C<9{Ri%֗.})*#IV1syjfg>r#9K;ck)VxB6ߡ1spz3VƖ2J[r1aXvec/T7p]krkt>_xZ1w4E*l{juoxZKygTZ?letjs"KyuL9Ym_2< 7'+:mTZR\4Vh@|NO}/".K*rv#$e<޵W[Y®MDDD.0գ MH~3 l}ZO*NczDt:(!;i?ߩxu쳭M?ٟ"H))a޷Y:1}"HQҩmR]OaU4^:}ͱjڛdfY7m*_E@vYIũ[2+*/NS5%ں>?RX8/vfIh/?ؙ ýYiNѻ֛-PD6zvsMajH:#3j)*$ zXh~"R#+bz7A&mTOˑYd->Nl?P`rsy˥ߊA3_3>ɱ1rew@''"WLzz:2uW!"#64pyeZf:ә1 zb5K׿̘QA @a9j5x; V\v<^,^eH~- Xrc,ZsF&lvM"LMFFFW!"*. ^tO UTիL RH)*~#p7TUΘMΏe@$cyI.N7(ʋ>ss$*$ҙ7N_VPUTIQ5ؘZ3s(Bgwla"8906R/*W䄝)q)E; Xrf Ơa/ELʸ!^̙܋cѹt:;N,Dq*Eن҈(!ؙ6)^?l؉Fmu#.; ^H縜RӨ!̧ovG;^ڑvs) ++ * ++6ED:Bee%Ϯ]=^OWρ~qm ;~#Vl--H)*AG_jf*M?RR[lW~l+?הhf'ZWHݬ{!wDr"7F=/ B]ͷwq~_M^luRGH*A!jEL0/@iن-Y%:cj"Y0%e-"mLH.ϯ#XYϑI][XŞ7@o@A!W?paxpv?F$=DFFh0P>?' Fra%ɣ|{yeL:{r5G8wo]O*Kl*F.ӧOOL&O>cw{B.Ne;z[W>pkԖt=:Nd='Xp0Ft,a«7sC-lu1duY.KG%?'ԫ՘OZKʤ|3mQ_ @Kׯo#ʅ)Y%Z^A @|v~D]UöP_ҍΣsIyP>v4n)/V.YY&+QȮBg+hHο30fDX_ "fXN R:J8D{B8w=nkoƷ> z ^ʨqzB>SIfJ"זwwvㆢ<# J.%!Ms?;CjɁ,|ܭy0̔=/9WvOKp7/Aʌ~!?p~1Snuew8VƠ4`fc En`ӶJ+tu?Gq2&DœImjoJӂIL/&-ޚn\ؤ6~&ANXRJZ4Syi+ ¶͊灉Ee'2$p:6˜w\)?,/Nv;݊*N9D>úZ2MRYoO.qϼd,t]Ogj+텹eDIgi?[)J#ӽivF3TVǫ[PO3iԩ5lݓB0ʅ_ s#rjMK<|Fo^⹙Oq:7ێ͊' zM=3޼c0">''.䃭Sełms~O~+,}jMJh4tMYe ŭ bZۋV8ו3}Om\w=NˋGQy1v}ϭ7S% Opa֡3%e8NlV~' EJ IDATcΧKȻ>s5@m$!))$ ;>?'B/ +6iQWVK۽ihY^{uKf<} <,߼w\Z]3pkseS5 3?cuf >&hw\HuD¿x{G_:'vp~'ѹhu ?#JV?JJє FJKfŚ#$c99t:`wRiɌ!7-/y1?E2 0O恉1# r7E4hjys| cBFpV}1w]sMʩvJ2;rZ?ݙߟY s텹?=5ơ^Muu544t,I"TumO)H$e%YeML{>Dˀ-*Sbf$d,ͷGϫ`JTؚ3h{htlSw֛+'YN%3S^0< 0+ pq0'^?Ҽ{t?x:|͊cZq'5M}1!u\N3 =N޳ÚWȤR|b5&f<2l/]ȍxO}2[kx(~w8f***HKK@xF`UYݮ<%prZuNh=TKƴnZv)&r\+$&_3Q9pGοY+ LzSS_.VRevˍ(ql="X }~~4=&_0.wKvFˠ+cD*a/p:ɻFt:Z-:^::M5eT475h{qF 6(/>HGkѶXSi(Gof5)@NYYw]e}}D~1a;oO+= o 'nzsK pxlciB*5֖&|4*)Y%Y [=-O->.DP^U9ۓr9ë'Vtˌ B"?.; $~qV/`%,EJ2;ױXLzyc#b"nVVt's a?A{Mڊ*ЂFJRuMN59ŸRN5of- 6xi16$ Qf&hh{Nd.hђc7B:tBDuѢ4 AV㊑HJHƗTxI$HdǛKRPjQ uoCcNⴔ t:Akܹ`#3⨫_Vk+ٳs*U'q$eغ'B]zU5Ǣ\&e/Lښ6OTT [ +hE'`1(TH+)of۝i?zV#綨Ϭ{=co)q9 QSWCOmF;^ڑvs)sP(8:;y?̣gH!# K]m&ߴT.kI7DM7Ǧ7roRp\VsVixA?mJ7VVh#; 3r;!HXHm]^k+-# ө[MLF,a}{zuX2Q@Xy ,|,Yѭ,EW̧H=._1PDMu y2Lއc'T5>>7' ԍ\k{&iQN^34('oo,-/}d҉+3RGsښZfBM  DfƜ#OGo^س7i^|նKCkICH-Ri#bтbaœ9昙*I>3y5?#$fO@4J`$=?Eq(BJEՑSvu5Y8~>\S@"YCbn2ܚ7K).'*-V  H^I>Z~Q7yu{|?NlʁIgY]b2H=7&NEOX~2 1r#Fr2Y7i { AӆŨ.ƙ{p<hZ)/o)xM4 '9~$sﺕǢ8~ hVTUVޝ˗쏯5F ? Ksc#}3;%:Z4iSܠ@e>Xq,:)}e95f/8k3+=92xF 'l2^Clv?> mvA!W?p | 8Y;h ̼$qRRVVV `d2{NI.o"yt/w5+eGGיkMFnO7YGrVq-!̸u˦?ꊕUIJzΜcg8p/#bx'9|obO' H7>XG9ݼ^QTЮȟ,*й;{Q*นYuGΕ!1ǯY '^e߮9o/^B>;W+ځ'''c ){#ݵͫ3rPM TiʚU6Aq"wҢoSSSͅuS?M>B/J8yaB~~~+\k{Z GOn*ͪ# )M[ck&quum֮""ׂجxAϫT*Q 166nowkX^=Jȴlm@ZGx8[қe'UYpU󵳈IjJ%e~ڍNׂZΙ_?}zU|r?rg66z-Rٮ Euix =T:Qyq*\5,!Hs4Mb(Œ' F,dΟR{dp6ExoKap@RJˤxZ*d7 l2x7LMBZ1q)4‡G @x_IFˇgDV-奍0,p"6+&Cuqى N㥍`0f]\Qe;0a0d&t)4"VɥD~wMjn¶uZR\I@1LO#)""].pE~|{{an L^#-#vЫ#z4#9؍kY;Tpm,هBmL9 yώ q&%;mJo TWaER<\,Qȥ@R)*g˨SkcO3n ?Ma,J%Y4UA7/̧8C]}sfœQɇCo1V֏UײbG|Nz=OkuH۠!;1X-)ۙ3lA4N}R \:['UqiEy%:]']d2Fy3R ;鿰yߦGp}a)~~~d ]8938JEAAAK2LSpRfտ"W#"rsEʵPG=[B&%֦7/mṷ{1q~4e0o2)9ʉ}t-ijQ# Y%XhH ܴ־!BPV^fFXYVF3X3|gy}2&wk ҠNBnnvnz9bͭ8!FvuFK)z c[ut^Mǭ #E AKgMM--+tXڷD&1)HdR"ŀn&y p4c0)7\҄YCR]cEYue9ƊK=/fD iq ^}BiZX9S_:3j& 3?0O#ju:+ p4CDڹ{ދ[6PY01p$@E ͛P5[Pij \JmuE2.t4%HR|)i1B >'Xd ?zu1YqDFqػ/׊$`FrLNX aovɗּɻvL&cy`?e/W&Κܐ#)@Of},呷-P{UF 3Կb_SY+s1*ULnZnXYOfŚ#XZ2r˘x3o=>' .,߼a/o| >߱Z#VQ[P~ xXQUF}_c_Aގ2TmAD59t:4Zi%xY#KIT !'8f䫷)ҒCnf[_پ7~& I{o|+b5V˛擇>`o2_R)Cn:s#i ccc'&lll03k{t6/D. >~sE4t~S.[x~e!/g}ܢ,ENmZSQ?G.-riہ̣r:ix[yZbe=e+"b4UKm!<.sL}5ݽ(QiO^aqXZv)BlZvic;}jLm~>Ω}I`ajCˋilV g֊;Q7ylÌ P*h=N޳ PI|jMxdؚw(Bhd{UUU)W)HRDzz>P֑NLMM;22/^b_]0gq>\gN#X1fo, %մL;- X'z]zU:mZSP|I {g߅h:Vm '߾K:cZ&Wq!LE Dш95C;11:S$O&## L&OU#`Zx5m)/+ò˥;t`bbmLtm͞NϳJ dHN#ۿ8OL~A .{1uՌt^H=m+[_LaUYM*1ȫ,>J^E$q>ԪwpJM,ynb8yzʍ)V(lowKb IR1/d&B_:1k /Nn`o!L vlՇsIp3yrܘ">TN'+e`^琚Uw0gr/駗Ͱ1et|=Yd,y*y{ l`kG>۽adx<<~ VC|NO}/"տ6׭[ǐ!C ߂Z|%sqsjAJw$,%8h;(ݞWPӴuet^yYg4FW MÉ/~˼/z{鏙5߰x8ׯ ֧IiLNcw9w'-3[;u} '\,#o{mco^i}6;H*N1¨Iny{M,sc$SJgvizE*~O*5%,6KG>`]i_w%p2&4Ii]HFn_ IHfXEU=v V\(iԇ> SE}anT|gf1uKNvfW%HH䯈]5T@9?8Sa-}IDATK4jrg͉QiX6$Hm #ܛ &Lu} [w̕(q A@ ud)q2kz0QLlE>~6^TU=幄F3/tf}.o덵IkU!r-(“};ofpˤU˦VDtBUY-{emˏdx&|} يsM}{5KZxZ}Cپ?Sp>r;!w^_=_fL( 5 ,.;/{^²_ԯ=1!XsKnyEa7rEsm{[]톈ð pl})Tt[N'iT7~-HUejጩ܄XDݒ[GA*n;1XӒZI[>)'3RT8;(< j`؂U:n.ˍ9S@_p{ yhFx4kNy>Ϧ=qs0>lݓij+AJ0R;ؓ*4Zq˜)g b ju D%e4ElEkf A˘H$uVXl_Ӹ j7?-e{N4Zm#qo ]zͨ+%N֎}󨬬$''T*Uala8w~ɟnf񛽐bTޡ |Vm%zJjpP6JTw Q.?9Vª.g*wfɊc98F.r^"onq|8u&j+xnʥKhd˓5ЃR"Qk+'#LD Lա^U6l|g"Hh)[qES~6H$SDM}ebbIN~yれ'aqˠiɈ%;(뭏e`MA A \0{ wK˵-ZڢY-ZVn2fڢYfk !K,?Fqf`Qg㞐~UϬ~,ٶ%*%M!:Fz~$I",, ZmAV,|UTT4uS h :T*\]]٣knX6cA )5${gR. i%6@zqS}./nueuDJhѢR8srՕ8PuIKh*J(*̦حkF[g6jT\.$%գU ,L۩kNmJ:ET%Z{:½<^,BNSuu]&]ϫʮɜLR.>J[=7HZHFkIԋE YqYӫ:Ϻo3@[ɐ)L]43GO+ œ ͩz7PdѽyT)hl7f_{Ӯ[0M)  c: ߗcF喝;lO!uV +CwZ2 H(]Q%UdIm9_pAtt`La*!~ T8ˏe]3P)`Kx\&Eeg¿ 9@{_CͬJ.i{8}{.ʍKZhvɠFJz!k3_ kUϬDt18lz"/ +|t;FnCc?HCx$h2++6̨͆ ړw֞st.>ƌitw" 8e3rn*wgǠ!uC;Ά曝_:^^VN6$D=0єܜ|ғqS)T*f[jOs{ˋ keYKS)dȢA ړ߿r*f΃*ёqXYYERy=BHaj]n,>Y&AB8֠Φlm܉ HM?Uf I|pZuŤ.cnעAJCMbkkKILLd@_;v_Fd4cØ;s!.-:v[~cxkxv4oHhZb'IJ8χ1fHNGsr2ҳ; rP:)720L^xUr 3a$@$IqCkذ;t+F\Hpllygk3`Cc.$I,Z-[܊$I9Jb+INLl\"Ͻ4OΘW7i<6x2~N竿bԝ.{Xk6ی+# ZƋ"d4`x8 nחkGDܔ-!tP.vgGnq.kg~Ҩ~A4EAATlNRPP@tt4]v5xرc 2Dȵ_F5Oۻ`yHQCkwA\eԹ8<tJ@tdᄒ1GE@$IbSYKP8(x4Z-'>Ϭx88(f$[@,X2#'.,mp&S1D$F$*6$ <I|;Falj?_;_":"g3_~Gd:1veⓥxisʊw?!ٿw۴ÑK~l߷S1Ɂ5|taj5k^-ҲRJt[,{͖y_6ے$|ښ%SˣyM$zСC$''??^^SeJ%-[uR{аyvEeG(є|JzZJ'G|t֑'z&%"L5=<>m<|vkECCyv4F;a r ~mLpP۩Y`Sg&nD+te]}Ε 5RR[mK= ~ʼs1QGدqh8>yt$0}ȳ1k\&?JNN,"L^dĀ hJۃ]?47]?#0xFou,&?Jhsйk2(ZF_ s攗-.2qSs#|[[[Z=4L.[t:*p:&_h^o'wf1QFC bq///4 Gm۶5H@po"I$%%ammm~A4<ȿVm?V8(ضgsW) ͢ei̞Jc/#CBuu5,c7je˖_zHNNAJ#bVF$&&rʌSUUkOPP(pww7d2>DFoذvc'=mlwȨܛ| 8Р=#GO4g͗ۦL၇=';;۠V=4M'&e\RŸi"]qV ܶ $'^Yie &MĦM1bD`4]x;Mnժ[=-[յQ^HRO+]WRn^bn {M۞ȚsX[[3vX8@`=^V3z&ݩx7b› Td2mڴՕ+WPVV/ђiEk>d28995N/ϚB.|ٕ Z8Xn׼Y{{Z*΂ۋAAAaeeEϞ=ll%euT`OO.[TiTkq=C)..F$:u4[/>_ %舏OcVVVnmkr{w=;;;nd2]t!44THCAۅfMyy9uI@E -mҨT*4F&QZZJZZIIIF{Q @ h´o9qIishNcOTbmmMuudSA*@1G\wo3]MCVZnCPW疦Ȩ]B]Д {۞ JU,0]1ishržg #bf~P _BʀIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/imagens/rel_tab_edges.png000066400000000000000000000435021360462764600243650ustar00rootroot00000000000000PNG  IHDR+j}5sBIT|d pHYs+ IDATxwxTևI&L2$Lz'PC@D׮˵OQA( ( HPL:L8aBIPcnhwp _DlF̓`ONĊ^m0/# ؇`nʡT@ t^`ZξE^w~Y$5Llەl ulMXL&v=={SrtfEF,.d|??ѰAj mh'WJ;2^?]CD·9pMuB |vޛ!nm#alX7{% n 3@ X8@3讥{e)k^TOMA 6v(ݥU8΁B* (IqHY* k+pOcU1 E"0 ļ3S>+b›(=C~4RzQ4F4Ac%0=Lz̔ؑ627 , ug&@m|q4JxiZ/z#8îlXy|{L&F!A{4$g'J @k)"(sߊXRJef,v lQ 8Fz0?c27-]ZOAdAN%Dhaw6IǏ3A AAITJU޺ϥ CGB. 0 $~|/|j*7޽@ ezMTfţԆw SSJyj4Q$\F\\@]I6>6usr\QîHS;Z'oA: TZ',~,;J?_mTwSQT >@ Ww˜JQܯhFnOeV<.WQxy(Yq8mu{ĥ6bYkʱW_;DL v6vxkfB}V$9ƔѳxEg;@ \HXȈ rjIYW? d6 z{C}5.AČ23@NJ̌5 EqahC_[A}iy|Go9!}4VH ~7G`gg[$fRBPF\O'(MOK\{vǰ#n#oE[aooOԨ!@ .z/q鏲١y}2}f=v =@C;[rJ4'}$~^7Mԗi$${SNa|f5DCiٟMi\=a7U$I)%RԵ1db Z3`0mC`^DKBV\&Z{Ʒ[Y3^NN_u;` l3 6R@ >blj:Aд-'ފ[ͯf`ʄ7zs]\ UlOl@RR mnǗR[/lylj:&zpoQ=76&a#4@ЛNՑ+j{ii)MնAC`v7ǝ3󓚂Kr󤖭3֍ 3KiZ-b[ P;?#љZ{w xUy- } BsժsM"l Yw z}kb0豵ܟh%"lԏ@{U燻~BYf9**,,KukhhijW,BfkD)6;I{= dwG! f:s_ llkh40LV]@@ t'8 *FNm:ewz yyyz+9(9SNۛcі_QϐWܺ.=S2s+?a[J}7lOaگ; W>=󡍍 zY tqmVGȌ%duoޡMgoXօg48ީi$ľESc#_Rtz`[Z'ܕm sgWmmeie tiΈ2߯ӳ1ZݭK3MΎM@PCG ِr08yd2{Xo4*2zS4 EVN0/݀v L=I"`42O3Wymmp Q>ɭ%pd `7$»H枊,l5 Xy}Ad[~PZ|PCV:k"=ik pbQLI;.+.eD oBVu<;}swC\@ 88@^ͥ*;28`TfQt7ݵq!16՛*N:'*(MOthO76$;>]%d%a Lh} C%Qqy½QX09$?90 \Q0oؖ >*xz$.LVjuYIOڊ_!vb(ժIY,\ye$mY+oux8@j`}I9- yR kw;ċD ˙ SXT!^|- 9185o(~!~+⎬;+&k'-?:6ˆ||{lH9FDD̪]YRxMՇPasߊX"ch&?1فCZqh2h)Ct0 fa_e\av*dоe `j($ƓhfX~E=uM)vgCi2~]kNnMWGbèyxy\RUӈOs%u˱R$m)4}(,a閯Y7t0qc ßs[g ־}Fg@mYe֣%]&/ ɈOz]B}iac8Wl%HJ̌ɧNQܯhFnj &/ ;'W^4Ֆciן'Eo*E3)w) 2x:IS6 bu Z'(?|K6|7u%ipL# yU uZqsZ*ψ ߕ[[RW*k_f!.ĜiH͒ՕQKı <>{;[FDJ꺬>l%;%y~\o h$)7٣gh %?oZF冯zĈZ Ÿ)(/O zXLF*9Bޏ}]%Ȥ~ޒKMA*M'%Bg>en;!j*2cq QEP&C58ԗJ_zK0' j( H"db Dh-M/N&KV6*K0%;aAj˾'d&ãaBBzYWGg7%KKBvc2|֧[~A XqV'͂agr1uq޲=>#6oء~,=#橥b#2TRY݀LơcE7B&]W->.]\9BQdUZu`C1 !WRo⿤fgASg Q`2zSx#`2H$;`MٓB{CZ_Ƿ z&7ό$5 %h5dT8vjj0Md֦g?]]9jb6|k5cn'Ah$AH6WMGa@CC2oܱܵ׾σW-xe1i,]lOsb4im'6Z[_UGuq9G)*Ϻ=q 5O/}-TfgaEBŸW7<ϴhfj 2s_nulg-M&)QTM-ϯΪ4uj}m?G6&YQ!o{ڢ '|_ONl!;9vN?ԝ/_jA>d9Yiu晑>t2ʖ($Ng=l'Ͻݼ>'t{ 3J7g|[74Q[DE).$7G<Cc ,dl\TDKB& YGASS\邽$ kќyd")P?C,LF5egDere ]eQy艫)O $PyN>쿖[B'deR8Y,G>ߑPyjPyj! ls:IHSK"wI18i]q;uzv#$lūp e;@!VumQ . /6233ٽ{7-Z+/:O]:xP1SS7+..`"EPJTIKJ2+<Ը TQB ['J j7W45TM/=$ٓ0#> Cz?ayh~lVN`B*2]{^WhEis y@FhbcX~L&dXC{zWמVpRo]Deqʥr].*r 7{qF?IM~_/oWiy)zCAwUۮR\\L,Ċ #F`=EqСv wC&rw1sүr쬽GI~2j9o9ħonϰgwϢgd`Çm7!*x`kggR$j(7T2{sTƜSDe^1F,qJ&ooxuݾξx `˫˘=@ j*lBmmmF#9~ x h3 THKu*٤lO꺓*J"haH9x`kwfg~U=;uc g^8;;ӧOjjj:t>F#Fe6'AcOi<)\WHE$h dfgVKOz~߿#Iҗn]旗0r K E/VΝ;III!(͛7o^& .BN;%I:J 4O/̧ػ"m+nx[>+C?KUsױwI(7oՖ_Qp`o޼6|X|IE,ymvK%Ϩ+ϒwկgDXϕ<bI&?#[eر8;brKR& IDATn9' }+ 3"~oI[$;[yꮱ= ?5W_Γleδ~>gU|>2s˙?#{W}7Fk+=IO0"l862rZ[3vfKqfb %;;[9prrb466r;gt4Mo!8MFJ):- dbCpl~y){\ϱ{(LȠUtsA\2#V72ғZ='1 w%|0nKGюG wSr2 jd627GJjx픔q׼a5lM<͑Ͽh21XXkԬR.̺?˯$,PzM. 4f۷+iGx`3ӆNaK!&EʁJ%;z i+71 -;>>>\uUY%>>z6'Yq>wA^ط]@gHX [|T7"Sdr&stIV~]p _:m+_W zWP4l?VL p Ah`0W)}va۴ ƢuZ~jZZ-yyyu ;ܹW;yzzbggm CBޣLghxhdҧX"qNJ<YTOkY]#e{K_;$bOl["j\|ϼBHٺ~-  'ߓ\{OVMȫh}i2qnv?&㤴cLNj$6ƒZ(8vB\sY8 9XuW 3,d{q%Є P8m-"(+MљR $s}29fq-AAA5s68үGg~J -{gg7~.L&I-uTz1+\ r{{f#c^= < NJnY㭦2vSSDEq 7g܃}[L@F"Wp1YJd7eeeu~>G l}sJd+q h4xzz^v +/:RyA)y%4#Wأ]zA㎓6ޯZ@󂜜oj{TrVNaOzߞh"3+Vmll lgowN;572~[xQog߈(\Y\HHΊ@ 8 رc46J53 !!!bˎPPcѬoh28ETMu7eمlilBdNu3/ goQW h!V Y 3SZZJQؓ(/RINa9ٴzK)OF`&ME[vVjt͑v~OI=kbRpq#Ċ D4g^t ǻ^g >cYWUYMM]Eu/VpҺu[[ߪoQkIupA刽[RpA]ڮ;l{a!=rtRtOy[".Zjkk)sޙ M܇]suCm- x5 LQM1)L C~uX=>cSvrc;;W/}|g ŵ,/Vϯzšbrıj.usx8jȭ,G6'ju1F7mcJDkK} o?nJdχy G2gZKHH=q!{pvd F>z/8/L?ƱH>62sҊտ'ch\OX,f짃d` ÉM9u^(6ybWs>ᆵ9yo]A% ~ٚL jgJEUjglld(r);`4;s0WFQQL]~!"õ9 7G))yèkbٚx?Mz#UIPM;ޟ>l{% |U[?p损/e8D]Al?`*z?S˟'0bE .prǩ(md4TZC#9y//C \ =plotJi:}4Ȥ~g\H@ncK&,BK !#5rs[&?roL&[3v1kձkXl[A^_s*e*quQQA<3Ҽ9!>T4I}:HוsMC{;[v9=33$ODn&ue"ېSI|ر/5[˝7N'`~j4j%2=sYCk6KOWղ3FL2?A=rbծlâfj~Z.R"zCC2oܱܵkr4޻-lOZ+%O -]ʟRTp{oy}_%-= 2[1|>ȱQFq?ori2y>zVG)>^ʨ ;{;m#{KLzݱ1{?/-zמ{R]]H89Dc|퇼+[IF#)Ͼoo_x l_3<_ꛟؾWVmXۯ,fXF{ޞiZҠD߶P֑}q7YN]2?pې|  'J wiev2y' -26<5~sV>ۿt!:{1ǻٗǥ!]b}*٥$VrkJ9":):ҧYVBJ/\%8X6'.*rF:<ݝɵ oND-&c[be€q<>\]Xg՝d2\6IiuYsӇMetQ|x;]1ZL .JF# 1xjO̹a&"9Z G!-9 ? *g9g$N{E+?Mc/\ a#XoXr.:yghX&7>? ªݸC<֒x4 ns>NjJd2qaܷ[[[rB.q?6ngHk1 \.| y1TNL&r9C"۽䓯=oŊ4-+ uξ]s_gVᦆ_dV2:oke~}>MwjQա߶2[޸POXQ+W]UԎ p7nuAwk2Hn&z7.dnrff]7iYD"#̯7cqΉ+gZEEɱCqPHhe!&:Ͽ]s -"$W姍\`Bc;ʨq-s6Xy|~yYUUQɟ{楧wӦVїr}̜+}TUVS^ZN`c%gKpv\L9Dvf9+~Q[rN܇/N*'EZY:Ԯ.I8|S-[.?mT#˗" >e3B3$OK_;JEI<޲Ɔ;[2~Wz! W8s8;m F#:OW|bEpQAHX7;;;k1;i\jؿ'r)ރ,{Br9ZOw<V\hd2Q_;;955ױ|VKZb,+-MS/>?rqrrCi{;RlL~R8#G(9^Jcco.~5bȖ=Zfx@ѐvLj9İi%TZry%THX =?y4=*ɉK}ͮEfZoJoi M-]%FC```=f%Qk*Vhr',㱱 p"''ho;ǧY4V:*Y}\{ewܷk_mogerW|[}Dg߲qʦ+]Ƙ555>GF;!HI2|qvv,++""\hTdWExׅ#w?CLt,yIfjo% H9IZ׷+(AfJƑrV8::2x,O^^OHZmqrk!/ {]jI) ';  $'yx1OW_~7š@ͺ|SqPX ?KKKmt-3+ԖA^UU7(ߡizH)\sצᛸUUGd2O˸0VS>F " ,B!#+ԖDQgkx<="~w(w7awcW&.h4"(533C!appnwT>Ng2Q{ʱ1kT3Zh#ߖA('LC0L&S},T>IMOb #l6{}̼o(K2 xNn|700ߎ, &''i~i hVkabBD#^o.OnoaM?:[O0^ϲ\ߡnLMM5:!rY'r Q|ɍk n~;E|{竲A$vEQ=hd2H$M` Pp Q zZ*tqg\x'1L===E"(c6 X!"jQ+:&H;Nth4\gBDT'd Uhԓd @GYc].lC3Q3lp\E_cBDT<^ddY!IrqE(w˺Gf!J!NCӴ|G:;-cJ(˅?bBDT icones/convrelnn.png icones/seltodos.png icones/movimentado.png icones/abrir.png icones/parameter.png icones/uid.png icones/database.png icones/validade.png icones/editar.png icones/moverultimo.png icones/moverprimeiro.png icones/movercima.png icones/moverbaixo.png icones/bloqtodosobjetos.png icones/desbloqtodosobjetos.png icones/limpartexto.png icones/relationshipusr.png icones/codigosql.png icones/codigoxml.png icones/bloqobjeto.png icones/desbloqobjeto.png icones/relationshipgen.png icones/relationshipdep.png icones/cast.png icones/adicionar.png icones/aggregate.png icones/aggregate_grp.png icones/anterior.png icones/aparencia.png icones/atualizar.png icones/baixo.png icones/buscar.png icones/cast_grp.png icones/cima.png icones/codigofonte.png icones/colar.png icones/column.png icones/column_grp.png icones/conexaobd.png icones/config.png icones/confirmar.png icones/constraint.png icones/constraint_ck.png icones/constraint_fk.png icones/constraint_grp.png icones/constraint_pk.png icones/constraint_uq.png icones/consttrigger.png icones/consttrigger_grp.png icones/conversion.png icones/conversion_grp.png icones/copiar.png icones/cores.png icones/criado.png icones/desfazer.png icones/domain.png icones/domain_grp.png icones/excluir.png icones/exportar.png icones/fechar1.png icones/fechar.png icones/funcao.png icones/function.png icones/function_grp.png icones/grade.png icones/imprimir.png icones/index.png icones/index_grp.png icones/language.png icones/language_grp.png icones/modificado.png icones/msgbox_alerta.png icones/msgbox_erro.png icones/msgbox_info.png icones/msgbox_quest.png icones/novo.png icones/opclass.png icones/opclass_grp.png icones/operator.png icones/operator_grp.png icones/opfamily.png icones/opfamily_grp.png icones/pgsqlModeler48x48.png icones/proximo.png icones/recortar.png icones/refazer.png icones/relationship1n.png icones/relationship11.png icones/relationship.png icones/relationship_grp.png icones/relationshipnn.png icones/relationshiptv.png icones/relationshiptv_grp.png icones/remover.png icones/removido.png icones/restaurarobjeto.png icones/role.png icones/role_grp.png icones/rule.png icones/rule_grp.png icones/sair.png icones/salvar.png icones/salvar_como.png icones/schema.png icones/schema_grp.png icones/selecionar.png icones/selmovobjeto.png icones/sequence.png icones/sequence_grp.png icones/table.png icones/table_grp.png icones/tablespace.png icones/tablespace_grp.png icones/textbox.png icones/textbox_grp.png icones/trigger.png icones/trigger_grp.png icones/usertype.png icones/usertype_grp.png icones/view.png icones/view_grp.png icones/visaoarvore.png icones/visaogeral.png icones/visaolista.png icones/zoom_mais.png icones/zoom_menos.png icones/zoom_normal.png icones/alinhargrade.png icones/depsrefs.png icones/novoobjeto.png icones/telacheia.png icones/exibirlimpag.png icones/padroes.png icones/rename.png icones/quickactions.png icones/movetoschema.png icones/changeowner.png icones/relationshipfk.png icones/help.png icones/permission.png icones/permission_grp.png icones/collation_grp.png icones/collation.png icones/constraint_ex.png icones/plugins.png icones/validation.png icones/extension.png icones/extension_grp.png icones/fixobject.png icones/objselect.png icones/loadrecent.png icones/filter.png icones/import.png icones/sqlappend.png icones/keyword.png icones/breakrelline.png icones/removepoints.png icones/breakline_90dv.png icones/breakline_290dh.png icones/breakline_290dv.png icones/breakline_90dh.png icones/swapobjs.png icones/clearobjsel.png icones/cancelar.png icones/run.png icones/result.png icones/tag.png icones/tag_grp.png icones/dl_binary.png icones/dl_source.png icones/eventtrigger_grp.png icones/eventtrigger.png icones/update.png icones/recent_big.png icones/new_big.png icones/open_big.png icones/last_session_big.png icones/last_session.png icones/mainmenu.png icones/random.png icones/samples_big.png icones/adddata.png icones/exportdata.png icones/disconnect.png icones/diff.png icones/sqlcmd.png icones/design.png icones/managedb.png icones/ignore.png icones/browsed.png icones/attribute.png icones/codesnippet.png icones/disablesql.png icones/bugreport.png icones/delcascade.png icones/truncate.png icones/trunccascade.png icones/runsqldb.png icones/flag_argentina.png icones/flag_china.png icones/flag_france.png icones/flag_russia.png icones/flag_singapore.png icones/flag_poland.png icones/donate.png icones/flag_cuba.png icones/reference.png icones/outputpane.png icones/server.png icones/refreshdb.png icones/objmetadata.png icones/addrow.png icones/delrow.png icones/duprow.png icones/editdata.png icones/addcol.png icones/delcol.png icones/delrows.png icones/delcols.png icones/loadcsv.png icones/duplicate.png icones/fade.png icones/fadein.png icones/fadeout.png icones/toggleattribs.png icones/browsetable.png icones/referenced.png icones/referrer.png icones/genericsql.png icones/genericsql_grp.png icones/aligntogrid.png icones/arrangetables.png icones/jumptotable.png icones/schemarect.png icones/flag_ecuador.png icones/sortasc.png icones/bulkedit.png icones/policy_grp.png icones/policy.png icones/compactview.png icones/help_big.png icones/moreactions.png icones/stop.png icones/newtab.png icones/relationshippart.png icones/resizecols.png icones/collapse.png icones/pagination.png icones/layers.png icones/addlayer.png icones/dellayer.png icones/clearlayers.png icones/movetolayer.png icones/foreigndatawrapper_grp.png icones/foreigndatawrapper.png icones/foreignserver.png icones/foreignserver_grp.png icones/usermapping.png icones/usermapping_grp.png icones/foreigntable.png icones/foreigntable_grp.png imagens/model2sql.png imagens/model2sgdb.png imagens/model2png.png imagens/pgmodeler_logo.png imagens/pgmodeler_name.png imagens/pgmodeler_splash.png imagens/brazil_flag.png imagens/crashhandler.png imagens/rel_center_pnts.png imagens/rel_fk_to_pk.png imagens/diff2db.png imagens/diff2sql.png imagens/bugreport.png imagens/crows_foot_notation.png imagens/rel_tab_edges.png imagens/model2datadict.png styles/pgmodeler_bg_logo.png styles/h_separator.png styles/h_menu_indicator.png styles/close_tab_hover.png styles/close_tab.png styles/toolbar_bg.png styles/centralwgt_bg.png styles/btn_checked_bg.png pgmodeler-0.9.2/libpgmodeler_ui/res/styles/000077500000000000000000000000001360462764600207745ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/res/styles/btn_checked_bg.png000066400000000000000000000527661360462764600244230ustar00rootroot00000000000000PNG  IHDR)+ pHYsHHFk> vpAgg܊U1IDATxڍK%ɑl[༷c.QH pyZj9Ѭ@e|QS3o_?/?rWO;|U~7>g==:WMoN+~ \_A#ߟw?c\<}اsO@8C)}.7̻٩ ^ xhhsX06M6t|ow31rpfƜǁ3xq3iϟ|n8wƮ=4A>p~_3i?򮙴yQ$fO{gi,įSq|2~bM tgggs*Cp XLp,I>o̧O|͹qad o'(}zi +tAb Yi`x3ۋfzd6O# p v1;~kprWq>ijϸQc`-c6\f~lr<`h{J/nDnFƸ=1xܨMhO+|ߌ܃ACA3BPK n5;] ؇k06 t|gl%_/|:c ` *5[݌gch왟!;P1}Άf*؜(~i8?ё#ػÍ'xPbXY+Ҽ)31zXy+DF)cwx~19vl^b IiBGҞ6bIN+pbζQ-pNa8yH8L7!vL䰐BdK̝BmB4:%\BiLHgB24N5W$6—;N;U'%43$%TCNbF͓B]b$d#q'oHd{e=4g!ȗ;3r3G4zP`|(qcnH & 6 y / NhMϒ:Oߪ'mV#@y@3/N2s.А_vךW F{FH實omAڅۼ\9 X*GpP2u N^d&NLJ~*hiLE#bVLKPƘD:K1slԞXC' ½icԒ?3'(RM-8y#4WĚnY}*$"Y @/+LKr A? ?Px'Ou6V؄2spZL=c~=;Sc觑-s^wN4ȳs/U5B $ڡ-&7]c2fhy>a2 6 nn>^QpοTRn9o9EhF"%i5 /W!ΧsYBL&kI {&F7[ F8,{!m~ysp'dV\)@j͟^dLlӄ^_mٓ6=Zq0>f #}&qZ:"M9D 81| Nkz4^/vcnh@?{: ל<#JfCY(/.`gXL$ Lf#3Tnu_YΛ8z)}3T}M1F_9צqsw4b6 ]v1{h>&mN‰M%ex&؄]*`c:[@W[*[$K*tE: \3|3s3-1标D|jոcTFjq6dț1 >egV`x˝-cyrBZҫL^DjڦdE|f:̝ԁֱ /fbx>|٣q #p6w`08SQ_֦si06;g"njovFd􁪠ܺsLRgA? \U64vp9dY=u7|ۄS~O]\a܁ƛ='@C2 4AMn{{xu>I\u~^{vޙ ͫ3,SrQPl^ @v&߫VzeH,wH$5-2^x&ql5X@dL7n=Ƥ(t<fO#Żrm g>Հj0GI:h@f.{'k&Ws61 UٚE\H2}kl?p=K%rsNأ+{: 63%a rpA>w5&gҢFY nƜ;!K#TK-nܠE+b͸ZtjG"&F28s0Րie\`:2tb7ۇ6@Nisz{-uLGgMny"2!{;Q ߎ} O%,K[{ Dz,|<˖Tw28>N@n%1V9 JwO6gxL\k[{H_2 1B Sˮ GH78-I4YgXODss 3錮de_շe^}yhwfގ}I]}=$`䋅TЌ"wID7)%DSGе>vW#c>9}:ߧ=o t;6A~/N-h}飢l0y9M<[&9T Z2" aYӢ)u;FacDrj4nlA)sdc~pxAMZrH{v-J ENZ1T:3ɼ}91ɰW6FțYEK:T:\?!C=foM 1,8IWsޞvg 4@}M.x أ)ފF_iy  >C] BZSA $ !3j'D =NH+m=Q. Om8@,rDڿ% G~4ivU'~+ȵ{w+C4Hv.m8܇n-Z@GmDh3?6^4< WGL;0qܩd7 |f ec]\jkp̴$m8p8Kt]kƖ'6&{SHJCr{>}[3ɕ篟qyJ'탇)960| ﻙ=U `g{f9)#F5G]"AcNLI&'ӧv>%A"[/a. { #҃gG6brAY8ew`*R;6yrdnv;F}ɢ 9f@^ɩF,Zq|JA- 9~9v=BGD,3 LV\#8jr{.A6޿Mq 9}"FA6njr̘S*^7T᥃iG6؁υʹ3v>$Np]qWbCXGɼ'͌)ʎ{ؿIGu/E2O8JOٷ&pɘ>@ň  ꟔W۬H}yCXl1摑ol09d`%ALذ5 7hqQ7e$&cWF=nv٭1kM{ZYBPGǭo}:'x:So3>C)O P)J.YQ>G8 SUЫا:l t2JęYn:|cg *}?iL. }e075׶njǺAꛡ;%]qy!YC`:Jr^$g0LPB m|ޤBiJH\eCڿZCs\7SSmswUV{a.mkFg}k1h*%9q65r=ؒDŝ s0uOq=qlC-Ȏ{*Of|SgS"BK(l܎6fr?^+'#Yxk'^ 4d9^jbO˧"Fpb,9}c[j(܌ah݃dk^pww䲳R&]g0/o@̛^"{2эmD\ϵDTl?_YTx &s.}q>NuV:F8&]̑s ISVIk0X]$}*N0=Z8!aզNk]q1C8\b盷ETNe>myoFe:lQH#kݦgo&ٸoN,Z:ws,I]q9a;߭\U]^ucfGQmp+ \phDgK<;4K KהJ 4 Q)Ol" B !*Dac v1Ʈ-h5N@ ^d lY|L]>7w3aM w$_Nw`&Ul~ۊ̸|N1Fy6Y6/h $:xȳ \,vj&_H`:ЍRS8g%oPbczL>+dkc;iRE.t22iB>,T6d=\ 3ZLc_3-.E;f![uzژs@`EV ^\q#^v#ـ&6MuNޚ:kۨqCqNQ#2 ;MˠU÷2mN`:HpEAl_vR ~‡}BL# ;iG`v; 8owY-QpҚnXERay0*W֜qqN٣L\:W'*p͕xI6!m:]b hҶL7I,~ 94AsvA "͏>7\I:{21mJ2soMN |\mSCesMHѣ=NSλzSxKg`7dss릦 %ʲ>&[8驛9qcXC"y W hf 1;ޒ$~Wݔ22+E3EڹP/~t6f%K5B +ڻP"9om8AψSaA|'O/g37ױz& qY9\{[6fM wTO'2ZsŒ|C8 |X+ l$Po$Aw1Gm! pIdtٜG:f#ȜA&>@@+7:mrjs|̀-3d' nȸwG ?FfD< iX4M1n]S@Iި*sOG|v`d)pSb'z_s^c=9fGMܖ7J9 kl_&|qZsIcg J8=<ۘTlst x$ٖ~= ,{Gd& /ۘ"9 4B|)Pe;S㔑_+Y9Sq&_s:yV+Y8 nnWX"ĚgқӧElYCN %f8 T(o==wɈjuVfhMo^2zzSĆD 'fw-E=߆(!(1B`0uut~J7<s l#g=#`d#w^Y`^"{nol DSBj0!)zb`f=4\3*!K^@ #:CsF{K_#/'5jpA|dKͲ Q;KԘ0nF1*m 2!aO`~sɠRk}6LL}TÆefԣO1ChJ\$$n6-W4&_Ǹ%Es:lؽM̘;4ow2؆sH gưZm ]2۽ ߺ2 >$ERgD߾V#C -ÍE+|ܴw-0n0g|:y#}$;7PɟvMWcybFac6& "јJsD 8}|OrCIz- 팙]Ź72U-%4 nBN7!f՞0If4*C+n`|Gw>;snLqr̩Գ%I7@Tjr Ϧy__5L%}!WG=^,"df5B9S9ʑS,>_xu)z̆YPxRӽM(d~(M(!s9ZiOg7Z@Рŝ{}|9Oj1w&oJE%ҥ4 kC C!<ΒF8@Z`ls8z٘*9N1\j8f|eG|ͮ${/̆t ˮIj,0q?V% AO1RTELÜ8.3m1%j47>˯H/^mo{4voe744θ{Tv>! P"v$3l.?Mr,d"3YX1m%!t/o_ Ή\BJ!>Hf̛/0`PfN t~ĪܙVɚߎ!h1fRw5]x~:9 7s6lաRU@de{qٗyI~Y $SN0F*z} t)}iY5YzKh~$>ܑ1hIgSm՝/}'`w0 s.e G{n! u}L|tPg(9Ij'ؤ&k|\P24vYGQ}Z7#$&Qݘ(Q`3LݾQ9.p~R֍$UII{Gn{fR:;.=5]Dڒio;SqpjBNfYX, wO]zx(zvn5 gůqu"07hM!YgQ6~/$wvOm1>X sz;.miq!]L$/#C?^ #4rz_Hdl^<* !wŃo|8i $tM{Ӡ% ۇ s(e"D &-fV/{t$sR)a^F΀p޾p)& Ϙw2 ɛb,o9-`KoYN#)&%b4XQq=UA<n3Vνo ܙoXv2C4p' P&gf}TWtÎF<'k#' ;svrME0"&4; xy8xyM}$Yrh59{ԹBMxg's;>ǩlD^{eo{yOZTa=X.܄ <#^3DrnQcx™f=}:?f@0zzXvrbz{VSy S2-:?΃%|k5S`9*?vfΛmOK"x7f0bl/]:!f,4"n|6G!>|<Ǯ30y͆EÔXqʹ:' K2%:70!wX,^lpi(17e  ty?&i$*9liGLF <fT7\k)xL/0Jʜ6E~ZqUN}r*7\n%pq .OqM*tnmiF>i`W{) wropĔÉYNk[ =J)! "Ym(,s%>R+G-"w+t `g[i!1lI|%^ڷHrO,4uټ|_@תn8 "@G/yo:$l(c[; Sp+BXH7:8f[yy/e_k@,΁|r ˯_RsӾ 7_4ro+Gm9cpV-F͈TMNrdS fuh- 9sDW^ ʽX~*` F0)Ѓnl'-dJ537G غ( UBt&ذx_[]=ʃhA$wQmr;nI]<0vO09Bh?-}fIVT;P5ݳ!8"F@ w 'Qxڨa48wrƺ|<7bzoQTFPst't(JNBTcc>=qÇpӮgo+s :SrSo MlV X| 8MY,g,M=Ǥ&0f4DŽ̒iZw~GvdE ;u:%/6 ٻ2p}"2S x3 af61.#X?$+%򣎳JvWOZwpЁ:-_iۋ7e7C`pj>Oy8:שnh؝JN#qߨ]NZykAha`{ ivp"Fu:CN35,]$= H~.˄ȩgk^h1rP3lz|dk .Zf2!z>>,4M ȴxj?o8L"lo5H*fB{mwhgK:˘1W g -{xzB#S4H.؛RpNТD6#@z긼3Ff] E1ܓ>O" 5Srsg#-À'dOW n$x,cmY^%X`кMOVC_<lehX_ɝ6=U>8l^&41[10iZHG3M$tCr]ӵm7b'eZuEv~m]'Ic2@3Z:i /YVegr5>0*ZCQd;}3p7~p&&$Anߜ:}FҖF {'`2%-g9PX:@&tu]fLaAl b8z~{/$-4 K4V@cFwܱ'N`:-w4%tdzH%w6{md)HViɃyƶo +ݤ^4:SɄ7 :okgbqLᥰvӢo8@%Cݎ{"zsF܇fM>mjݡLPve|{\yOE a9 UE**we5"Obxq\p_wl~t['4pHoqO :kn np{Ȩ=/u@NX>16{oMrV31k~[ +'S-DlؼڻCe#ӮoW#fxڸ(im`NrNѻ 8(erLk31p%Knb)=2o,1=-Oyzַn䚣*BE װq $ |}ԕ\+ eZGp~ uY|{p^ ߚ[# ]Drm*Ecθz9װՄw2y Li'^Q RAǃf4,ixY#@۽ Fml~a-k,}%3^7Enu!wˇEuSӡ~x =A-ɚvx{3N٫~G&ϧ0C0yƍR3Y"6 ; <͹D v/at-612cKLxvR2߼?W;YQqұh 3u=,tnEa]0rȟ,FZx Hfy'Oٰ\#6~5D9T.iDCZE a71dz$g}KR_>a؎&؛%|73-NH85-6 s҂a`BӌmaR+n>.7epk\Y `48@@/J Pj36{+Z-yDƥ|_~7L+L*m)cJ\nLn4h}:n!po zidn"zHlHNkTAMI#@$=m14qoN>t8@vϰ{^1|?JL麚F%[zCm;Mmpj w 4pk]q Y4]m·ٽ:Ǿ 7/3H=1[e}"'mYf4$L3v05!2]Z4`C a#Ncx-w!̒$V8:zV&w|{$(II x>Gk!?/wJ8Ӡ{ wxW#ct*1x?n5荖LٚҦ2>!pGɧv:d8XOs)>Twֺ`z2H,R9Z3EohЀ/^@kBws& t1't: P~!=a|baI n|P Q7 lMQu91`;f #`i'IӴROw7$Hm~2M)qÅ!fL>8`3cp\q Jll#ʼn3|ߤ\'9%*)Y?'Mrvdʾ@1ݡǵvw $dƅ!ѷ_wa(QOzgUNr s,u1U4fo K$Hy+ʹ(n|G ⍊W =gAD.tiPtDv矟-?RI8t$+RzM92jJAMޜ1c,)W2 =# wOCW2dmޭ|Q^:c㜃 D)?uIr\wM 497p7c#m$MUh94OM̑lI A| [(hm1rSx ef ~l]Rk7Q xr'ܷ^d$`7aT- ?슽l a|Xct\d2XVL"0hXK0qy'xM"=IM<焍Dm3_䜃xl&k>L &>mฦ·HW`rSsmlSs^џJZW|>M9Q@fI qr1-&u7+6l4܌"O;Ѡ}6iw9eǸ΁?3}f<04.%Yb][W3~]-&k7NfJ)1j`~HI: aLoˎXʓ6c58H{p<+lj$[7),I@"- v?YaeЊܬ:,|N -z$FucL?}31zH6xr!Q8M|C@v,}s I4N(U~jYRY/!x2!Krz&Oqk¸Cu!sيaiqYK\PӺ.("/˻Am AKow9#`2QXpBR>8.JMf#uċ Fa[@Z|!,x{I7 &jMVyoj$d,|O^`p:n@ws ͉XFt~izl&pJ>{mo[SB8+;`n`Ov3> YX,# pgOȸXB0A*f~iĶ<}͌"U1ssOW{Zn²E) kY=7 8_uvjufq}PĘ|05 W85kSPs !@H(t|TLHd~A$e3g>ɒKy+㙱dՄˆGTJxAfKԮE'b3H>̨s-[E|9+$!mzG?C%1%U@4p= 3XYm߾8`p_-3#J tjI쫜wzL[x!kYfHM\Lf <_h7v4l]>AiUec~M:Mܨ@߹ǯɩNNaXȈxܕzXX -C%ƝVzn}sn\ |_/|g&zs2g}tv eՏCo'o%jIpyq(8C RwW%tEXtdate:create2014-07-05T11:08:01-07:002%tEXtdate:modify2014-07-05T11:08:01-07:00U9IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/styles/centralwgt_bg.png000066400000000000000000000527641360462764600243420ustar00rootroot00000000000000PNG  IHDR)+ pHYsHHFk> vpAgg܊U/IDATxڍK%ql^!@M6Áh lk ˊ#Kud#~?_?/u~wo'||{*ǹ{=^v~u=mgx~uus|oz}^wy7=:WMoN+imp^u3=[.yZOO@8C)}/7̧٩o3x06CikbL4T8/31ܟq߫pfƜƁ3xq3i_6s0vMy 13-kyߟI.L||({_ch334橴;8&6y"1vF"4y;Km3Pܼt1;6! m5zpuƛ9i@sgcvX2>vkA{3DwޟF?ӿ:۠1xr Ӭ40C< cәE3U=2'NO[zuyˎA58Rrj84g\1q[-k6\f~lr<`h{J/nDnFƸ=1xܨMhO+|ߌ܋ACA3BPK n5;] ؇k06 t|gl%\u '5FlAECsl =aLL3&ʅlo{Gc7A 'c!fmHʷ(οÒGȃ\!?0MgH_< |H`$:Sh$P] z7Cb$Q/;"'\gTtK5蒍78mvϑsK|8sǡ yz $ M:4NJ{ڈE&C;IK/opÉ;۶D0"D $־: !L31߄1B Q4/1wl;y/ozMcB:8\Dv _,; V-pZΐt9S '%o5O uw' -FO>({h&s+B/wg0$f(h\Qi6*L.lx:oDd4 ]1k(%LP4Zdelp9=夐gRٯ%u{eh_N!o:5K %rf(3*~mgVnr8@xCp0n?Q\S^a^;x:.rfWMa DZz7#?R0[zFlhKP~[},9x4! O}u`IgK޼/ `pY2Nk:Sq؟nc ΃pq2=]HcRN™4\z&ui(M=Oëӡ @[!HKxG4NI41ɓe9sH;C DY s{FI 4AqϬ'T#~ &]fx h3oZEIߒKŤ[\U/b*ŔH j$`듘:Y80ɻI꼼b:bijD3Nny5SeN0m|g36|yk(N;kS={A9cfތ4˝NY 5?Yf+ K&LNwaIRy̼ uqNK%s^0?#߄S>+Q*įŠܐة9aZL=ŹD͢E0+!xN? @砂9'9Cjf bZ% 􏥹=@'hm&D cfNP<:: Sy'Sb~dGޮM0 3OeTRU&u<Q>&Y$4QieL avF.um){*r+!H mw6 Uwh`wqMr3J\ @ӊs[ !`!(Mܡez|k?TjE^H2zx#S^:y4{bPKz)  IOEɦn0xF{*8c[nm,%gocU-> 3bSj!m`8#9t73\' _d ܭ( DSiD0486=K<}vзMZ^dͼ8VL#gXt-:9_B/I]8!35A3N4;ʫ_mAڅۼ\9 X*GpP2u N^d&N&Xg%?4Yp1+{(cLd"m9 jO,}!޴͊mljIUĦ޼ ??[@rD&OvZd k_HeeZ{I!1Y?UOW"i1VrV#jp]fn#=8d1ޙC? dlfzw"Ms f&{N  /n14F7h(\^x L\{A,DR:}RbtJɦoD+sC31ьDKj_#C1o8pYkJMؓA6 :Mo@N[pXϼC?nNR$մ۽ӧ Er Dz'm^=Zq0>f #}&qZ:"M9D 81| Nkz4^/vcnh@嵟=kNGl!,qn 3,SF&H*B:, 񖾎Sqc6pi\XjM{1M$:0vc=^"FHR9H"3$89O/8f!@W#)gd8b=Ϛ!j50<xWFj_jy {`0j#کgr[Xalf{a(> a/Deh4S=lL8BN3C  0@l`_N6f I8Q op+^lcqXg ?c^%@.咦-mN? wf|e7O vw,4HMgN@:\љZvf6+2''Dp%$E$vxmJV4̇lܹ Nbbmq C d-C!q|bWڷ6ݜdMAцQ?q W;~3"T΀X֝cf::3'pVEO䐱Vf$;l)oN=EtqQsovktsO\rzͬ7kpBn!&F`#m锏%UcPܗ!9qoHc`Q9o ^k1?e@ŗĚ}k6̜Fe+H>&G>geRPk#}vl&c>@$5mvd'0\8~ 6{=J7>ŵ G-Wt|5mgJ?֓ A>$Ӄ?ys$U_yskskHAdc 5>p@o (j%⮻06i#s3W er*ƉnSG{gH`w=qeb<8[(F:z`NrA#s?EUS5=r4v_p%u_)j&Ϧ^ k*d2w')Cid-;=ywg," e NKDNYq5p/y\VS31mbdOHD0=+.*D/z$_6NcZppBx"@^028 r` Lf";/u%sK[_aK63_ۦS+);b "qw=xZ@R.$y^-;J&rh{*Y"1|e=㞓7oDF= $uP$-9qo]ٚm 4z{o75+M2A!(AھG~/,K_ k.7o4ރ)q4O0"qɶu)w$D}o9w0D y2ZD9Mŝ^SJq#637br3>>g5&gҢFY ˿nƜ;!K#TK-nܠE+b͸ZtjG"&F28s0Րie\`:2tb7ۇ6@Nisz{-uLGgMny"2!w;Q k='iShn ƒA/Bh+)" +`Ʋe1՝ ijOS6[`U}Eg[1Y;Wmues, )64/.F֊'‰ܖmȈg0mgHIqW7]{49¶%y m4c™Xث 9 ԝH$ߞ~fgi"HFr#pI#[9.TBw@h @l6 u}o9f T?K|pE*n@NQӋwe,9Sǝ4(ml0ǀo*e59cB,$)0-;ynʡ s:p::g{k;>k]@f`ҳa(f`vmVK8|F7_?@ғl+vig :*ng::OGn\ZMĄ/;DQ|ۖ4<{qs3~iOCBi^Sp`1Kt n=ߦm6mRaD{b9O%$-ϡ(_txpyPCg}yh؈Q1I1gCx [ID4;3`oGUq# hMXI(ґ{D{ۙRB4uD]cw52Fsxܧ{zo@o"[;"aODOdkY4i2ɡj2l S*8ͤ]N1ܷwY5 _#Sqc Jy=&σ F lL6pޖCڛmT)rt"ע{҆IljM00B*]zpeM*pD oOlm7qĨs&_y{Q52&^l6B#6M'`x+M'Llx/H w)r 9NxjFN%$̨yN~,|:!!wyZl_:gho'47p.'9On|;:۠G]Du޻[|}w'`vDpnSa>v; oqRr?n#B[՝9yDI( ?je21, C7N'm; 5_V|/CR#@-][c%!h9YZ˞ /0@8䴷4Y4C=Bg=Wzk#5\y^}&)(۰q3f6TY/lMؚNu9'3}&LVڡ<lA? 0@%6K&۠FJ~ўe!TGW]ӷS#Jmғm6q6Er̀S9IYZrrJ}{&{-&YfM+"FpF' Ոj]l_ڹsE&#-çb0}3cNexTS9 o`>7F{'anP;-wIf] aA&OS^dq?oMo!1}48?)Y>jWMٜc`##v;zq0eQWĮon0.Gc73D(Fkd46nmHL2Ǯ/zĝ8[c֚&C[_txOtތg}TS<O P)J.YQ>G8 ʩu5RMDw{iD7 ojiF*XUGuKOM:m%̍r,?ho3QIFziT>݈ـ4ЈW&`ry~e075׶njǺAꛡ;}%Sqy!YC`:Jr^$w0LPB m|ޤBiJH\eCڿZeg3MbsEc+<` +_0p, ED7!r=ײRIdmS}4Lc Ϲ658QBUX` ě@v1G1n!ܓ!`a&B;H6Uܫa"{vgq bC MF{OLjfjcD NG7o9}V}8N:-uآP?:+F6ŻM%@S0Mq$X"Yviƽ2&soòw ~r}Wvy{?zxEIe#@­+pe}6R1.{@Z.A*^S(/Ұ.D\#r)|ws<]6הt}% uw>}&?[Z=%[75],Mv(Qɤ7IOar*kb@0xOHsN@H즔?y()噫dn*Xbn6[KUbkghH/d/߉>7U#lhmk-P_|*M>a_>F-cc: 8T)I|wЯP ])͊O3}m\G<7uB>O#1Q)gȸ{@F=<"8qd_ Egh?w#lGYv(CX((b0;p*zUFBhãY z*C߻sΒ=P78f5E 2m6߅ qBX)z1GeP0bHԨ3pY~>fw/E#vGy~ nT,"zw7t+SSȯ83O[e/45!sy`>w> ^HmOؘ7p$c?%+G6`jOv3ⵉǏ!@-?8@fe\%$E := \ڃ釛"vS+mҝ #Gi1ͅ¹E60l\fVy~H4iٌǡ,n?'+v؉9vlEmɕFt!c#] vDM)jW[z  8Yw,4.Yʽd1,:"qOߡ})"l3W-xzFײyOJ/_P%! focL r9 Zmbv6'$?Q=ن;GtWpd8ji3.͇e{q87ωW<$H)NH8b0Տ0FCpn@9#C%Z4'tF9;M} yWo.u0lB [PgN#ܐq+pI$~U͈x Ӱh bJ kQ! UR3OG|v`d)pSb'z_{^c=9fGMܖg=sbsR\^LHF.k%iiʕ 1qzxh13ASof[0cw'lclr? $y=!NwH1OSFR[KggLƙI["tNN3Z8g\ıhE5wx2jOxX~d65$ B|>}@_mJR \Ky=,nu Y hSrӢ'$בf=iy~#6[s:DN23U>6[O]by267ZEڬ`ۯFp%ӛ&6^'84k)26D Dގsk_t3i! <>6{v3Kv<~X>/ V V{ /VL4%3hJ' f?!jCj5䕡tn0ъ34l5rzRs6'Z7@v,ŹرD Fni b}^77 *. IֳgZf#_ 6,+5}BSRM"!qli 0:()c]a=,0mb@Y|6g6a ?R O; л4d{sA&u3dB@+bJZ&d7aiX``tE@#Fkw3,I0yZCH[(%\mTI&&dO99 "&hHnm7?8D!S?jqgl7w+$P؉!g?CZ3F!J<͝Tw;kte9x:t@$eѸisްdt zUuW;PF gD`;[dۧK4[Nu#fLlކ8No+s' _P; ltjU΍MoG崹'jo2󷇕6pBd:=@g)-7 S/rc;-o$>;7PvMWcybFac6& "јJsD 8}|orCIz- 팙]ŹX4泆[f@A<ge<&J>a?w$S,{6WlmoHiNK4MءY'Ib>@s}';~I~c&ys3)|(SBPOPKʹ`^@/Թ)',ڳL|y<ьFe`Cb{ ,Sݓa~gcg+ǜ O=ˑ\t N.l7Uc|Tb?ϹUNt TxG_/;;jgv%Am+06'.& pR0[>żvޛ1oEB:1ym#O8rgZ&k:ňIk t'6\gDU"kJUu*Mپ.g_!n&y7`u^f%t0ޏFL]~v;>; Wʦ;edi+ʣ;8W6sG@Ơ%M{pTwwI&ޟL67Xi_/lҖQ칅7yl0MoJ8z}ҽ6Cߡ'`:Xqk|Cʴk@o ڍftEj݌DwcDG0u"G6 ʻ.-KY7fV%% d)I?c\}w]zj<˕V;%-23R wԎió5:?X:;cQ0 _`۹$ rՉ{Äޠ5Ye0:ßE$GQs&j>wD8,(f[X=R=f\pH fS I#4}t[L*w31($o=;b崀-e9;;ޢlZ`]&GCp>w!q[XDX:ھ/xrga`]{GB-t@+'Rm\ Jmf ;<7+O4wd^Ջ`DL)iv8"pHDPwk(VsOcs<43%CO 5 w| Sو2` 6ߘ @/z\p ; xͼNݢ;[څ313z-T!:' 5;{:?f@0zzX~vrbz{VSy S2-:K (y; 1)qP!0fO帓"cqIȤVTw<5]<{?aV)|0so{Z"1fNj5܄qcӴͅ~ m|74{eqSDŽw0ćGؕ|rvf0ٰȿs;N9kVp@rs_Pe dnke؋1.^83S:q@3QjFÖvd pCO~ofLuڼVpl #~xim3 a?4@+k]Uy!'rVwи$J0?FKnmvnp'-GDHL9f`Гzd2 e-ކ2^Q#rTْ -Rnv_;,`+-1PM2']u}4o?̓7L [#/ԓwKb.y,k=01*k;8lxgwwYȎM}`V0z=&jPŚo`m=FNvn1"Av+Z8#mqs`~ JX3]gTDc b'ICj m{7_%u :컓C %[MSBՄwChW-;sqE2rNLd "Q1y6Er&4* UPiڴC))H7ClM%xSӻd֜A$m.<u TB2ZF̿ퟆoA3URhaՄxwo7t~6SX-}o;spI|?xm3026YvweRs0i6ӣDbm >i օ_ ؛!=ܣdnOUꂾ73dh3TRla#-[}jo'dc_Ƽ#q1޹ yD5 &(O/p-ӼY8Dڸu\7 |be`D-@K8Ȝ3|. B9z*hưO{JeoBЍ, +Aԧ5߂T)L 8w? :lGʵnLm㱜8[jj-@rY̲ fe7{VYXLxnfJo(:t ;6O`bs "@&x_!$6yIZQ-.X2'~mHgDILӍ֖q Ru5R6fA3"D3[gT ab+mN sڑ֐ay?i(h S7lE% Õܤ`#d}bf)< e5S4 t0"&wbV¶F©@jUJkŒHZzH_LytQN*'=j1P`olw[=p zw7rbnO)3a4H6l! U̻u' `0DipN эu;ySsY|ayP~NucG^PrERuҊ̫^|B sˁWސf 'bT'3$>SSUK'~b9 >|ԫ-[j՞~^lmCR 0\CÌSF} M8@~cZ4}H] -M6m &1;Qs0ߝ$ \7`pcrlj6#&v;J7YU)֦x"*Bl(;ct[0KS/W@fIi4I}YL(â LՃ͕mD(߆hAfYnK{$F&enШƹܛ5~I'i!oC-wsm_>0H,,G  ^b[$Z!2s YB^$9HDo40<8'6S)h;оyD-lC:.k YCQb&{}6H͔3a+7s<],@t0hݦ a!/C@6Ӳ}V4LCw*{W MVw&9l(l2 'Dtmr{>mXIVz݄ct$taLl=}Dz*;QZ:X$! 񳇛64 $ p+i3(/0g;)1l9u5GڭŚ 6;^Z7cu 뗜OlbcpE<ػ}i$iqpĤ $,i [mxsο4@!.2g-!`fK'<:x M AjSuw3a/t+< xs>v Q6u󈮳/m(ݟ`He6.8J_\`Nnq,Jy|bZnLf 1yjɻRA}4y bϽ{K9q24}GS<ǫެ(越D=5,jI}3_߅=u%c2W!#poJvBVƑ _b2s]^D(p}fx..&~@JX3^5lr5!,[ bB=S餗azT2vx ~o =; Gy9m^ֈvhwhX'azćicqȐk̀ jAhO足Dߛ7q^'2G/.(6Bǫذ h zzs$CPN3!n:0x?/d)wr1=$t,$ܠ!CVp^;LmvE `' tِ6̩6FI{xuch~3$%|p*/v a*<0b~9 u5J- vR:9kiFhĽSmΗٽ:Ǿ 7/3H=1[e}"'mYf4$L3v05!2]Z+ h>;"F,2+.-["C%Iqt׭LNM 4γI4Q97~@צC>/wJ8Ӡ{ wxW#ct*1x?n5荖LٚҦ2>!pGɧv:d+pޘRh}F u#_Y e)YNɹHs fҳڛ"Ѐ/]@kBws& t1't: P~!=a|caI n|P Q7 lMQu91`;fᄑRiv@cW$6I{?&}Yu3|SFniԈ1AvE8x%6\'9%*)Y?'Mrvdʾ@1ݡǵvw $dƅ!ѷwa(QOzgϦ/2=6Kj]_Ls2YD-RJ3-~?Cxsk8OR2+LWy %PYM;F`b%J<ys`"ͥt@BOۙ(^u9ΝҼ#\ÿ8V:TzzN 1N_OWfz7'?}_yp @@HM": 'hq[)̳)76}ckwxB|cYw)۪=zGR{4j3@{2"ʘrY=l':(Zx <Vdd. i`NU0czȘOzc c6r/ghGKY^Cž>AD.tiPtDvߚ-?RI8+ xMIf;vWsdfՔ9!bYSd*zF!w|ūdl[!49,t 9R67NJi3K $snn69FH0bsh(#'@xQڔc&LUغu_:ּ;olNon1qIoè[Xd;{@!0,4Hxd/XVL"0hXK0qyݳ[#$]M<焍Dm3+SrA+f1#x_'*nDpI{8i!?,&}HI: aLoˎXʓ6c58H{p<+lj$[7),I@"- v?YaeЊܬ:,|aXO^x@A&{]zǙ=I$XAxL<9e&> ! ;>|Nxs-J(2{6bz:!ke{{V5iޭ4rpS\hi00&c]~='l"xXZg\gR0=J3vZ]ey7 !(|Y9q;L&*+NH*6/p^7cHwo'ap?$6m!;4_K:emF~&@ bcFI#Zfl?I+; x{ߓW'츎`[;鹄DPdix;?4 K=P]8nCC!l0G7y'I;MDc[g,d l`ّγq HLd\, r[ 3 ?4b[>fFZA9ߧ oDu-7a"}5,2WZݿ@C0G%1&7ߧ?l?iM8NZrnH%?6 ]#< ~;i$84_ OE|j^xf,`h5vD9FYҁo!fщc-ҰO/3*e,*iV<FΟJ` d!eHv@9|Lj- \{4r6L87V۷33'9G̈Z=* |4kv2 IL!GƎF8([١l/I;Bu"9ɉ\? +p8B K!|6eh$¸?JQsmk=%ޜFqBm+tDmc8 .:EcGU7۪GKh(躼[vUQN֬ pYܸxB>0pV`7G2{8PZZ>՞s_HOU*1J\LDouuDV䁛|Q`|cT QIjSãDBߏ9]7r~#7D-Duwv+ƛ:;ah7@ۅ5 p_PUR<#!D^R.caD04&B0d=4N'7F";l04mP@1Yr_0gҨ DDtHdC2LcAlɪ\a7 @MU+m$RKDQ n7ӃKl zI/Fy OCׁwѧѸ ŶY缐N^JȧӈB!?ţ!ۻnń n[5F<>AS0I 6z6!ՁX`(J|X ̟d7-4|8U@Ձp79dzQUZ29eޕe~z2{&2=^c%jAx`,"˫.׋!kĭ,s6Ɯ]dc2y;#Q83-ܦD8 |?iܒR<¼HҘ߈1gsvj291,< Ҵ]U9 vvQ[MMpؼHTWDm%׋_<| 8Nbk@CoȎEƈu5  'Lk9 <@WiS3DmDޑ4Ing>G4uX)D=Je!(imĵm;-Y7 |U 2|Phx˓BԛsBk=$_,*ò,BF_ o{~Tz}ogu^,%) Q؏#򨳲b0ߦ\Yf8!=DA;$ߔzW`@&I/GCkNz 90GـI@(cE"O͈9P6`v값# L@@]t)T1mJ7 ؛ D8&N;jDISK`vX84"!N4UZ}Qmvs *IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/styles/h_menu_indicator.png000066400000000000000000000007071360462764600250150ustar00rootroot00000000000000PNG  IHDR (VkbKGD pHYs"" GtIME;7DJTIDAT8=KBq^^] ,@("1H}Ƣ& %Et D-ې4g8Á~< ۫Vς}}W)9_gZoįG~fubս b8e-]B#]yHdv]h03t*_} \Hm"(BCpd~ԑ8ȶFauI )ts׏Z}V0l ![8|:{8:?S NKPXXsM$!7n`& yk~Yym@Cp@n[ |rl? T~1YgIENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/styles/h_separator.png000066400000000000000000000003461360462764600240140ustar00rootroot00000000000000PNG  IHDR#QsBIT|d pHYs+IDAT10 φdu:t)pIӶ]m@HO#}R I)jw328G;u-xM :oK쿫mZ6[ b$*IDl"ni۶:R+xxa,'IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/styles/pgmodeler_bg_logo.png000066400000000000000000001447141360462764600251630ustar00rootroot00000000000000PNG  IHDR:bKGD pHYs  tIME .s:EiTXtCommentCreated with GIMPd.e IDATxyfWU&} 5*$L!$L@ ( rh8 זnv@F " BL$JUꛇ={*$T~{skg=ϳௗʟ ]`}v0G,?éq<Ox_[\Y% 10fggj|kݳw/cٹc .Kq*~F~Ek7oys7Kgqܥlmn<~ܝ6ȼkXc'N?NgO}ޣ|lopw݄<?b)}VP@-rr'DxsD0&ҿk_Hŕ}!6'Bo&Щ;"?/w>|x7[;y_C8m&v a&o}_N"3'7O}V4rҝ'Q㈾kWڪt<'}^*سO;0׭ܼ'= oD cP\].;fo v3/|v""ӝcExn˅ Êp47;eH]ѧ,bD ]_? A $=_J&XW&h~~8">޳wǚqY!VǎxfPט,?AD25%<龈 =`>~͒} v-8v$WU(Nrr;<c7b!qD=.m] 5(2b/Lrc$?PR҇ AbIo [z˾v+8}ΪBv`}scPFO}X][yX ",B""!\<"SdH̼1@Z""% 8OAm+3A)$H q9=@ɥiIiYmͤg Q/,@OZC/}.p"R3fxkSxkTՄ@BNջF+HJ)XTDDfV$"@ "HYঈ"Br(mö? D{Y_䦋vkjS,pM c:I)=.PѰ݂y7^KTTTh)^T'6`PT✚gSjeHZ(>#4a5w+P*~$2V.`Z؉0@av48U 6@]BD#()5Ⲁmx >cS_Jah#zڈ5\4g[,qP(Tz/ߣY_ sSPϋ_r/_I uxUuseg/`DB%Hۥ~euz`[-0 9_Hԧx`5 ;97N9~ "J ^X$J{}(锄SRszѴ'$y3j G:wb0S`&=E*.ZiK 6t06@mѠ u"xu0ĮEu]"B=QQ&:P):ƒtbh+"T(%B_|s8G`Iϐji; p"E4cQwqZgdh*L9j$`fƝ5PJ`3'?GT3 X8#a0];AN3Dx@h"n;t_Pzκ{hfim!T* @ ]4S K'U0>7߀PE| XY:sط"@h;b) p;_Dc7s/Du9 qs6IshXR40@Ah$м?ݻT r$ ;ÙE;?N|Ͽù=wxb.<*hi`2O!gbvv`"U@E,қ` %HPWaf쯳sN\@Dhxch@;I|=މ-; T@@PU!.jGm3h(*T;vC(;|3?~ePj;jkĘ'  sZj#ѐSYœvNO"+ذeJ6qI/痱+eM!dOok8amu 1'O\.}%ع{& M" 2 V5NB:-`4TTXߔ5g+ y#.~%-T'-d QзkSh\XZ(pעف۾7t~3;c I 8/pET n[SB R‚)@iuRFc MDB@IE;Lҕơou_p=`f<jm5XKgr|T{i0li[HHaK""1v"%,g$x|տ} cmL+vM4>[+{ VB3Rzb绿 b˒!EF0^HBk+Xp/]B9N?}#8vvޣL :KP[o߾=2b:IE|ԗIeQپF osbèy"8~qG;fvLKD'N,^x+n_\àtؒVj3 tϐK#%: %Q)uZh>=uo(`_,ݤ2c?beq W}ګq_Gn! ;w.&â܉Yz{ѣ9}66771;;Ϯ?%"䴕u@vk&u `n7ⵘw?p3-fg/^㝸A2?SvNMWMB.QS7/%Ҷ*%c p>%Dll @`H@X]Y*qw?̌z?x;h0U!Nc;oackVVt1RLDN^J0iRd%/)k0iY4S>)G?~ *aNm3үVN7>E4! 4'qZ4!+s*ԑY*ޫ%E}.uޮ(PLA'FDYSzd3쉛 PEiV^_ހ>XZ<׏d2*momM4EDh(b)OLj<'X+$Jwa(]yU11GRS"@i1]ttL@y4f)etկB^zNHс !wd7'sR/&NtHYY %kz()XVa?%HaY" !xLoߣi;5ܢiP1(@̠X,(ŵ8N0h Q[K7}.%0T"9YMo XZCdN'cB_p8Yf@p&+ewrLem~~] ]-$[98Ow>DmT'gtWΨꁴ[rS^ɩY"]`0G>Qڤelllb:m;]']cp1j7R"H!t0~]c/I=`kc/"pZ&ʼ{ FIUπӅ! A+nGÑtzًk2[SFУBHyGHWT˜TL=Hk{}xvbm"Jdԓbn}%0*~Pv~P4E‚` /yNGݖ]2x>@Y_XΎgd4I**X53#!XC a=wօ>:p"VЯҍ}W#;gxz8B DPt(_<_7J [U蓵a -`y;Te+ɬ@ڲ$pN.p[9WX+g5䜸x_}SNU_Rf3&>PUN6oou/x#,d?|SkO@;ds;[]PaLpӭ7VN,;tӛ(Oy~mO݊ki_ _tdmuϚlmvhW8qh4;# .@hgvp4,)C7)@F"vD{&)zz{@0e;S*F..iyP2\`7r5߫I,5@aD#]D6 "3~/pvI@2U㡫1F B m;]#xǫ]P$O]Z]WZ~뗟s]˒[؝F'Ͼ,'/~zҴBDCVDOcv7`G3-jn(]!0wDȥ,lͧ R$a3,L 7cF${FHp&&AO2"o"K kDI~ZRZ“$hKX;tZUC)P`f]]0 eTxeϥ| !ab!j7C3y0p0Q@QU`]tGDJnz-a5]4TQU} 'i빆tLZg?е^$S);4ze;eTT&YhZ~(]XܙSdfn0^d CFs5=#-~Hbl=#IlI x-gXdyE#7nJN3l5uM#mT- -d00  n>td2ma^jG bO} 0B~`}+ݲ|^O ]g ŊiڬX㕄tzZ7lINU"3=L#?:~߿a<"ͭsŽ}3X;xGjb0"tXY\Ǒ#51Q\_EH 6jnt^de IDATP,4@%@#ףU͕[pTOV|QD#l&!ıuj y~۶ .|pYqekAztBό8X]"ȝ8jT'iH8JR~47wJK<{;xCBO( rk"m6}L } UtiC׮P aU t#B(dK)ڣonZ7< ׅyfeT2XY1<[ .U-nE͚Yڿv'D^>+ U8k?pGb׆/T!m;9m%3-ԼA,ўM>@f&q-e4cy_.(ThkSI9V:yQƨ2;@S2W"(z|\NH/^' 8iї?ﻨVZsJ"o f! (U/}]W.I%1d)dZ*q\{vq!T>k/F*sy'(QLGđ5-/YOĉxvN?q@*$s-o)L TțlY蘺h`D/ 4c\蔊9$%.Y$ %<rrliK!F~JJgmNůe8rP$ +MnuMDKGzYqG[7e;8>-(h䦑^\C֎ #ٲt񇻋=ͿwjOk-F' DjٳkA6J-̪uNWzstJt3ϙÌ٨ydJbQ#S-;ER֙v\沦ٯ""+6})H1u ItRxtTvs>.'$ET(͖Vemy"Ff7?d6Uv1]fIp f޳REG]y G)ATeG,ջK N{t _:%YpygADfyՇ#HA@a.)!9jV33 bQ,.rhȩPItk73dY}bw],5 ْ(Nb]1RßʔBi?`B!7isvҡŽ4ɛl[]G#mgH~*4=>rM _c-;};h!7TZ!u! >dE%@B,lܦ w;j Q7z*` Ny~&úr S.SL m tF3ʿ°#Ѐ؂w9~lVdrt᜺:^ڤ)ۀ,|!.g]cGnksRNY9!4 ݘw+blF?k NE&؀j\pJqh[JgUf]ݻ%]$ìr素忦Ra>ǍR"9ph GfL@OQч;,U5d:w?y蚦OHNޠjNeڥrK#KMY?&bS4kmq:8Q nMvN;ᓺ%W{aZ(̬yBib-0>Yѕ/yRQZ\< f~8;*F WK;I؝HL$&gme #BNR}/lN\mݘ1J'Jf©M0$=e2Q.P٭8FS2,nh-{U -,.[9<0)s8kWDJd!q@V_8[ nmf\mnQ fs&rhap.rH>2NPC2uyng:X !th[Z:R&Y %%rS.x#/" S]Y yt^)cD٣}%{JhK%H@<,'RTl,Ypa" kK=_&~p3[4ӈfҡk.Jٶ궨p}6D"1%Bە6ء޹pJ"#*-}EJ!έǬ=V'R}`Y5U0qدeZR!gB9/b '4HF$ô/Hyp4I 1y7[b>, Ip%I%7/_Uf2wЪEW鰯h݂&h(`-!H\l^׷!]+d| E,,å+.fv/{Iϖ$0H#;dvZg] m1s|%X:.=#*4$4FeF}v"kkI9GR:rD%*]pv5X 5qqP<~I;"`D紀(TWv1UXس󧝁bP7 ck ܡ['t`N'̣4&s?0kIiCHU *`՞0oQĴxaqE*63Y[>x,S2u&3|-(nn^]6D6/aI0Qtޔqȟ+{wlKϺ6>qr-@)zs<'ٝB@6[x^cQzDk`4D"ٟY}f yw>gļ9$T92ރN0e y՟ ܤ}2d?-!:xD_◓$T3lF"B ^ONȀbHH?ˤEHL *$+)E Ig1œ^Pa*C]nCd02{LNIv-0 qkF -|gN!qdl^3=%="ۆpdGM/\ 6!Ft GX}Q>K$z%SDXh0Sz)J6hev#isxwIJ2>C5,RK}ʼZh)/c"EA9=R[䀷9 ["®d;i""pR>ؘdN` EB3vUkatMn#g <HOa"@kg6vk:D0 & 'aNW 9fI]vpH GNB&T)G u@P#S}jyϗѝ,%lDVcGJ)u~2,&RU׏#/{.tb0N|9#0b#ls΅w3*oF bs [o m*lqBUqy "W-ThtCY6($y^odι Zp .|I'.K /`r*` EV#M⧍^)K.^+漾g|s9T0DՍn*蚘d@V6h~VcmHpa`6=Q9#l,c @Iucd5(8GKHt^E9g6g2wz9ύBnS(_=+׷s ; qi̒tK޺jTu}gzMӀ1-A Ӕ`OcB7Fu9Ưa}#H;M'.[u?rP=(:VC3n1ZCbp<õ"KVٗy6(k Ypŏ*ErRa2ĪY3구w_P) pL kb"d^r>GQ x? t[jy`Vbk'EuEfH;*J-H7Dt ]_93KGIa`uma`П^c/U?Üc>HmCrEZJ2o yinZBԀ ^M aM(Si΋=M鐑(szWƝуK5mbljr'?4Xm+QUP!_/;Pg>LK8qW7.P@< vP:iww76j4DN#Nv>4PYB6_p,s֮5dal-J<9ż7hpbQw~MnXuLoe@t5̍$rFbB;8|iN,%**)mTS}SaP*#KI#yxI(+ >Q8l72!"Z=kGeqwwu>~mN`̮xNb\ {;څ@Ͻ[ .=Jm2;ɆNf{1bcp'5qݘi00N!E<$(l)7T'l:Ls[a?'bcd4Hʨ I=,և{C(D*fݒ-͘"Öd534&0G7'Ttz"/v r]ɴs]{{pƙݻ]Qf@@ӠS7B\G_WSILF.G+D!Rv9% N3% YƳ}XQM5>`fg+RPKAOmS%>"&'s) 3p6<kC.} *Y~ǙN"H&zG,]s.%Ovn4FMh:H-&d'g%$<AB2ʪp7 ~L.b4Wr5~iqg,= @ި&s3<3lvH]I:=6րf 4 k@m(A"GDIIAؿOb߫}QQIZ's-%>" :5:u]ܘӦKÎ'?C3qEo‚C23!zydn ΋au *+ܢ-BN.x⨛s0;7/%$i$.rjY,,Flzꦀ:p!C3 ZNT*l &dp>Nzf lD& -fW kd7 sVύ,&KLPR.@42pJ7ylOԈrjvDčuggB7bv<_]fɴsTPal;1Yzх]5}RKF39F|kg~[DlRG͉{qF(Z@m(_Øݹts *Y2JT Q׊yq$S#8.&i8'Q:ҶhVEj)Yr+3r#@fԷԧ:U k3֢^]g0x:.ۮ">b0!*I*Ҝպn! /Ӣ #}yJebĨt\˓[̶DП ?\]-ӄ1%OT afq{"tž5%U]b餹l #.$*w%vt3!K'pF[I}1DJ)lf*їX[a%XF+|  _ N`<;?zocn~'8FV$nMgR!zIb) A8|VkhSCRN>?_@xhgF={P{,.~G`2P -|x?CumA^O"yi&P8.1>Sήs0B9CaTj̩uk[z')@=CAr<ƸYJD;{ IDAT\KP[nQcaNg;vq*%NONnTJM=Lө8 R̫&a)W)g1"<ڱo~;w"20[ޟ;b"{Ƴ X"}BL;ЉXؽ1:ZFlIHlֱdCU&4 <t)eXL<@bH:k" SB&׼I05nQoDF$w=Yd•alc>{Jg'N'Yې/_/ɮx:ZR* .--| dޕ_\ ے`,9Os/*zm8ծ9B5 &{37V71WA$ 5uFFk%?#Glb (u5SkxAڶDӴ=~ewm`+YOL. mPWgwoB ɶ0Ŝhh& xu~e@]3OXGxo4,,E=S - b #i*D,p KvVu#TU}O(k [?ٝ `/"0QySU>?"a8a8Ax1Bil*Cc͚>H;lE4+lj'vhOl/In1_: Tn^ xb|L.-qv>!f@-ʳ'=2E䴃gzI:eyubD$eg~N.RL8rs2&)ؤbò.FTN /jctհlv泤抁>[J$wd=" +Od"Y.~X:Q|ZF͐F"9EφZg.̚RFb&t/z9mYЙA)"9I 7CJQ ,f/NLo W6&mt]zͫ o| ndᷓXZB/1 LU(cťCku m2̛g?o{~=r i9GdݜI\=%YZAœ_RI:uc}~a'*>Zv!1e7+KY Fw;R ɽ* <22%)FV P"S7xq`uz+8!ó䎨ā{#  =Ho|x10 0{sJJif!Q*\yTIS畮ž}ށ#՜w\L,=6ƌܫoDd^q!{l[FUexڊLfqPprM4}rnUUEw ġŢ6?r)@-tTD =5F'M?"@`J4OL%Ȝ|!0u!WUR0u)qRcE $gI'7+L!nhY!tk1n4S5ƽY$9>{jO]q;~:ᧅYz4@4R=Q=at#1|ltbSsDgi4:CR3`d2 h4%Gh93 H{џMLj}|/umK 볐mMҼ, fM 1[f2qvfgr]\e6@ Rjr޻"|BD[>S&ʣ[csP$$" e 9u\ιg}/j.őmGQ !!; KY_TBc3 xǛ^7+3^6j,nm>>[=;%@Ù;{1Hx E3mnAfǓܴzz>S1[p><<9s-[5P3ph\ID[[n^lG PȌ {޲ONѿv99{.M)֒>&m4 *8 ICTYNԏ |~ 3#t= ny7FLmP;`t#/?1 }82oRlVs._Q)Be;NFv Ciqp!跒KJ|E=MEMWDNaJ]~ /(,4-G\3Nr\6֜%K*܂@Ɨ7E gw}H0dtdٯ"ZϾ~XnY\?$p8]ퟵ5 sLp)cBSQn/,]62:LĬ+DzF t'5,=^-_ iACJvqD6% I+i5Z":' A7~ش2LNN_Kxſ&\xO༇>N>d) \Bތ|ʢ57}UUE=ԧLǐd`"`(Op=%]DWn^<\+6ćuŇM۠T>y <]'Uc R7CK;qdg8sׂWUw6s(독DwOXSu%{&S!̉(-/AgPs_f΀ Q$0Nno^jɋn6l,Ni2ZݷHS?'m,qfR˓Q=ZsoBB93 q{S XyC@Up$N4!y iT`A0F Jhr"K>:* {%i[cK}KzS) GO=fa P9lAQś3 (.LgB\a ̤FL`Sp]MCܶ@°!`f"3Ky3L s K߀ m8TR|/ёl.;Nwa-'Gur n;va.uRNKv'oN6H8$n س{#__}5vC> z?~6 10"z&>*^$ J⾝6BjD'D@=!}JkΈḤ$yfː$1()Iw 'Ҧ #>Qmǵ0f|rɶ2f2>c)\DiP.+E#Cd9d`p}\eKn->-[O=ں;599c*;wbI$)#n`6hC/_3wM6ᵯ M ;޶0;,/!$q0!іm 7l$Nўv6h Yn=vSae:%0Vg=hVt@L\H}ΚCq̖Dl3Pe' 668.&LNI:!Ff1"ES\ nZHkM8(,#u2;0 u=ySeTy"TRZ(ˡOKGVCX߅+қ1Ps>(6o/9AVtpW yNV"!JroS@I$F01= a4Eܶ:^>:|ȏ$/-Ra1#Xfΰo/ƅVBe%4^EF~ 5؛Uxߛ_b~ v4μ>%TdĽAHT}0"WWV>D1hu3H5>A)f6`E+t IDATV>?#gR njk˲xMFgQ E eP^~T !=f9sHK V-ac)M v4 `8Jf䑎t6iȃȱgt@20Z7hA[!ORcE~SjPC  \J{nƠ:mNqlyC/8l$-Iu4^֮&h2\EuzZc:mд-.^flCPH |P4J ѮuK0m6 ۆLݐ1-QNӧZѺ.evB(A۹j vp3^)YNY:Ds;N#rO8UeWUG=-PD٬SyĎ)gX(/lC  *ʒtJ& G#2a6nHW}*Z^^^)dezY=aڲy+}Kh0#&c'n_,#s$ Zw-r~n.@PH}By$#)9=̌nju ZiiLB#,rx 4s0KPoZoJ&% ̦'(Z(E焊 ,T=Fv}yOJ[59O9L!=dqEOnشe^y2Z[x,u]d2t"DFk#F 7lkxε* ɿ͟ T:dg?$c!)!29l!EeP^ HP n.>GΣ(~7 ~ hƯ[;&cܢ4-qmk5wA+9zxn(#ѿ 𜧎X#4ݐMAޘBmwIiMTuzP0?vdOhJOcBK^X޽GN&Gg5Q2ztzCJv9ZZZeZ][VVpAN=T?Fv j) 7c"Nb@̔Vڴa 1/o j[ ENTDEFJeByDPs^$cj.6ӿ^jr= y{FLx*<"npS{A8!hH?ah@ *IB%ܚA@L|v+65PtCkV[&\˥ω1$ڔ;(zi>d2Lk4M#O':.ݞө,:e:={nǭ;oYg)ЕB Y uݠks]vFHձ0q %$ fޢSG]@v7sKR7]gzFdfQ>1,pZIk#w1:+n5J\w)T@fqӝd\7""1bu ,Ơiw%*rq𞷾ν:</dJuY dlG? 7f&BA}رt}EO|"N?4l۾'t& @iewػgLScMסtlv*%/$]u'2C, rP^*JPYARDZ%ܙ=JD=b;M{b6m(̽Zoᥱx[Sx1O1NQQ8%v]v-<ʣlר(M Y֖/#*B $VzyO/3_FjT;?^?Vu$ȓ,׽u`aQV,Uʢ$˴1?>)yyw\h[A(J%U.ڐP&%*ȺlN@"F~#EL6@F5=bJk2ZQ.L= O$~$ Ҕh)ʆfs]Nxt -g[D&}ETyM|@o@>TsRUT=I~/}Ǐh(ȂT^P_եW >x/~3) JKViev.Rph:eI;u?܍ꔕƸMFh}5e%yNA 7!TL:v"3*%H?9f7" V2rBL ! s]{@4Q fr%)Ŋfn4br5nx[Y) 4m\hR|x:Ae33C=mA5 Tc˞N$qI 8"kP*c^5.s PW߶5PJ] Bo4F1I:1qm4Gԑ똂m !RI ;~ ׾% #g4']u邞4?ݙyde~o@ҟs_vdho-e }L'ȺX+.[Jm=HշakնE!}=aaZ/0v@^@+,Ǹ1~ܵS' q>9]-f`cw 1v!"̎gVw-fo_ &`&)$?ZēTEƄFٹrB‹BܔV,Nkg7֡RXY^D^Vx%/Ïad凎K-loa s#k]ŽN>zv_B,lnUza0HYa(f;-;n풮J<h4Qw}RgE9*pЧ}knLpoe2Fdk Vx3QON+Czo詐kȧ:)!Mf^InV`5$(㨒#A/|&gnkO1H 7} c]&y[sA CyAC{.| 'jFR P*wYf: |, GjyQT ,;] )*܎ͩ*Q2zR,MwByY^i;~vMx@@6&v$E1">)/|-%W]BPPBf> DYv*_ ]AnKQ%A!ZY^&Ȟۂ`|,0]scv_S\ ZiHbmz!}QJ( {^wބꃔ3[t 1 ]HYAe5Yfb:ĄdpV7o ሸeٶSUP `7 `aPc`izN|ӤXjBGAp)jE%HP{e$ui  .`@ @)CH=d~˖CD,NΐdyEDcv-#~Ksqcb{@őeC] ǿ@ ܉Ez g}##냪 /AohbŢreր.*6V|7b:cH0(SFnDPt9F—D2CzQGZo0SԌ,#/J2 kIjqIS,&5-g H- de ֨\vK)~sg&݁'=Ewh#NzD>:\DX"g}JC}Kc=Kd c"Ev*ۅAnP@ynK=<4֚s;[:SbϒI~8?vs3,J96 ʒMOD;?Eq xڎXt}5L)GcT=v}c'$ӈ ՕJ(N ~QT|ش$蚅NF?'?4^>" t|8` l&lJ!lPc=hiD?G2\5EUu@U?HU]ȭ10ɶOwGE͘$ ƽ-섕@ ^yŞzzu}jӞ2lX0?NZ)9POW~_}kJӑ}a) qDilҹ a,]I%6Pǣt AeY.N}ƋiP 1a1l;{C~AjKnDw+a:Z%Qu PAA, :C=@DZN:LB߶5qHJgwrTʶNG \r觇ӳlqA35SWkkaYCDQ -}vÿ*MpZ]I~xs<<nxP^ŃF}+^c e9xӸtM>?;LO(1)FBJ/ͯ{9 ֍FפylqeT+?Au:JCYO#ickvƤǶPQQ2,#J3[O]e9;B5NZ1A+#iŻ_&O."*1 EH?e ģ5{GM-KwȡFŷчz qw mba r/\Wӿlٺ`Q+c4^D4tzC҃T/Tu Y ho{2̝,<-3ˮU6/;IR;0)5jJ '[𷻍pu;ke?ۤsMm4^nU"9I'RHfgbM?99gB.ezӟgA~x.CYamuOyoc]@Lc`#@m v¶ T$N@=an~ >_ 13d, h =ZC{@m :ӃCAyQ>PV +x)ho 5N,x!+Y.+`Pv?fƝA~.tN{nZ}IH"eɺZšW;rex{fB1J:\M&۱޷޴p\)?TJa'<}嘌Ɖ@HRb'z ˨_vCyQEdA A?fyoyUuz!To钭݉9"cL#m'ġ' _af'|ָ?2HZo8(2 Wa0ܠƸ߹A˵E5Zn`ZRØFZ4\H+i rOSow$3P,c鲿޴Ҷ8 …iSzλ-ҹ6=Vkt1A។aS;,\ 睯Ŵe\TRzY)KNj0C zCe9{;;Y8|S]pGO,=9΋.;$DgԤ=XY]A5X 7ai݂a&,5ZӂѢ| >=aN8>L'6T-8e_ҡP* Qa;FxvWSgz{0VWH5 @yTtم 9TU™pL7Y3(Oz]pLU/I2Q7@׳OL cnY\n%:$0#M}N7DNiN9͹eIb61ϻ  lG;Iyq 76zذ$M<:chBHuPpj0'?$:vsh&d־\$?ra-}"Oя?yDI= !ܓ`<4y4hM_ZJ<fWp9jKUPS6-̵/EkV*'$U Wc4^s'fe%!$\Bii I<chTڦA2&fHsáʊӇ]3X( :4k{/~yWǰ$#tx7Gsa;#&Hk8 L2Ղ7s$n $HΝŒ)}Mfy$˕"m .}S%q;{[4}n Ro,:ЛSҴj_4>E[! S eUB>tHz5x?*x]&t0H yD!^<쁂z";|Rh] Jꓮš,(Gu[ƭ8 ^Yc1ۨz'?* M%pzy],;3Hrn_[ E#bL uMӀ:tt :C6sЃ9PoSg񁷵 +zfމц3zD</oC)&@\)EϺL)}&+$.8Jܱkv9-$|Zis#qڊÛb#i)B9v9cB`~ (zs 0uYn,˶ ٰ@ۃşA>TDġT 9)߳ӝ6IwQ2xXEDEpo +|5RGr*p;8iv0 Ltkrm(HcJ!Mzn2uMg~/г~& sl'\~Dm3Ŗ<01QA) (J[VPUׇ /;*klXfj)kNQ (P@pSE|ܐ(I3-I$4!!Uh]F4ן}y]VO[(뮠@*hIz;zCIYJ)P+{1مכ,X'LcnЂ>G4)~yqA~/tJ碋 d\P9 oNЙ7,F[*(E%J&AAKlfُ_#c>];fQ +͚k% +ŋ(V{nz x寃 ZӶGT\Wj_ nC+%W%`jZvRIuBjJ4[bu J nRˍ4GD ^9WI%g;9,$: e;@rJ> u.4[b“A~e7'x蜨;b7jkPCR<+M%Lr$L!4!n{GN5!AY.6{(`$28qpp!N؂!F r[nUw('Q?~F]ZZC8c_Aɮ/U :LvLЧ ڶ-:9nY?:|75JzaXi( lnbZ֟<[Kq>bn4}@SFL/ZH=8HWTWL&F`I|@MCR3 ;e!~_Yo?@^4ubSY5c:CA @Ɯ Fu0jcDu}w H˖캬T(LH4ԛh\x)a %`F^!>wQrl:BsgD^$]]{em3Y^40h:PY[䌳N–RtCTYr52tޙ=!ioаy lԵ1\m e0KKcבf h6~s ;-Ҳ4ia)Y?T"A-TGڶ~cIn1%}]yXB nlp׿JsIs#AU("tʎ/܂-[)HYfb<ӄL5U}k*n=]~d@ 3 jQ B|H(aJpbf >i4b`Ȳwߋ9Sc,)46܎H:9o]n @y!К,z8D iV#Xں<0=seFkV:@KD)nlb1mD6p1?cG;r4]c r\ uNnq=s[ '" [Y(Er%!ǔM:O6$מ-T6P!ڠA t_!ۺxC,X0uȦ=Da?G; l n_o02>B0GˉCON=.(Vtgi-H`#vaMEـmܫ6$lV6-ei?asO&@ƠȴYOs9&^dܠ /\4՘Yu@w?nZ[N_Ж3'lȩbd]4&oo${2IꏒePs8tJ0N7~>(\EG|ܒE,:,kHy'y._C?a D{v ddӺl͡qXX¶M=@( a8)7^"smK[7>[)A{Ŷ:s"VU{}y;rP^'c< ύџi,nC3Hv!BGW'`(6𓟅] {N7|Ӻ)Y](,B̭M'w^li#ɟb tG(`>,Ems0^n a{]]ڲ| qeHL@ 1{WeKWW@Z;xJdhK#o#.&UCU0锇=I&{BHIaL@ l`E*){#B.E,Tq7 'rpŅ(&}ga9&'œ(qv OW?Ԕy\>,޿TY֪(Þ(gzjDQ8N3"Ն'U:l^zvpcӯ|\nfViX?%\6Ni\$L`fؘE`ܢb{#߲2# UR)hqL' Xg_ ]tƇ7مܢ>d\6 0m ݝCՏ㊷N/4VF08>J9&)%hMR[xnVf-;C<@?@Ih ~+עaKbB3Qj~. *WM&( 栴v/L+k nSw3G{_& 8DX"3C`mO{k&7"|ԏ[Ou95se称")xߪZվd\ʎSf2:H@eHg<-yvB\ {;R3["{~Sߛ|W\ 6 4d<¯B0n1,ԩ*8ϗIa6[(e?:@|୲kt^OChN5}g(SW(:@hβ HBؾ 쀋 { ?و1t8s{;:8´'يHfy_~_+F }P5_,vK8'_aV[3Mw35PfEA@4Q#ow5bLrj$E1UDPA0(`fI{qjwoc?~N7}]{Uk]p@Nwšvmƞ e3 @80p1* & \7%a4w;lԝNs ?pLӄ& S'yUOyAJt|5 ]pݿt p,Χl.oe_%,u|0#'y:9RUdPd `ИbH_V=D\3G~ Y`>3e8U )HBH#݁PCO;C>Mђ2"5 lfgT"$V jn$k!%1OeeA(?H\~hp0gg)3bzƔ#H;I Ib RhU[^ FzI2Q`T6`䇖@6D9 YV^>srMDIY` , lCa0MKu]9bת-7ݑrXI T<]KPp /~PČU;I.%)0# 0!Ct 5pZp!d2,@8R"Ad[mj'f |<`})ea9 ߏ}*<ʺrxl˰NfUG0B!!IB5HUa)rCILr\+8saLƣ)&gl \H)Jt| 'd2$nEҞs(?߼>ۿ_m)N*7BKWLnGQIsW*HL @A8τ!C!P ;6OW< 0H?>?K p̀LR;* w޶1 DʈcʥO1R1 ['K G}YJ$ AؐvJ;\8S~HF곃 scHPg"?{eHP !EQדF*T_mqTo F(%~t ySVu㥧, 8׈ik<%. )H r?.˗PG']p_mx'k*M)gOe:kEU[M^MJqʁ+Rj䨨s![,BQ%15&HOu6(;)GGkM>qq }qb)YeP*hp@RsmS})I8b6@:4+v&O$q}@TH,=|!!$DģezyU2,|iO*@KC; @7jQJ6wJ\:b ݁/ꓝ<|] tViUBc)d91w3ƒDuO|>J&q+'ww)t8o.nb{B|rJs.dg&WZ0"M4g~~~wߺm۶OD"*ٷ&kڴ.=#)U bC X9y^~3f̸yyyFK=WZǎx 4_\\,\ĉVZd$[n1eRp' ` OQQNUVd2Z!Z:7nL&W+ˍ88;1WII jkk1uT?AݍlzO.Yyy9 ˲B0N^E+PCC8B, d29']Da߾}o+Yp"Z@<ǚ5k>~ B,Xee%_t9^{-[p!8qov_PPpd18/0I+yhw6Ƿҷw:A LzAa×;,`Dco%%%={t$:K_a3*?_bRORя_xBJHpW1(/n4 !YA{Uc"p>}{@K/6Bn{asc:?ڳgύƍ[ !RԩS!`o&UTTz-UTTdٶyÇ6rH^jQgu ݺuCUU19H58u#~_|U$Ps5Mbkl6ȧQ`&,:azcٲe'꘵)S`ԩ8s1utp"B(:ߗ.] !S+Lqq1w]nѣ  ȑ#iZ1RG1cW)S\UZZk١=zРA:GKKˀ={@  <𗔔p)mX|9c|_(P^^qQ‘[i޽x}41477pN:a, q˲y۷5yڴip,n'N7tA_b3w ɤ}`BXht_$y墋. O)5׆1c5v IDATN{{{G5w`1˲_D̙Xpa#L{MӠiV^\4 r-755,dnk[oٕc=nYVV ~9ӂ@eY766p4Ms foڴ)q]wjժ544ض-]ѳCʶOږѣGg[.1[o-[,y}^ʃdz$E-0LwVqH|F2LTWWK/e˖vJ_ʞcٶ^__;DL& MDO0Q1ݻwW\Zxq;e]}G~*Eʁd@`07a„B7tSСCt]C|ǎ|7>]ωd@p„ |GMV?~x0GQTUUwa[[[G([L&9t]'8S:9c>񆆆^sιF]{G1_ ?I&]ZQQQCi~?7u̔NJ߿˗/GKK44d21n8~sĉ<8{=د_ݶm~_/[l/~4yskw*y1Yf}ܸqaÆ&"j+Etvwv+++~gVg͚eG"]?ٳ :t;:u%TRRQ-mٲe;cc%<9r\h^{wnQ*'D?O8qb[CC z 0***zXӴƍw1c?l"vϼɴVUUܳgϡs6lذzc$%%%ɓ'!"sn2o?0eʔJ)kHOL8=ܳ׽{ww}W,\p{VVVI{{{c eR BOn[嘦7 .۲gv<oo鉂 ƘDZ׮]ّRr fEEEYIII7""'wN9 G9.81&5Mӫlݺb1ID,SL95 =@Ȳeee{V˲rt]w+W\d9Rt>///0mڴaBfΜg}v+ޔR_ P.[#d„ Lu۷o߾ YkO3mͻ> 6l)91Ɨ-[|ڴik3=&QIII0~Ɏ,*--KDfCJ)@ p`Μ9/[3GϜ9s\p󌟼^*K-Pb&^}W?Ss + ;S@O>F"ciʶ3-b֬YǑ}9s=%}/FD~98皦iJ) &6;WWVVar|ݻwGyyy@>;DA4B'3$okkq?|ӊ+vK)^׫ B̜9@/>|xGaǼ2̝;w>:C!Ox-,ټysϛn) ?|ܹ ,Xy޶Y 5jʕ+/$"ӧO#Fcǎ脈;# XMx4m6mڊsjO[>+++;\QQf"Xr'N8СCwМd2/YI!gIC cYG]B\z饼GB,X,i-_j-2ƜeY#FخkoϞ={---𜛈H$1z)fz+ >S[[omm9`'3Mi_rНweڱX̙3THp"Hb])kRʗ/zŶm/}ZhBF*.47]׃m78p4 EEE4M>(bw~^cj`ibX}9;\N?;;^v?xv'">}p8F8ֶy"@SLҥK{?gΜlN^|t] hP,ңB KEWhљA z]9'///uܹ34cƌt]lS4-{c|I{04ca5|'&eY|qg)sAč22]:7.~JX"T}PךpʂNe~(=x`a„ z 47|svEEú:no֬Y3:4kw@^zoH$e8RJ [3VCx 0$RL44gռɔPj02p8kllqK*Pu-ZĎupv##"rXd#wR sU nTeHNJf͚---Mb{tRRHvUM G&:w܅,: b{1trxs-Ly; >8[nujjj|e*J*F5bԩg8SSN5`˖-?_`A-e;vsҥV4*01N8Ie[~~"iJ& O{6b *X̥Vm׽)1x^p;~2\G;.|y51"N#]̇pǎ֙ggggOi>)I5 ) At'3KS}:Fy!Vo@”SxڣR 7uuuK!X`ipλ1Ʋ8I&ͭ4dȐq FD"xv? YyNw ǎ; Qsm/;UFB9sMӘY}fݿ1w|<-匱zƿsa憕±47>,1Ć 򲳳e h,k58: BmXv4b- OL!lH8ǏSK,h.zHCCC#E?׿?q0 }ٲe>S1#Fc.+L|0ͥH4&exsi^PVVVC<o6m[pZ]{1U>rκ_(U 9GDt7FsL4L$'|>T ~{^͛Y<3hG5 4MMd4M\͛7'Рչ/w(J)sTrG:v nGI3 nDR48N81Xc v3K_UG~:V5 b~?kѢE3WW_ .sϖRN7ocY4M?G"v5AuZ4MKtwB,= =֭Dd\}P>FjwH `_ /ן|y~?k„ C}Tp琔 B+9]v%e޽{uCG'!}eiӦRsꦶZwAA ===ʴvZvGeeeަMvȊ{>Sa&4MK $X,{ذaуܕ>hGIι`d۳z8FUUU=_} GhѢ}O<'?T]tEN=&p{}yhRPF%v8F]]]~_=qѽ{ N3gΪ`0ԧOW^knnVYYpGXvmb֭+? F@dɒ{2eeeٶv_SSSecc38#9sB SO}ZTTW__bɒ%$M74WUS{{{KYYYCIIIGҵVYpyKK=3gl!֦@|>~b (|ȑKrrrKJJKKK8!x<}_' OJ)t.+7֭:K/OϘ7woOwmݻwݺuo+80X3 ޱs9h݆whv^^6a„o9+#TcD"?17xgϮwRhmwNǺkժU9g&"RLJHznKBA۶<;w"W/Sm/S~AUܹ#*3mڴW#Ea))p]xk?p^ vp14SUWWב`c|75jeY8N"üy$!;""2d#jԔTbMzI;K1I)eY|rSSť]Wy]vLƘAӴ1c\֖TKPqMyBh[ Ǒahs˿/)wa0ѣsO8:\(%dicԥ6cuݘ4i֭[UaʽH 2\! @ɏMɀG(Hzi8!zk=at=z&WJ86FEz_?~[@ @;)Ywŋ=?%`SZ{D$k֬پq=UZUUua?lkkz0HĤG%"uv^IDATرc ^})4Moֵ~H$<VGUUU{w5 hQRJtQj5k׳gr0.AQ*-ˮ94vط4M H*3m5xəjժyzBlZdDk]euچ.//7M^xE`01ffsZ.ݿ?'"i֮]S]b%h4BDnd6QPP èXl=g=s}ٶmWWW7n:9OlܸX,_O7K)sMgye…BJɟ5W_}>YaXțO 3"^5sMJY1? <]SLf..?#}g?{k8{lnYViSSS *|X^eZ+J^QQQ_q677>EfUc555xyCCCk£'4MUAysZyd2~%>Mn{d2L&՘LշJ#1I)z2U1tV7!URxr[Qm&Xm+z ڊd@{Q/h[$#%)e\cXDrmS5440tVMGJ۶cj.icD&iG}}AX20ЭRXۤNh=a~'7pUUU^|EkWm 59-G?}iSl%%%=mԸ pi~!D=R ;Й(sf_Lqsu_:)d*a2p xDK<7on4M[)w)oPc p:!;v1MDEp" vkHaqrc݈R|yJ.y]+k` S]7\GrK(KRlՏzsRI?y} U,y?{vg3\'WRwt"{ϓ6kWoR'_/۾IENDB`pgmodeler-0.9.2/libpgmodeler_ui/res/styles/toolbar_bg.png000066400000000000000000003226311360462764600236230ustar00rootroot00000000000000PNG  IHDR)+ pHYsHHFk> vpAgg܊IDATx]E+mV;gWI1m۶m۶mvww.{k͙z q lKx%)W`)M_\Ua!1$昘FHM\Z!T̔3!i/XqZ>2EcZCq D07w8_t99cI9<=6' 7zp,m۽0Z`;;:CbLl 4͠`j5Ysqy:RW.8&!󻘜R>Q6޲s Wl<2]VP<#ƾ[.5R %h tBKa8hS:\\︼wERs:Z5PmJnE|Vp3Dpfq\ۜ3s0Br^I^K 8aLuxJ':x9/~N)./31&L{9/:v9&%#. ߰Gc4WGbnB\UkcS|1C,܋bbKh{ԍ8v_}<}܍fwnl XxyOԗ>:f2 eB{2"W) rU>)J'gfR h,&g>]HpŦ9f>t|Ĝe<V1(KRo7?ⓦ(~^) \Gكp/*6lo7 b³ ΣZIIZY`.׵liO 0 C`72bAڀ+N%\JRac=.\-h6,v>O>Z=lŦlQ[ԖWaoe0-N##Qp"eu`d2,ѽh Aw$vfu ū6z!'(VYXLS wI$e!Ɛo4K&JGDqv0gWMߨ NI+|IS9 q Ġ$ kxI9[N1!k&5XWsa[j5g塴Qr,%l<\(h8،RDz#MIkl7TZfA ,ݖӁOT܄Cv m;N!NЃ[ذ'Dq˥Wo>5pBRIR,/u z]M-)ŅF4䄳"1B,(R#)D\xBm]Np3X'qAm0q=z>/].#+*@+S>Mչ/f}½@j`%/|:0-n}Z%I>`1xN㩝*;Q]Rʻ%\zm17ǻbIkc\N*&.oNI~0tw̆Q:.i1l‹KumDhn`Tȁ%A>ӕ2xvLB;ÒPҮJ}p~^\mlZq7LӱRC"hGKV\VUvr^aG2NQ5ߦv|^Pt~@O(p٭s)!}|+iq񲔡E8|C9ߘ6 շ#-vpAh9Y)fUt\f4 pT'KxQ <&TËMu'G5Z"1%y9ee*J0s9sMGB{k iGi!0gmYj!Bp,N6oKE.uM!:)u{P Дm˓h*gc5Qf`:ޥaqA@737ٔ˹DS6 ]"ݤQp=cJ+s>}S eN630RFghӾP([ݶ B 9 CZLyVfpeniV[2J|% ?;43'uc!>be,F- &nԥmfHiOaVf:H.j}FccR;B-YVZi]?E 3@VHI~׼.l(yڟ3qynq5V1gDKq͢{:Ny6?-Õ>t ?a& l(=qtKR?ڗg(r /i%AG0! ,Pq K zmWp7Fvk [wY'/Pslȣ0Ij5S>\'8%Zjb\>T( ը*[ԛ6rL%{[zNqpJPtDƔ”0!h/|/vڋ](50ϓ4J< k7ƜxpR3]m4 $4첗&퐌EB;7EaY!B$!0Ϙާ413l$sA{/Ǔi1ϤBc .ܼr|,򞰃HM4 ws^6}w9:<1ԄRWZ΃EXeBZ͓x8KXNO?YDs,8=Җ˃ bnkZGFqB3x M~!.Im5Es8i0y'4B+W_|GnImp "f1e 0B{2tst*LƶUpIQ zL4<_RTMH?ݤͬ*1Zc*%u`tϼQ"p^Anmֺq@)pUe3ALMs*djQF (f8 |C`'vu?\t a Pjc4R m{F92*e7gz*^44_8[<,C(-U?heN":ouL\\l pګƤx;4]*ovx/,CF-K975?E KsѼ3kL'lcwbV30TJL[ަ<*9":hLsxNۿ+撍[_gTq^K̂~a'or͞rhރɂ^S_c#9a׺p؋wК@j_!)\2[l- 9!| x+.:3X.pAji7#4ol)qGD.3r6\R0U\AڄZ䕜BFQ+#ZO.ɥ0ew[_YӬ%ާq79uWAO./Dl&%uqPh"SB VyJyC#_Cg,IZ5_H35<'ŇeKf/U\x}RFXJQ[ZZy|6)6ݴa?Et 7*v kz i[NZМ )Ȗ|As2ղ_K6X.p-܄d%v#-7QdU&%+1埴ᠿOvwCI7ѭ}K'A3s}sA tUȾ+Xc__;_I7x(n?`]=]ZѬ2)?LсO:tb%-ϼ}9:!(ԦŮ?tڈi `NyNplgb2ϻXBnէۓOi(ݹJOW?qأlJ΂lQ*a fx+J^'hΖv '?6:ACYe)pڗفY\MF`>K%&.'0t1 p>P')!O=bZo.`FnINSgF\BxPT/$镗XFQ2H7ڻ#\jwƵt N).᭰k/7K>,XSer4Moͦ1S4.*jf>M\ nNG^AMXM hR( ´2k2cCWzav%3S8ajH{'5([E<@wZ uF4W"cR*ϼ ̟0o:b39Ugj2V :ᒈyq#K!7*p-s kDM r 4.8A.#7e&>Bg"OV[ɇqG7`. q 1pNi`Weu(;G+&^ r-qZ>A2e ܍<(Eq5SZ\r͸޸:d,wBHǑ&od׃# Cr*)%pE5_~ *piܕT8.&0?B@Q?ubg ii-s?:MZc"Ɋa,isSוrF(7tht [7\ŁT&Z5)WxY]J$)ԊcsFi SbaJ>,Z$Q|@#|Z{T)mۻAa4š pR?iTLiBT.]3RGWC#2'%^~ h=H+w0N} b>}o9Ȋ (]kaB9H|55(M7LoeZ|mlKB͝X˅Xtà>H,M^űx[8dPZsG$!gש=ől>鰅Ҥ)(n`M_g\;* qWۯC764ø4ܦRGcK??q. M!#&htnXWEnvЖFJs{8] FG^اqP2H>V-y-7Mnښ+^G;URGo˿8 "ylEs>3I$l;7Sͪ7yQ} ](HRg;m_FV.[zhASl(2"!;ݥ.~w<sR=0"i$6 )j#|d\Ŏ\Qp Cb(ؘA%)!m@7`hcl}sm45MmN27p N)& ڝn-~8>u9xmwUw 1 /PUtRW0gt˘z8 j.;N0p,؛sie m'1ћ#rfp_MއW9Ҏ%*( {Ebsg{x\ZN,§Ԃ.nxN|;s`,4(| q]n{KEwHjZ\:ǵA_ {Gs9CvAr1S Hm)"{)D ']:ՈO"ٍPeLؖ6mL=Lscc _|B϶tfVyq' rӅK8O]e9{ú^b/&Բsem񃦘SČ;,BkUSWmop4OR &+8q\"U*NW?(8 U\ Z)0P|"!6/??|VRT{$?C{ nYuũz|Le?xNԯy :UhA14W2Gvy']iL;mUyƀ޻٫Az3>0yӊQuxX o:+8yy,ʹ6u2Md씅{VU$*f/4Ηm.{Vr@,le Q_oS_#_sS >[]n(W?AkOĮ@fy&8v#hlCMA,ɤ^uKq)v&E,3Z_s8&Iep6lNuhdS"lPMT*Pf)p*ꃕlfnjjcK,n#4!4eڸEК`h!Š2B-"8ڽ(m AR %2 P[h#:CL/[&vAU(/L kL7~"r 1ߗ!:EJ̐8 fZ^FWٺtC# G'!zw 1S(X[;h2ej)ۉ-U)qӬW`wq|`{~/RI1I|yMgjcࡲŒpP*^L{'`NlqxY{1X6=Ґ>s-}M 䵭jB we#eZ^;5?u27|C2= N$e7ɕ~/rk(Mz+1'X%/ v?U"<GhEb-=iT-RP=R C%+u#&|[ǟ c,bA9;wkEVX `U;j3 8V; 3nt= Fv]48>pCye5Mߏ>;IVΫֆJ#Ot[&ZN/5ԋ G`54c ;PEԤr y 'F΃M\&]r+\u=e7H,uJ| v1/Bs(aT]۷3p><)!%l' |bC%l>H3{晿<" P פ!T2sWer4L"i0M(/SS^{k% #ǜX@"MBC]K0糚 +9Gsy~ eܑp*̽1WswR7 "Ia1ΐ)+U/JwO7?ӈcs}'U?Cy\8E;?HV~7ϱ,܂pk<6侗5[aIk-`(\׆:b|h`24eSa{a ;<Ռ>Unoxbh/-W F;f1w\-+6DBu}>I|SIHehorCG݅6 4q%3>MBG.Dضؒ`a+JS/M{p,F襬rAn%5?| @DrFfrE&ޑI1S` os^ Q`>q3X]Q.|êcI4t•v,uhş aNN%0DbNDމ;1-LLNt-}{96|}X­ZC$7>g8||+P%Vꪊ\{"\OA؎ExL{q6@$WTdA$8lDT]˹.Bce)?RK3/fdNNKx.|rP;_bB́"+d-ϡU\.R\{k0U,n\]&\̭y학D( K$P6v%\3͐$H y5솬.vws]0B<0Pr<b_(pT_P*Aew()?bz'1Ἵ`P,4 rK @:~Պ E=BVճsD<a/t~N?Qz +p oe&!9D`UIįIC.a 6<ƒ%)ogD^$lDusמ?JK]*Q u 蚢pzw%+\Pʱ6*1ĆiPW3BZJRzE}F+!Ieq=lW%OarZ[v:|/ N82\\PCy3e]q~NCy9I\|x6Rqz!^ǝh1,0Rkc\fA)8[J'.*khW]#KKi |DTJd77n7)Nte!I_+fE"^6]}Il^{Jv300}_1z|kWK>ʅ5jr.4_Q+q5ɧ_F*# fc {sJɌy0o7<5Ͱ rG)"b8Ԡr=YmяS(`>ʍ多 P)"#+)O,<7cln9,)lS $J 5vsؙtT/csZIz",F0jaR'psJ]$tx$ܦjh`}Y9t_`Bq_G[쇍iNF+Upu+sB1~iqu4|*:%s(MVEΒ椒loji(1v{rWal9p͞6J)fUL# ؏`7_f8 Y15u"M[fP=! 涒P[/){r|>GyDٓ+t-QhzdP_U5]|%7Y̆ !ErBP wC9lrT;DX p$؝΅^K77DB#L+qSiۥ2U9|7}TL󤜔s$gCsqwM`9GR¥64Z&6B5LWҚKj &Ga5iN #!tFrb8W`ztpÚ2Llf_cCFbs6@WWboZ9QS)A}BQ=v#ȫhdU (D@#1qtJs^+ew>:JJji)nae`@3A=lmlJyAI{B=%LCM(JI^ Z᩽^ x^ψ )K/r({N?0P˽gIJj;ŠgMǟ7aQ_%C& R>i0W ;@/Msxu?TRT05hQdc6W먦/}A䛮A;e Sظ`)QrdƽC*+G؟/1(K!9V]7tƞsh5Gہ PU _fC`Ǎ}C(^6Pü?j7A@d`DBmVG0 K7L瑱1cԔ1`DݏSf(DPCemCd&jC`?Ţ/5hwK`3R0+X-TZ#pg`2_p;ihW[W90G.j~%-GSSF0m%̓A|L\@J*Q.GOv;ƅxc 3Y3EB aK78"M<*o,| 6NƮoa;CtR5-iZNܠz]g峤u1略^s-(:( x%$l#|fnX7G: j.?!Fu<i7+Ҿ:POڙhݼ2E]!`#VKsYp!]g֥3G |p xW.dNŦ^vҐF"t-/<Eu78@ >큘Z(] d| W%m}I(6 XҺGHc PJ&;0mҴ_Yi%GϵJ%^H}]@+*xwX*8WRfQ E:& h1`,B4kp5-?H%Ti/}xր @4l,.U8fx'p j$7xDR);l,d8tLM 2>N{y$^̈́ft-O}?+8/?8FGRI2&{L$^I9U^PgaZZzA0&4׶P؄Ma7tB4wť#%ϥrH4W֭qhkڊ',NmwmԘ UH}U'p/kǖztuP+{CԦEƖlɫ?i!wVν>0z1:G(+_-^hy\`O[^CrLYl{6b>pm5mwh2AaAC{3sL*yKpoʝ8!^f+:yi/s6}_gݼ[۸mT>MSDZFJlNՈ'c?Myr,G;jiZMK` liD=ӷ4h==9_3&ﮉ0t]Kpl,m 8E+k8q %rBnk򗠛Wf\D{ly$, )P+E0>݃-^SkҙW;-.fzJ >uܳ!31wLSo [4jrv( _N#k"{,mLJ>fa!+F9qKL .{yJaR Zŝ81Εc3^HŤ$ͽhxS?UۉEnµ m+$.6OULlԿRh4/vN7 6`MCa?x=`~\hiJXèdC D {:+Q:8GK d8  t<4)W8KD5#=t򎞸)i-={J3MxXry ztt4W&Gd训~\\w+Ìԑh:]\ J(ޢR)~@y]J9`/%@iFFs_%wi!.V"/c0D~Q_mhS3͹¢Ϥ Tw6tqaMoDS.X3 a[]4q>>J)O %Di/Az.č%7ɜ21(9sũD #ԒFu`:4@*~5hTZ-WImspvHHąf3'8A9$'~]M(7/ΪQ= );*nR~Es {N峳rxoܧ%nxs~ՍurA:!}$6yC|ODSY{`6t$FW pE|! >0S䁏2\"w,fn_mӰ=hvh|smCLČ3Q}j\[! .]].7DTccq"jEpZhs( *8iėH"G`nXOE6.=Ejbo0p_7.WsS7B|QG\{ yE ~邺U0ʮctSg:z+\|)5׻58Ov=ULMq$TaFݿGhOmD7%!U&iHSq WxT)PnS\&ZbTV@㤱qjfO>'Yo Tʲi;D7RY|KU0SLJNZB//wi2ڟƭRġ79ͼuQΦl1W8(OqG9NԴC%+Kp Sh0U= y<,6JeO+pNT`'p)';̿Xխ[cE})]Uט/Y1ݨ#6r5#VPcw~R$N+(;/s+[Vx6&qjg1KJS54[z z@"e.m.P7(%ԗAMŒߝp']":Ni5!rkrWeaZrU;6U_P9隁%U,( hP@8sI]{N;BϰT)ܤO*Ҕc!40|1if 5´zܥ,`?=I56B_W42#`&CcAҗYſuf3P.`3yhn8ԓtPKBX;@8H2 [JC(N.+Yj}^A \"Lt9ۥ>ލ ,"R<%yv6t@>}Rb[3K<͎\Y`ڟ:8cdi$/P?HrI-G^~9\iH3;f38Y8>2>.[8Vr-Q"x{c- mۙr7V( 5anyytpw\ "8>XϔfkجO8drSP c=A}wyr醒GYPsv:ur.d*isjGd)'='%wqbccdVser4D\Ia\I3ϑs{D2Oq(F3~X sbC&;kxQ(sni|}+pG7>p:6$褹`!랏ׂ]%\/lGj.$7RwUXj*Ԭ:ёzy WǴ.L%=37{F(=^6ke`Hgm5Kؿ0@['>% >*ʾs4YvP*3pfKS\vQfefb^koǸoڗk{inI1 Tњ1_7=oYa\uԚN<:ZGzxTxB†^sH'sA7 $f{<վ>87)Х`.%W=kkPO7L !{5ؒs^']\F%>X*<|ڃUo$K[uj i9eՌ^9ׅ9ɰ#z[hBTrZ-K] ٺ[-0^)7]Q߅Ua}lC&qjCO[w+\(i9~RxԤŻS0ư]i$e)VFc*%a9N8@WY$='aHEQ㨐ե|JMԄetIRjCXLegBH~I.}]Mjo8*7ƾ&o,XW*Y2AZ py t֌-hs0$Yv*&zM%oNݠ %s Tre ۖ*!ͅ3a) k:A]kEgi<;T>`nvKF\W= *z .V,H`-ƫWIYVxKFW)݄ۛr{ .̼W"7؝`Zc+Q&+k{+Kmr}~|Ge 4f+ VQ' 1ny.m' klKf2G̓cZpdw)@ͼܾxKZAg SmW@_3` Ɠ]*l4r^Kl>M+˟ 9Y_n/1߰uThSDs}F6JMY^NN?J13}25lG$.s4R"-U/gۚٝGz4"]J݄4iүk/?Z0pً/bB9hl7M/xtԁd@_`{Rg{2Q |6C85'rRHb/]Eur&^ g^ M^&NWmiw TߝXW3%# 8=xAI&6*Nv5_`)10lƽ7Ί13JYQ9>7t3WJG)r>NF!ax]jQ%ݧ GoKo],BgkL(ZH'9:MO2BG1_'o8U9J Ӑh_*M<`\8y%w|U@ Tnc-M0$gؓ"V^Mx_Pq)Fׁ֛6o D2g68N~Q\Sww}&ħU< PYm0xOY3)شw5p˶ҐN2+uVp[id0ڑb:3O { c7ŚZfo;=Ŏnq}XZٲO q{_On9%=X͠SI+RIzl Ulb~ TJ ,>| j BZHp_ऻj(5U |av\Ѷ=!7Rqk<2pu*;V8넭)=+,(0g8!ǡpt6)-G،7}R3,hm]Rft 'c 40ۙff1U}c>h,z)7nA]$i>DŤJ ӱ!|>[}d˸RgzsJ{Q%54X[=n*X| [;#(Gc["Ǯ9ɻ##_oi/6>4zt|Le"u4/˩!&f.c2 pյmd7S}\25O (#6Mh3yf އh[ᣖP4sHmt#y,/Q>%mp=č|PN۞t}nHj 0OPWvh|lTEﭙWQ[R2Gu<&d.NbrZE[i*Aݛ[a~n.S3oIu䶫䫄 IrU>kL[P>WTJo)d5wv.W%%Q| }9e6c z/T:ظ$*-}$."V઼ *\╖|v*W6{p'wd{v"EceSRfp5* k9in Bfʙv`bHs+*b2=B8 vSn9n4ʳqy 3O%pq? @MC'uH\yeAxW7ɕuǽ<~(8'.qrp+F#6N)젪Y5_7(2F#-͋'h#94O(9j=>4_}G"vYIմùUBW$*eS= AnhBmY먐9Dsfv7rV>7̟KiK waSF朐[r HM`cʧ(JYzFdΦNXJ%ONQA/9}Rj_,15lʴVL\ϕ W/m i%B8Gw771G &Eh,f HtsbmtvleN)u{SP4tcPR)}/?Iy ~,UTsSA[GSs+3pnViHǵAC=>)R?_<+ xi;: "\Y7qr^/6+Qy%dp3J3re G]zUN&noI4qQ ͔jXB+.#[R G[t5ǁ0JIz fU.o<B`/)|jG24Z 7 nVf_(jeYb*_3S XJCW|N+ & .hD.JH]Nx6lS;{Eyh7\T;r!|j>,Ua4!Ϧ4˾2wřp6RJ7pD k0Q)B[zzP :pNqʀxepͦ*Wza^ٚVt+Ƹh:Zx+R6P^Oi=ch{e83F`2>n2p%oZMWu:.ǒ  Df2.մ߮xSF"Dm-\tЇrZBӸaSMSf@ub%ݟr|.veLq!gU(Nչ} CLu.cEzla)Ex& ^+a 2^i\U03e-Dž|H@},vA6P,lS.5h_3 򝴇2bp;m\o}b_!Ӓ{v[X1s/@?.C%2jla+>HO`n3,Q(e|UOJy'˜71?j( yF`ӠXr[J) /FKSǚ,%.i쥗k84LFKseTLk!8niks²T4pߩqsjNW|ߟksu.*)PAUٍv%e q hr[-Ysr  ҉өnu4մlFc|ɫ"%!w:U.,/E`fEv kI|30!ۘS6_?:8V\^ՂړﱙlVĞqwsM)9Lh >x9OYolBM*DgIJe|4i2fv r{97}?x21`7skejE(DJs-?O[ya0B PWW Rd9]9>[#:lx)&ORy(t+-e.: ϥSGe(k%kN')Rcv觺IhIK`NI5iU%VKzȷE]Jv2p#^B2$LJ-0aB| c.ܬH|p/co{f欤[oF3فX_xG`0Jj oy gT[G\ 2[1φ0d T-4ۮ栙|sB3p- (ErtH 鍛cr? ^98.P t7y=!B-X ׉c%ߺ4s$(Ts/Lw7|mȍy2L2wBl*-m^g-stz*a- 3gZi7_RozH_2rJvW=̞Z0㨔Yc;c'] @{ӄlJRkr I*sLof2Hj(NlKa^)w6RVK*gKtk 1I)i܆_7(%EcJMJħNKM#Gh/!_pe5kWS |JR͗z!98&ծɟՄd `3gn4P2H}et. wKi%z.pU-d)d[f&rMNiGe[vcfsb}ۣs7368[D9i¥h6lC( +Y|4Epo0s(" !VS՜=҆K&S7ͯD m1.܅E$;U8q!VޢDuu@6^9_|{TF'rR\J"C59‹Jd;rNz2CJGR'+i?vNN5P [ vr1lT>]O4+*F%\yo-ǀ8bw Fp|{ͯMM/%#grgZKL@4ŶEԀP_f樝ȻoAQjK})?,I5G~k% UsKE4(POب[7q/e|(}i]-\e NCCQyp/C4OqVϹ҈ R8r8kyofR<_u;ràWEzgc;8!, mA6yKKdz.5jGt󩏲J)` E*[nS@S!ֹcz5%w27fsyjrfY34QA;!5g3JN]c ) zc0pgi"wකc_/ʋ[(6Ii؆AK, ZkاN'(#7lq;S![w5>fS-V]!k- !L Ms\i ~`>'Lsۼ0kHⵇn;ݍnyq,ϦPaK1]6OR91擘Ss4f4pb{{8ep!sm..Qh gRf]zS/;ORI;Ww*Ox%#P Ib|Qų P: 9i\NVV !-n Pܒ!6N4r7V8T^E6 3;W.en:.++<%jAH>[m+;*6n[iWl1:=0Ns =YN=r@ỴO7p7f;j7_w}e^6x - =J\2uT_䤞q G\Ca$ěp#2S|#ƿ@OBF ()Tv6jzggy]u.MzhnP_ս`( ߶lL0'}0YX2{k46pmqǔ|QmYnj -)ue {PXz)@<.V4 j^7wն+ I}H1h6MX4R /9J!4^U%SUN R\8M8w%z?"Χ_|A,IX(8~(Lf`"JraŽɆ̅TAjU4dʢ{ Dh,PM,gpEJ!@7jJSa`nE=PKinA\,=upXB(s.A1  QGţКAۛKk8+v"|eS/`gz(~sVbc"UtCƹi<U_H0 /l5^/1vhD2o;,C3:@e]4UW.)hVsk8ͥsuR5CmI&H X N+ *)M a"i(ۋ)޻A.Qy3h5q}[YG8h+  v3X-k-|Z] .eA:@ t3@%vz`$mO6'52b^@I8/Sc\T䖹 db;u I١?n0# tF83ķR 8${zYs+[pmFIۤmԶmۚS۶>;&g}'ptwŽҩCWbLWMկtjd'L࿴S<7 Jn*朜F2ry 7] k"H1/ V7uvd\cjƼgtdHi&g@ۈ<2UYuT tcri宲_^$JKiTs~OEw]]F1dA~յ/g.͎OP>MMl H6gWFxV߮{9tZ3ӑLGRZ+/T0:Bokb0ty;`e{اB;=Z4%ΊV^+i*]zX֭gO?.)NNJNr|ԛ+\Sߛ& -ȅ#[nj*GR8XM‡xޥu65P"f^W1F8 q_) 9?sM}c&WVΟ$'Tz-&sLkwrozkg[y 493{3-vD-a|\m}rԛ]dE+\BtSͯ}Cxd>i3 q(6gy=q;ԗySX$>*b1p#=0G#&e$VM-9)"B4x@ZpwQp8 g* zBMRL'eYBQa{"Sp"MrtKA%RX"> 8PW_pmQ}8%SY=q"tԒ:tzU'CQQ:Hw Rc=Qpo37tureP/R!샢Ae$L9viD} a*)2bp@( q %0߭gzxҚnmM䣸P:o 58-GyR7w%pF6̟Epf>4\4)|a%{B1p@"WD)^\l+u^p ~bL0, 2j]|]mݗirwOn_#RO65E4ĵsx_PI)9VS1-tS]MtSќZjD+G%Yx' p7+F!2kOKLNg-_L_~ W2Dže):zR:oGH Z.BMA,]1!Wkcc !X)i nD:nP,)T/lj@bA6({p]~gu)ܥ`6rfI]|E3*$˜N( '*nqZSb>Ȼ05V# ~"?q4>a:8'1v]CQ{jLໞOnD7w>S oK9 n;>lZB5!q6{V+c]ג?NE] t%zE:(͡J:=So6,Qg40M MQbna,"ca@/Vqcp.6U'HCqgӚ>8."~"NiM4gXR8 ot^b{Zo37#I@ZںPY.’ʋ/\wxIU@^s^)8S,认=jt3ڗp0ܮp#o|s`o@S4l[9 ?2@BiY0=\^=bn;;N2{Sb*F` =3e4uFet)o4E/)PMjG=gq*0e\}RsfH0yc..Qo1!O]*cJxW47YM0I7qIDAT_K*@7uw{s ~fYjgm~7[>Dhl&7OkmeAMFxbRl)uZ فd#0[l+*[c>^H Z\V Tz|}053[ZLFH@ XES%5pnS  4hRr_8N0In"Yr 7Qwh {Sl[ج&6rat*rϿ q[:g5DxLIE3dc?&uôASMu<׵CtD!v_W-q?e0Wdd.Iy\Eluvq% 0C~ Q!J,?#ZqKeaH|/.n6u[/&9 «a \po~F2fzr*\toH':$KݤB}MmsKB|J RcAM< o7AN YhMW&`G`|F)]WOnI.߸b: wD& VK0vu00:xTv&|r1̷$r7qz>L%KUpa]xerEKx|n݂_n n~M&ȋcfz1xDJI#\5vyyupe #gI:E!_5x´'W$Jc!@Tŵw9,6k$&Ej>K @!X_PkJ_ؐZM *-L ՆJ*qU ǩpQ)G Uxط )F~2)GeC;"ausxO^#o&%jkGB\ZJdƙf!7a\rj$p[#5nr1m\/yq0[V1?MuvxABaq5 6@~-gg'bdaej/U.dWTtL42:0)O*F4=藐*+Ӷ{0)Q+D8# 7ۖǺ3ѧ$$5g~iߐ7#ƗMلY^VYȮjn]Y.vN PR OZ!!l? jA~j $?>ٷ Y,-\ZZ'bQatNnvɏ_7җǘk߬n(wBG4 J3q`4xrWR) ۟8 9o0?>tͥҟkBMMM?0hz`퉥]s4M,,ܙPucӕϪ) wp3NHuzX+A}QNba4J$%[~!)|2:J ]BK BlOodsٴ8(̙ʎ54/ƨЅU*p:rTZRK/WjyXna.˭5 흓<ĜPJ?$9I մBuJE]/~c'bݞ\ќ;d?RKb"{a| ͸6/Sd%C!;.b9gJ8:V2uwq7YC`2ES` 6PcI[.AҘ%z2Yfcz3l= n^l:&#NC),Tt,/%R Eѝt(*A(Gh՘z?3~A1>t8>W omSwП"p-ܠh6Yզ >[A0}>~M#̍B`&,Ձ r)X ۱ wXˉa!S2FP<@M@?LG^rVh $ՇwgاX^H}&?MMCRV[X֑еpYF\cl$Q%1yi3L7y) ATbvN(ܩ@W]v?t/W{;Oڽ~؉kVSG< lo~b܍(Cm Lg};δs74Soǭ:>&C2(WjI])]"R3]nP c5%s%xaryz)t[ P''T|Mj.9%40tCn@Xrhk 4׽tAg˨KpWM~ip2[q4]֥9Zf!p&7`5EpY?͑.V. Ƅhޱx4%N ?| _b:T^p5<`Y1oTRrMKy hG) uSFֈ[(?] ЖS!Ll*L \%wJJ5sI -Q}v)\&e]ᬊ%e4lgc(ߤ`lف) orxnG@Mnq"͌t6Pp}\:O4\K':ґ*K))E8V,_a gۜļ; tG{Nr4}A6*KQZ'/z&*JlCJ:d/)Z('} >R̼ es76lz{k$sk`K{1ӬXʋ |Gi(5WB pL~v; )o nsvYz"1G5M6_`Sڭ03\JjX'~X4~t<~f 炄vR-u|dR/WYz]e8fJ2ynIzFJ+ُ/ itv/QͪrWbqB/ՋJ@/?+܂ab.*0ݔ*=0L:څj[ceP'R.3)| tCDfa7'w]n21hîu٥3|a|Lufwy+ " PytbnLGqq-tJ\:l OV],]Gs3XIFQ.m9Lr/UHa&Ixt)]-\e9PQMLdRsW"hzKFZm 7ގmF) b*'5q1;l>P :cjkoy]Imwg@yF[SEdw/#ĖrM飢_Kށ1/l}5GyklF96eU&o tVRXOڋPNUh2X3@f5龜 U>M\! |~5uq9\VTv)? v1*qCx ٓjlf p7$.L`J%)MNsTR8PYch*vBQ{ƋfRB^HB!% ~=9j+al1*Ӑݥ*kjwPNg_r4,=Xho\pJc)kQ\{fź4Y7~^oyYַ \vBo1%!M8:<1 &J߃F?;63ٓWG7I%wi}MF/U"J*܄?*e83\3 \浼@ }؆_Q. m)oRKHۓHLNc5Z~~d TG&\` n.sC9J!xfo @ Gy5/(a?Η<}#ugA=p)954F`1]Ѯy#J.^hgl9y9!]m񤞢%I>HZhәܐCImz@}6J7*Nx;-wMk;EG4Rx#@.pA67QuCoX(J9jP<̑++qv WVQmA1%,Rb3Vyn*@@0 Μ/Le:礔Xſ*DݧZC9=qvXcdHfB(n`$]o}AO1:OҎ֒\eO FӹIDw+A"x ˥$6j%2滕eJpM($s~ѾgY6bηUdaqa8s ^.e !y-_Ә_m^?BlkQ%6M~Kúy+k0V@ ';\Hvut}׫o!ZI5lv7l;LE8lGPXXX>Wꠐa;)c-x vu 7f䶡cJ3 MtLgsK)"#Cޛ{f}8P; Ma0CW-$)@}cẓGT6HGLKO:HATs[<VyMɠ67KG/.>]p&z q^ R8ݝXڽ=UTq9;K0C,G8"znK Pcf kTho_eR"nr b5TC9v:-ArN#ԇ?KB-I )BϤtsD#|WrSnaY|e;S֠<47DJw)&]ބԮ7øڮcCy 4zЋڲfmm)S?*m0-=,Ղ`Z@9P'$? Go-ڏJN.u :jZ10̇ BZx@cnQw,F5Mqe`ENWrE䍃 +oݪ?vOl}BKwB C]+T9"fTBq&[k/<ڂkD;vQԆPƿ钬0_99u!AlqH|ɻtATE*"q 7mb.3p(jٵ6-Z[iS)Bs3Ȝst/%YK5W@/ٔ< %81_iD957oά~q-ukT/kQ&-iKx5!č|VRѰua/gmnc+H( \|-(}D9t̖毠 VT,i Uf_dtZY:!/cCv,աKMKp 4S  C1N ġ 5ZϮTѻA}^.4~܁DzΓf~ҷia帰p2 ;U}[q䗼K#+K6j1)͵OPIA>|d,˱m˨$c ;W+4C 64PsTƋ rr({ASQGQJE ){ hM`ˁ}[.,?/YB-+FV/磕_R.oՃnx.ʶ7F$_R^aHI-xUm޵!kGc% _qI1 j9l… gv6V`ZrJEpjh"5CAȃqK7cyc\FHLNɥGeq'n/aw˅:ծs~ה!nR]pwZ8ЖcJ7CXbu'H+aͨ{gʳ9U]F3bKj8)6"c;lDmQ1o.u5T,+)U*mKj[E Y: k)ܱiX S:sy=NHSϩn$'5\?wOQ/=qO$G#?H7[S-h?2KJ+urgJ Mƒɕ$a⅒#a*L ].m C@2oVpf~喻N9(#erQb+n~'NW% 2[r3.+\XK?c:k II6YUuλŐ" F<ߥl.\a.|VU/<]*gEX %慞MR=fn3 Livlmƒ^ Pv 0EՂWI?\M[_t?).Ypp:UcfI9XId?d7(.EDj8Sv0[qdXAtxF6 m-TڙC&)-u ,~go'?&Ά0 !dno 5髤 -<-?hUq6﵅4T PN`b*{[2w^3WX8cg0E.A8aX"m1ن79x),DPӞ2<˕:{Oh6_ڏmZߤns\MM+b[jJCl/V=m )\G$8^Cvn5fZ5p2xxEh2Mmƕz/0Wq Ou(nk⧦v~f|$;SdYLgObkh.8Jp^-^R زr@w"1owB*~XrI:[Q"\Jqy -cq)%`&P1zN[svە⬜fr2{*leZF́˰ݲm 9 _cGmvCqRɔ<N3%d/[3DpB(l^0Ae-[?F{^+ӰwK_Kh4YKy"uhK\0gOC}ܙ+iuxEFpN'<|-W΍ͰUtkNn3Fԝ˫grE]!CniFm'pz}a^ӯ3/O ހ8L{8Qc96rT!okB[\YX22`Ĩ*CdTQJcU.܍zhlV){$ )lVP*> 0W@j "1+ƖNO1kd0Tƅ~~zX=cJ+8>h2r9)I!~=&1]f@T~B!x&fF.` =UB79E)-K{UkF$`hgtN}7*">A&k=#/v_>YqgE2cK?_vGgalDI _{`R&ղ__Xٍ&v$rSoy2~z1٥ky@Yn8n0 ƞ\q~z OP^邖p$4E2ɍ_ ̮"\Ҙ< Η3`լtr>v^%V-` CֱU\̈́̾r5LIF8m`ކå\hZG}!k=dD`B'ޗ걔+;sbII2eT.H+ %! qoJ$R="X+;MoI07,2C^R=XA|E"2{cSO*}.J~hf{B\J<|dX߽䃔Dz漌gPY_D.-sws.67hT uMy~qLH5ta6+H9>{:A]<ca*%elvۀEM8Lp^Gqt)Dra<=Cwi:^tU6XjH'* v>tV.&mnm2J3-1!We-#GaR7v*|~P@rJ wB(U4mɤQ|NRݖQ yg} 0ªv2ԡ.\"h?M]X!|o~e']HLEaoەC|T'kxa޾ Rd׺ nK,yzxW( 踼b.ǖԈc Ԃ\16g nG,'1V 6ͬ>J>pv\+ӯa$ıCXssx^l1l''=PJY𒞶$Jը} 9+եeR"ɎmO̔r ).K v fx Y8wb?ckJH{ww%@8NQ 97%=L2h9'ő955nOvo DqB +G[ ?Y T]4W?;~2Ws>BŹufd8Ƥm mW*F9FE?dW&E'|ǍJlh&`N#~V~ ib;TAz6-pUn@*fWL(~V܂|f3"8cVW7V~ZL4q)_i3%OxgyIwJF@LdtsBj4jncRzXe_p'')/>fBH3lI529Q~ڪ EUc%mgKHO}# m: jaooz%k<ޕ19dRHy+7x5GP!>J3"d҉;J\9~\tNC(7" H( LzV衉秲C = )fLKG08Cpל1SIn '6iq[gr fxO]#- ~ھo܎A Pvse16\A./p){H|~5a}CJG&@NxL>خL\FS:qH ߣȨ] /+]w\/KM|$Ө'Uml ͨȯsS)Ug4ݶŴT]1VJh.I>lCQ#rLĪ]!|OҖL3L4Kzf3a!QIVGJyElRڅy@:T)<ns;`|nbMВ2oF)$ZE.y9u10Y2|,ꧽ:d ԩrVñ̈́y|5y:9]cslE $?s͔F5{ Coh+˨`bYL &v;1 v EǾZ:2l٢~;瀿x}FǗGVu+C-4[.Θȶċ6F`EYo.ۨ*vt)PIz݁~[w dv+~~x0Ͼ\TKJ4K DC L=yJ%ZvS3̊tϢA}~a?hK$9v`6ΆD1e.r vq0EҚ$6 ntv`Z.IODB7V"\n$[&7(6#Χ.e3)z麬*)/o|$46Y:5$[n.VT@$>봼I5nO)8GS+-b~#υg.2gwv ixl\oU`2_e[8!n.n+TU8h"ƻpo0;іlk0OE]zCǏMLwhkhMh U ~wi.TF)QI-g(_ d\AZilYv4kMM To U<fCSct{a `9׮l|A0^7 &7]?=´|ev =^IEɮ-XQW*)q=Mqsc$="_kAVc× "I#NY mlh`<,kfcPFĕ8HaJ~{r/MusjNX8l |F)Z[[K]A=d}HeKcB>gnn24.s`Y9m.1"?akDZBA"[ 9H$6ڒ65KkVM$gA;_ECp+˜۴JRP ]Aq% 13jNB0n߆68:m6'6>Ԑқ}$Sb~ qqiE'Ud8P-fOZY,.üO֕x{-W.eVpgM ҁKDExBėDp]x_OĂY$Y*8 ~W~A;r>e”"-~)K[dĢw1td~8iw*(p_#;/ -y5p P7#߾w=bڶ0,JG#'ՓP3~L3 - fW9!)Q9wsϥ#;"94#xGc]&p&tu TxB9-/g?Z˨?H5VFqZ&95nKR̫X)H58!7v-hԑ 2 MR-V!D逑?SOp=:j<;p4U#F$%!/WˎYJ"T:'kKYEQݧ^5RCRg+He@.=(&ǵ_8SئO 7Am8GPq;<@鷎]U\Cfc D+>B~?^U6CcQziyݸ)QI1/j$߁ɨgpqL+kV $v]\'[]x4sp3׽oX(TZq ?Czag[ʕSm?3r)> 0 6=ԄXec~5Nf/kxw(-Ȥl~*5Jq6ߘ[+tߊc|ز^6Н:XIyb\+TfP_cMPP)"0:咆aqJu(ۏ4yLݔ9x*dHX ump=Mmxpv*pm4]1 δQ% F;)9P.⊰s&MA(wLp(=o|Ӯż l!478l6BW8j39>遃*Y)>֦T 76nCe%}5،z$%1X6ZQ X+\`29vE`y*e4o.fdhrV6gd" 3g'H8ꛄX Ynt]6f[{gܤ\p,}b׼ HmrAnhc{y "&0åpa q\>,h)5}*@[3=?G=BJacmظ+v8Hiimo}j$,Q}~a<{C]@3Ræ1h-tC1WS"\ &p{ *S! K$qjMdU&+$?9wD'&+ĖaOhJESj߉h(8mG̅8*5dN)}"5Ƿ!p~g7Džj0ob_jc<.V(p'u} m,ߕ|Ni?t)}h0\xY 'Tq-ǽyU% .8i W[d/__*]k% 6rBpYO8JD }(\cЮ#MTSF@i%N a8(X6Kp1Į0| */=Ukb:M%e#7]|/).7ZnD!1)D xIZ'qAv65T˷6f6۔̐2kDӞSyA"9EE咹9%PNaUaS2ZV0Z%4ÏخT ;[ZODz] Mno- L":9ZGE"~ pCGi^3~/V{$81 4pd#8+-VpE֖DB6D!T״G-W/[gZs ?1eXdJpV{L~6%̲{d ZC<0mltU!n6svHE{h|iؕ >4OLZ V^;퀟Î7OCiO00 [-e~BQɡ( BpuNu z)̼3xÞn%&j(~EipOaCh/^Js~ ݔU? ]Jb,G>*).(IU%ʲsYhC9qkf?}R-lUҜz]/yݵ.m|UT+.dۥ_tŧC 8̂}3i GNSYg_f4Z饵WΦqI.IWt`DŽe6wͽmUװ=dј ڮcPS,ԏuRX'?V {y.ʹGl8YU)060 !Q'hZ22=t}+> )\w=Urt S#5οa~~7j޻Z'c ϥ0۠- 2|[a<\I~ѩ*[(e.;Wm1^ ih;ՃRkFPWL-R ig~|jKx۞`{Ci8"a=B6*91#3xv1i<n0&ݥ.kL[ $t=q0 Tz{)EQ}ß f xk yݹDثbdD{zW4F"i8>%\S/>wF:1.i6^cVu+EθCyxfTftX^8kLr鈥P~4)|jRAnxsۜ6[?um!'+.:z9EE~=$9:i5i,-;gZ%)7TAI.ZKmY r)Š 5iIj?7)>g&6~R_3gaU,PY}Y5kk_"X T@ ,lk37ZJ<8躠!G99aZR 7sP gP5b.}½|2֏p]܄}ʂ=]s4ewR]kms((iX&Gkq%<,]ɪ6K$8/-X=um?*y/PEnVtnC5T|T]GI-!  VySq527{)-v8'>ti քL +LW^?'WxgZ YkQ 9)-ON}e2Ul`1iS |axIC8+PpmcO'>3ɱ5-wM#W,(&$ Pb xAüZ5'4O1_Gq)0'ۊIQnXj|.ȷb!V:停X.R v (\pB5l&]vo~(L*1VfJ [:̭@I7$;0i U^xʏ{J%z@^l2g<1(!Npmŝn]cLH4cB(/wwm(.4V9ŕ` $Qi2jx4G:/nd2vm9G5-S\oGS_yC?fjҀKnzCWG俇 8s]c2@&!ق8k|ȭ\n)WG.7m \Sn)d6.[Uv(hf)i@T[ҼBHmu<_bJyp#%鲱q RsI@d?f+T^u`,O=hlBK9 P]IqQI;i=ϩ!1ZUNf*U{ ^yN1T6蟺9b+!gHTWj+n x@RKnD%nP.&v%!`R&nSxg e&A;Y!F)XQWr(/8a*ɏ 5aٞ xaa::/T.pO19Ǔ^7$~ՏZ/[&ӐpEq"H>w9}“9=fzA4R=SQ6}['pzSR3SmBiwJuz)Mڞ73|;:RG'o^A*>5^tq6zH /ܣtyUyj%Sp6A'A;-qps"TZqT| M?29<tRg*dGLy'0e0gP\[ x735̤>ZnVGfy}5,D$t+ݠ ZxW?Menc=R]wƹ~k \[#zR8 il"߃x!a;ܖ|H? l5^ChU|=.%ܐ\zٱx#rVAXos^I P\B=3maJ}򵨸j2N yw#cf_k\IQ1L.*γk7 K׹|.91f=H[C`fX7zaeC $Mn8A4D'Ko/KEԭ@hK`"TwZC)[I=܅ }u9TߜllP6*5輆ȷl \ڑf,<-,ĞSֿp^e;6t )x"sm9z؇MLq DiN]ZS T,HlJs(m'v7$6uqx0$ P٭ח̼6~l@XJ9ȕmQc۶musέ&m۶m۶m۶v_3IWݺgﵾ/鮪3r7)K}c0H=#Q=2vy`+ҝQf 崝ؘSm^={fx#A47NUãtB񲾔O$~!eԵ/y8/x[ k:iO?=*՜j*Or_NC7TF _xޥt>PBe owu1J[uNTQ`IiexJPC?;6Xc*Qx6-@LFCjuY͙.trC>RFaNOad,X~BXm;yMKtܰ] *H/wx+* ѡ04~|KcVNv:r>{ (U"h\!<4t78iFI8[54%t"J}xeB$5ׂ4NWJ3טӻ!喜 sIYgꚗ^ %t7ԎJ]܈Naql)q9O+0٧Ay؅\'m3'4DrpJ$Ka[#&'0 Kmxil ~:pB. ^+FYNNYBʌqLJpm(M(3lŵs{E݇{s#j QN|@\^ 9"v54ehnAfI5M L`C^n 0NGeɜZ~&H>xM}̥^ApvIHq?|^*R?!jq贄ggбe#Jʧ,ȝ/sa.QwwF(WȽ n4W"zws͛!wB"GM.] uR[|mo=/:54 wrū+ 9=k3t\Mi6S)X9{9ǣL|ɩ_@in 3KlZͯq(*5zs S im q9TQy{  ,Օ*De'ݡLa~d&jΊ$zXݣj VMlm vQ o XVm~2%1[qJ8o¼ÍڧNx!׻o 6wO)7TA/i/1;HV1 { ],W)2^pB6c oPX?o4CV_9SZ${r&0*x51J*% {{× Z-ͨS-ᗍÝ{C*xȥsۿRS): nL,ϖ"?lhWK t/NG!qY,O'<(Ԥ5%B@zZT b JM]}i]yS6DC.ӛ #$86D)9nR x11fZc@b/4ڍʟ&!\$ZpN=fMf+8 gXgB54Dcz!%U0E_TWD WM^k7.BUΞm( 07Wn-b0T#ܳ-}uMmnGӸ'NQ@ۥ5Ĵ`7㸒sc=јVP^Ok_K>9O %`3'!\jzUw]YzNirH 8)}=68fP)#e)_qYY֕%Hcsqt=t=ƇD3"WAFPL bT}~![mQWB"I,,MT/!1`0ݥ)xzJ!q lC%1;Vw62^HvM?R@?e)d& wW2HXZcn~Q!?wc);E=W4^2!|{4$w=Gs AY&8*TE8L[1.9삤Driym4j/⥚k9.6-lp\kZ Mj9'Rc>'IF@mZ>֙| X_N?hB;M ͓O>Z:fT)Aaj0`aexߕjHgƻ7p+'n{Di*Zl17.7| /x(*Oi3w%0j.!k`*C'htUݦGm[4H-ppEiTEѱR*i*KWF/N!tZMT_RN 63ułO˦*ix3DkGhClo:5Nr[v碫p. ?(υ vW'?uWx9o5jkHE 1y?qL؊ٰ)6IB%껖Q(e=tSګ%g|km|QF/`QSlyTE4U2~o]gjԈcM/,{% ["$R{~r Oğhmv9٬0FQ..]W'J7Z/ }A Fq:݋ mjg$pm iU\J4dRIjF[\hsTj0{LHnR+km7/Kp:jL-`LO!η!P%:vmRnV(EQŧ|O}sblm.[Cn,9 <> 9:dkAe5N89?P,>̰]"aF0!SM؁wK_Wq<.]6Gz{IuȄ7>].B{)*H=$2uI :DuhMI(WCRK#!op6,C.gE9aOpiI<RsC鱦KMI0܂p< PO|Dž9A][Rk~p'"*S|1aU+D8P"ۀa:p^-qiI2V6?y(BUKu93gz%qԟ "S.VIJ Fq=h->O$[sLI|\?AG [ʸJ{t,.,s_G(JW\J =Cs6'q}9h2scMj>.5ITT;e6\`Q,͉ Tߚ);2IԓC L]nJ}8{ ,;U_xc~z@iu^DEpoZu8]1u# C\ 3bGIW8=B~TzqAIF}q+ȍs8ecK10|ֱx  ]mG٨N&MΟ(F\HK.U>\TK/Wӈ $+km;ל񺆤qx淽a5H C^pGUmblM5);n 8B}UIF)l IDAT}0V*7EUZU&0~HlNQn3K >a9YmEu vMK/岲)i%m1j 5>J.-i`H<*{&g&Hp7K[1 mg)}T P*I,sѠVGQ9 )po?qybkqE..%Wq,I)"Q/Bfu˻ lH(7չgÄJ 1߲*Hm(m(7[Ee<ėZNq?zF1.G+)2ܑ4Zꦔy=P S pE.2nk7^[f|ߴW%M`{)ql?O2mud8L>I0fB nROSmKJ ,@*6Vgn̍ s3,Ӷ2úXƱSy6< rͶ,`hH_YN.xe!8& d?Dl;Lz\=PF1ufVn,S!׹=rrAAf)I3\Q%~6b 5?1ܬJrcӇزRq>k _j1̇j #rMwI b".pvR1m9śczn|%j{)I(Mm} VT4R sJ~ vsSew\54B*0~.%|_WSW³:+ub?8/5Jd#ڨ?po"StP'&LqCaJdf$ǴR'uXs,EaLkbEG1r)E]w\์eN&4-SS˷43J(NL i=sLɶI^*Ȟ7lt4,Ĥ<|pos]".E]V?=DYt )|R 9%׼]npMfn,Deј)?)6!^#ؐ=F1YjAjqlx^x4#)}!2D{!5!܃%衔np'r3H9BTI k\qؕ Ph}5Zx*TɌ ^3+4؊)h[{Z!p2G3 ?lqL)./Ff6L1 $&$[dxi4ui<-TvroMʂ2 pXiB[bBЁB\CMly ˛E0L$>D`b7:wI88Ke,XJɍFT&jU9Y/q7M-u6S2 ã\}6嗋 NRx]U0.685%p/d~krj뗂xJS8?^v|R_hSW]:/-XTOzdJ4ڿvW4RgHnAOE⮁/,%ե3`U fU亮|&xp0L0]5pK-R~=}rS%Y{#Po"% )"to@,^f~Ba,gVx"ä>99`k*3@S7tpt H`qZ{{|ANa4L~:ZZ?- s[4eIsI[&w~C_j3 8;8 TrDun0 Zi{{ }5_S)-9gxdUB\7IA7 Dsa8?_p=*Gqt]7/φ(̖Ljҏ@'5R_$D9~#N'i>W.ݮ$ԘڑK֛BBQyZG7q[:T(oCvB!Ow=0:&F 2sTh$ݦ(w5|# < ٣iBɩ[hw86R23(̫L6oژ-fcY C'!D&` '?,O.>fnII,adzP|F]\xE ,8cymuG*^HDw{] *NufDf&PH7$txD f0J`)tƚ&1ƉDK! a쏐v姥ۖz=L76l&֋;c0xS`94vNܧU;n.K(~̬`S\MTz8'ut5\c:HnJ*./[W *it[q)$iwMAwh̅#&LZ۪g|Һ`?'k ]GP%>o䆻*]%wąhF0":u4(ڶ[$Na{W71e,tIbHYN)yG3O նe({E:HÔ2ږi\mA]Ym%,a;-@)=ebg _+wS}UMsoK}rl 4nҌQZrk-FBJ\ђB 'FP(Oy9ģi,Msq 9ӧWUTc,vͦ&MLJ ?j%^|Rӕa*Ch?МyG(Եa9Ii6#?58SEp2i8T2s. 3۽[0۾W(l/2 &c͓yL5J?DCΣórm΃34υ B=CwyW.ɨR%7Ԏzkq.%`Tr1gߌOoU e9y290 ۽;ԍQe勸eoD (d祙F"Pzr2hO0rQS;bn m$:\sN$ о h1|.ɦUbo~T<4&Waum͇iÛ/M|z,)Y䕅?20f6F>NvW.$1ù=ؕC~鷾̴1)m2J%vWSBxyK:>iRեL f g~ ?m5]z.FluP.oڪ8#ɂH-&8N?nS4Kyno~R$86>|.!$GIi TťlmV2UYR窼S28K&In;\kWP)ڮt|H<_MR'8eK%|ZOǐQsZ$SD])`[AY[E7&=Lx}~[K T][*x/JAtIGI[Gӵ~B#u\cB$Z7ث7DaPCkku,eF)JS{QL3pc .7.svQPryyQ\}m=)d{k_g> +b_䌘IBcOC4LoNu]yYϥ 3SNjSVM, ۭW&JlӞ jM-h#ư_%Ho_inP xi"@_{BQu;6m(]f!9&rp?΢TԸH&MG ē% P~"Iˉ\|w.4 SYjfMM7#RI7?2kY-gI5Mo+Q,{| A9-Os_ ]kG;I Fa{wN;>6i%4LG- ].~+.$L:h.:P3h|;7u!ǥ\z g NvnNKHqeˁ0=Bo䮴tKSz8!bks]-x0qQYQvJ%, \[SS!;g;TK7*1Ɏ<Ғ3hh'Ә"P<ɃtrC)aRU~bK9jce]Xpω1d @\/W7Ur9v0nO#B yl;(tb[ zC?3Fؔ0O]vI_7Qb's nQen4ri%q(*]4nTKX w^o_W47\p[[uڮ\1to--d+ieL絚@͢ RMhu/(oG$ie TJMlBlh:]2Y]bCmz{1qDp=ͷ伿_,4]c&Yrz!^Q) C\qW6k՜ܘA*yQC@LpOk%;B4pˋ^[Gi8qA٧N4߽0ڨ/T }L_q) pd+`8IpsB =c]yG5#͡&܁*\CGt˪pl͋{ڦNvIޙJ)+*rvd *\V六\"zs)9=c+7RI3irs) ?f/!?:j V;REmqH-s;o䘁՜ժz2CI*S}8Ab9*.P.3 u' l+Ng Kñ@K Ip,#jm@ڎ .\%nA.L $!=_qp_S"\w âv .W::<2ǡ In-ag ;{@E#Gcn}5֫fFoDtat#p"&/a0֠ (NpTt0daQIx W}s]g?9ÿ;ZP+>wK>wJ%c0cEs=ݦpV \fPO+2$$1^.Bj6[-q+擉W_PhJ2a]> K ͩ-{ulꎃhNq'TN _. \SWC速G2{uZ\n%:a5~Ǟ\;5fCgWQ9%%qhC {=.*?J]14t6?WT'A?|.RD c$ y[1',Rt+pƱgcz8NZC310QL+x} H )mxh7vRg|<|<SGNWMOЗ77Nt2>Ȁ_ptkۙWS%*}9̓c12CamM=L //ld )=?SG_rAtS}eD%0V$ ƶ=M:"1\llF:=4õJqm $i=S 7%*^%~Ōv2B}Ja̓xelw~Mvf-^mt~& 5閩U͉s.Yk"+/$oJ LW%^r%ZP ĺJ"S6t /V\IkE~9Ríqk'il#(t >\y/0T.2?dz_3UP(}\+h6 زO0.^~>EHc_7K#EЧP޶L+Or 2wՖ K\Kg%> 6PSP>عxj5J M"q|(LQ( tż˴ pr# kL[ -<8) z15X &w)D96dɛx*9Z#$o4!zU?6rG6X@L,͍pH$ tRZ>!`7l%G$΢XPdKK#114'!x +;"t$RdKFBQJܩ!)NKu΄CIZOe"ģXw1GB:lw%[y\E ŕTb#'~?MΪ;yGx-n,:姇LR,U1}}hưxF~V)2#5,2Lfa V@,64+~~fwفG*Ը\;d1LJ)xk" gr mNb>{0=T)c˂CNiAw4IB׀'hW~K|sǴB-*.jP '-;Nul>rmT> #jFL?~/}NƩ&z+) 9wЅ79fcng!J3~q=ρ/p|~ ~n%)t(ZjOC MUy NɘQ|ΰ % KN|eO -&S\>j$6'fH3&d^.Vlssv0 T/z)mlHAT@_'RM֦lR~Sd uJV eI!2@NW֖" A΀_uZ[8ˡBL=qD-@O.j(LC8V<"s>uD&Pu 5Ψ/08?ĂdTζ`-4sQ#1`gPKJׅC@G(#8rfc:I]IASGUwqeރJI8ZĕPO0,G3xۚE-75*Pik֨V}Ĵ3}{VRZ{#u6:S6W܀3]MBM4=*s,GY.07@7gǀA꬯;[3pjFdhx1p93L2EX${OSXHDI.FBei%{ޏ㸫فPvn!Ʊ%5^M-#NB8EtwKAE T LkF\Qeʼ( Ka4wy.8hj4 3P"[b(R|0XW" 7 I=;ȵa6̷!nvۗ8q~Qqe3+MAӋ~zYB[šM_l5ӸTid:h*kOo]ƼӢan|wad!]m7MIoP^,+yjY_ s_VJCF{iLPb?CbV\: (9κcpU@B6M[mBn'iatħ î$NzВw`H\_QN`OCvK'~Φ]@MZ9.ggZNjף=O[,Inǵ9L6Kk+Ӽ4(O;S V(bwxovw<D/?l'> 阻뭁TV<9F+uCN7,iy\Z5_(ߖ( r_)rr0vI\mGhӼ'JLlfsvM϶#Bfb Pϗ!JV2v{%Uhsv Px(c8X%'*?[?| BC1\hi*Jor 1XO1)]@I}+f=Vb x!b}/$6/|4A^Ga?/1 *I_^!01WtƱ-WI:GoҋӺ{NW1 !f/ԘQE v-% RzN咊 =?ϥּ mxX4QRKmS$}T`k+% /S^3*!5{ p0-l֓0ռ 6oCuhCxs5t aTi\e+!)4_Rf|ƒpT146eAZÓyc/ vU8# b&5TƨRh!]U\̶fzS88#fN *5%_stȸR} 6J& k[,M1,pſ6$)X izTZA(6%@TS1+eK7p4aZ Q4NsI )X[4wj$IS@%p9%:9mEw ]S`<#ڽVL{^`;r$d*BB;9xE h:}d܁a{XQ76>j1dl4۷E:O* l3][8څvE,y/cGCmLqP^Yo$thb$`LP b;fkh+jBx?^Zc@zyo#:q&vc.r֮wx6 iu--ߣ2צ vfӆFG~EupISl_!]1?Uzyq+klSdSE8uH!4N'”_=v}}lNՍFZ a@U>CQ6St{k |W_S\;&+1R u#3%.6]shk];徭2I+GG1*5VѼ DvQ+ 34NI&WϸW^ P~)5G'!7-`+TWhEiޚYP(BdC^Ѵp2g-[ʯa.qZHrwr*̎[QհJNK~lnz#Oqrl Uy:^v&΄8 yi*d PUSZr?pJѽXuB1)®XJ8ٓ=P7S81֦ 9)N-.6g-譋% \W;0ᡭdvpKs%05ɮ*uvZcvE;z9OI||tS0;&t OO| r CG*_ ZJ[RoUc#BiՏ:XB9 "j8 Ȭ2k KH(=rWXDXN;tΑv/W+DՃSvj%OP]`ô1ŭ@JZ߶Up];&rM;l 4 4/0_F= ^pӥ{` Gzteb.t~^'yNQJ}`D60[Ci&].3zj?@5 9+(X3aoBLM]~"?r}p朮xgaU)JtrP:lKU,pe ;rEss3Vqk"C rGqPFhF 96>%kF'saQz8{b/m0jڻ .T /xC3(Q <4/"|5AHyJg#su2S"bS AH6A\(OlNБĺJ kH[Gy׻^BzwgWٹ~w]lL9m)3b,qf5|rc4s?^-p4 8xx(֟ڤz-MˑVl )$Ց@+p /9ZqlG) +h oElKICHhWQ2ꪍ 4 Ʉ+w̆ K7څ 7a 91&ASczFu3w67pI{K#82>JE4?RZI_[xo܋s9!],peܗC6凴ɮ9quHwyBcrkC*" I @.׮?iaD ${.X91eJ@ 挂ts>(\ x6$6Mb;Nu1ų:?w8lg. -Wžum\MEcg)`n)%.Nj!u{(_(koBfbSQVZcz;ʹY{-wOdtF%5{;SA&Q Ȅ/1;y}]45$n,c Z>ӖwGhg4Kr\U'OL=%G Lt%[\bGE\x,ŏ|;A2_]I^MMIJq.zo=c{#`:U0>s& !7mr*mቯ߇:rY,<)SХJ.͔t8P?:\N?~YS-#ZRBo)U;s&؁"2B8\=d{Il^wS9h9ĤؑjYߣbu;L_u7cjLmAJnA-$JV7EW(B#!@^hM3n v ]jL-?9*eͤ3£_Is=xux@/+Ncp My+ ,P:JUO` Tx0:Omv,n̹6\6Z&|S5.m/嚻n9+_E}U]: hO*q5GB|to-U"~Ubъ`R}r6=cej힊;L.sեkx9ַ;1*΂0Tݰ$P{ .lK l^kIG ִ=^#e(v-t9>-.*uR#iȚI%`ҔW8W@lUTs'r%kp`~Mٖ4I'|07p$Rva$Tnv”7\&RSuxwMjoZIϺB<_H2O(o \*o,75UWUc]˞_@m sD% ?s 6(T4bW[RQԠQ4^JOtC*f4')x>%tOnR@iHI3ރT &(FՔ >r:t[K$(=j. -`S85TSnC]/y ,47Ц)@sFZꄌof`5["-LLkKş(9Wzn T,M_ Q݀_(rbܞvEn؁za+a0~i~2u #OfTulW(iPRUW/V<mqz.wOqL S859!F\7~ k;OwN"(,-8a$MU=OTFNj8fdߪgi4Db(zvza9ç>dvcE pڭ5MW4#qs+[.ٌ̭o RQ&fT΁LE.8F2 l(6O.^[Gp6BUب4;~0%KKJC]2,Jdog:Hh o`Y{9yN-GkU4w$zi|܊Cúic\w71 73;$D~9'.A86I 0N)yp>G4eX+. \[^=hW =rU pޝ/9q7%ђ֗TL!:D[ qqzC.āz,71ci#(gй) 誻%դ \:JMi=9x /]:̓lw ]Ĩ7/eD/#Tk'M$ QLtbfO@oo7-$69sj%G%lOq׭OW389KׁuTnPOoLr7mua (em.:Rm?| Wi6(*'Ʋ6?E*CɥF9d*d3 ;ca>s(0jO@: V_Գ3\Z~w޳mc5+mk횐6yY7͎jxQ7R7U4p"͢nJN"]UXD s$DŽ2!hr`lJ lB-(qprk2?kt_J6r1rB+7ɘ]Mdf9MwbnO\`r©H )$h PhN (?4tFp@葛GלoJ۝t+A9jY_mbc BY,r^5X0WioIbIӀ+gإ>a5* kgc7I͝|PLJQMD+(9tZNﱇMW-\2 2:;Nѩcأ*A~Ef9X"E/2giADc T} øu1a,wоYWI|MyǩN+qswB!܀#&>26JYG|ӰOO%*]Qp/v `Lq9eAj{ Ҙ^ecZ{+d&f`R2Sʭ40Ž12]c'ת0Y0vGRZ4KfCob^tps.&"ez-z6ߊn'~H;yH@"&O|'eܶ@쪄u5fܐkxjp=HWv0;j^蹉(/G2u=r GؖbPpcSw됿=Z$;GB.#<-;l]n%&PX_)tKeY%Cj+)2ya#}ZC;NOw}pWPSC%{dZ*)n&H?wSBu ՀD <3५Si ~ Dvgmo TJ925[i52; O1^,pI$ICl?}ɉ3\::K:/7N]*>S6?-gz{zrQr׈{N䯡!|Tw+Ⓓ.+~cFgѺ=mUtc:p.>韣F -.OBSCZ `V87G n'NRO&u`9FnRlzWJFۢ3xM! 7FZ%H h-2zs U%h/sAgcgCu O.&Ѿ/:/1QF;cKA+O\DʫX Xo`m lscqVc= k梒:GIufiz1KKES' v0LDDKkT΄ĠT`DG;W֜HOhW cūY)o箕>`u 8%$ڕG~zx饰˩Kǡ8ӵm[*QE vi%I[O2?whpoSk(G:}qn}ip ?4X+B>}e˫&aeg!wWo\} io9{G6b_|6wt6#8 8#k{` \vDDKx ShE•΃ҕ; ^-Na&)5OWd 3ӭy.Ɍ(F%P. ۹oIdJR* tF:tׯៗ%0q-NE\i,raJ?p9:)M3xP6ANgSڼ:bNXRFgtLzEwؙxpU밈ZsS X6ȝ rs81a^R;cTHAU3rsƵ mJLci-kC)e?b{)mmcQ?ǙAF{jhe1c|ܐbBV<+oT\a9]\Y%-A,rZ3iY-Y'6 |4IGrjIE$@Jw;\%w2TaEp5E]$5?nSW*2G'g? m*飘+g#yd5 Z>鵁47J;H#`/Hל&HEO< q~]rRW.L9r!el&ΜP1 P\j\ s]\/lv3m{:ܖfN!v(~GWW@,i4T]]i#ooeGxN$eX- ay [eg0]!K`(Ԍ:&4X=6T^{趼~ m^m3/fW`2y֖=}n 3qҎQl+1! qKE' +i [1$DU JѠYk\67?|3d2^M9:CcvB %*F܊Tsa[^llD ޠsx,x-AןUHOq>?s9H0O?Q(2t10̉$8HnẓS=$?}ZopDyZ&_O߳t5_x\%S'p٫l6QmD/8|f@h1JgR{C~}cQ-l-m,Jv} ;hdJۃkjٻ%#a/(_q$Q:XdSI,g;c 9鋣BBVuw[ߠ=>RSMQ8هk{43 Q2V(8Suj-H5J(9e0ĞhV Jӕr z hhci1g fW_):A: W@c0[ʵ];@j-Qyc;2#6#Jmay o ;Ԅ*|NÆCr-&2,k}+ԁ}65

E[f YeN^/#:IǝMyyulj2c )${fHHp(^ܝVݭxqwmp-ܧ?s} >v(Ղ"4 S1^@Bpx4QKJEAPE8I+<kIq\̆i2cW+>pC OZk6 2YB5N:*Ʀ) `eιBu6yBނo7}ЏWʦ7~@br9*sQ^^$χ\.qH*CeiS*-yǧQ%YVwLI=K[F]t5ֹ:G4bxW#KʣRnc/#=7NJcۇPTLnTq=䂫vq *+.$2= '"z|nZSFN,a.fـ9g+y/`N>mx=hy0uT䶡t.V,y?D_8 Ѳ7=6lߥ9jb,ϧP.G؍O㶗fs~ۜr o@klȮjW~<5+;=l3d?)o;kzNeo?|2';xMSI)uUҹќMA#X?q p/0g[V2UU4j3 ԪCUiNVù G)R&$KSU/=-ZzHYuZD~[]k?D."q)-ed4ϣ>0bWX sD2^B͚z&-Ie! 6tSM Iӌpf:e\l=%ITC IqtyH{;tv 'PEA!x}C'۹.G5 酾ɄiEO[Wz.+1TT\no.Q.U^2Wr˂t^PTQÒ~`u(9z qO7 SNxLye:۠}֗ Xąew1|96{\ֈ4vUʫ _9??Q6|ӍWMx#,`hZ (f+1a@ ;ec+ 5wHJA ԕoC\qx%""$.lS141)Mtk̅]0}Cv'2+GɁ9҈{?׾;-w|IDQ,9pyD0mHe^k1.LstgA yoG`,*HEpCU&(vY ԃ ZUFEv H[](㚰]pg_m*w YN{Q,.'NOW A Ԗd7cI^Gs˅aVX/K)Zbm՞֗C6 NOWO[3ב'MP̟ESaDZ $\װm,l1i$ws4v9]t.GdW&KE,ǃt~Y\ݥP[.!?E>D'#0C =g1ę𮬰?̼WNLA ÜoA)uq\82K [NLͧ^[p{|y=MܤΟ6ntʛ_]H)' z#AhْRG~B~C. tDyLo ]^3r ۶TV\.ɑiM5hl*ն*^}rn6[nATYJqpѮ-46OI@ 2|B4D/S)tnlqsb#\xSB,h-C-(`5j&k|*G,ctԒ-Mp VXHi(#ơ BO*%+=-Y Ω\5nL.52`/> 4 2DaDH uiQx{? ZFE,wғQqW bx)?I\̥ޜϰt|IIpJZKObJףvS]Ԍb\C(nX~` 7t55 iu ummb̟"yIwQ`nqlwq: $Q[[TFڤF4G}?bzyG8 Euj{x%UCu^S5>sK  :K9ܓ2 W@>([(oY egtgS]l~iZL>㚨ΥT& P5_sv~lMҚt餰 W+L4pur;4], XoqW`K;O2ArpGia=kM aKc)Ő%N㡦mlPscVmkNy#`yHEC;![!nZ{dLlrKR& rI˕p7E)-vehЃM_< R\]NMbBhAF/'aԌUc~nIOxG9܎fͷsN婗4/BgǑ:?/TO6q{JXt8:h W[Ls4zQf_lь^l\Զų%}fXL+(z\+p@ݎ ]uLeH%3NS&q4ָO^kHED F`OwxؗviCE)G\I64<t9=h8J ?pdv9 e_&.'tC^K`_+^ .T2R G(^bGZ 4vkͥ0Ro%.Es9;a-cA }n+d)dZk(|ߨ_4؄P@Qv(UjAaʧe6ҼexI튣:s G9+42v0h@3h0'D̐ -,tCk9>7 uGA)= 7y YT:`:s 'ڛ6\r[pZ=~d7QI^F8܍J& (yNx7 崸\cCGz;lc7\*x1Q~W')ҔJdq:1>9~j!ۅOOMjYr}mN9DlfOPYzךu36~Pc ON qm%77(8&$XH.ϳ%"cUT\vO{!m/֤Dz*n/q}!w3!]b*)4Q[xSÏKg̡G#bȏŽ$7\5ɫXV -zϰ>TKOW8'ch[%r4F`5ڤ>P`zfZ  +yYZbq"ŅMpBU3m[>drX24H 5`K >^&' F6kH5)e<2؋PNc.+U㘀5l3,NB,f]*Nw|qlRψh5@D )gAS rR krX3Qnvk55tSů$ueVZFi/ѹA~H. ,H2E?ফ0w44@~>=}2J%jh3!UTkT8 UjG4o{G2.[V&çQ'`# 3fC^n8VPH>ZROkEXU1xr%1ײkXv ƝJݾ 8'SOJ\ 4ؕc/. pË!<podlȉ4牘\E66%swupTrbIJOڨe1h-I4؉XToI _hSIz&@2 À|Uv.&'?NGApiNv~7aNRb- cCMdRH]x_A'js=c*B !eehOiUk FpD+u/1=C5x[CTݔݜ؞O̳^;)iX;J\B6:ECj h~宒[R8$Ozx+ dtm_%)%y;6s9 ~^†ևbB/e HNc~בWGh.\*mDvRQvBj,Z+?71faŵ!㛤X;묇7XIX/PNé9^ Mq3^37-Lqcsxn HZ p ghVյi6a‡zo5qu ЦЬjjx*T[Jr t9cu])#E}0wm$|]{7rcA* dγ;"l>ͯHa+J1!gSQvB6ʜ0@9$_bl&P Gq+ B\Cԅ~LNV9v4bW䚹yUE"UQqZ>JK5wDiBKTӍ:`~M|*4./wg9O¿֕&f .Tצ30mLuaAc'|;. U'{.I `Y01]Ri Soh4k,i| ^OO@5p8*bXSm3/*sji[4zYίz?;+$9r^-mr/~F2i ;fMUwwb'vHMml)([hC)ʟ ,?)X3sz/O Vl$IDATߥyHqqx`>ȎXc\5 smp p>_b"I9^ /~. c^'Ƿ2y@cxhW:͞-nn.:r~p$Q. g(%n '`lVܘCm $mz07l6#Ni'奿(kxWĮ.ą|gB ÛuU@L >!C.FP{V|jCeS6"4X9JWW0s7jեB_@q.Mr:Kr3RI8&QGebvntvݣ@j<.β4BW_8f}-l.f*{C:IO1y1wllvqXXD@W308k񦼷 s(j ť!.ԣ$x=wInp崄R F|R48+S%#J O*55{:I^㹑8X2`Y9ߴӖ;H") '1JlSytj[/e7xkH[aFS͡Ҟ] !!bCiE}1jK)=noOciC_k܃ K$t]. =e*]G(Om%EV.ye3wVZ^M]L[05*t IjmQv9*L2 bJ\lD.^%##R]~p.5`r`SJyf )rR+G7\y8u%TR5[ yc>gBkiB2 6};Cz ax=#p٫*H&0LsqYK4+S.TpT"3PPUbEJajV!M;JkmEk>́W*BS#jo.JG9; q^cێ~"ȋAѮ[R&W*Զ0IƟ%v2+e'![W})?KҿRD~'Of>Jn8~q :Y̧$A 8>J=LrAtB/[Qh8OQk!T\nFD=5~9"%O`߈ke׎S.=$ sSJJr)%s.I@=a't9!u5M4ܑː@2,VPҦӻ\`y;:fkOJԂjܓ=2J_u8@hC(tPX,ԞθOQNC./Ty{G.Ձ% 6wC l:~-caЭ.<:iTsze|P:f*9(yWc|7i7 Y #t/FGd𮘒JBDV7X)9:u )5~#XKzR&; " Ɛ w ʃ3ΰ0wɝЅW5zKu~r 2LiI›ba\xA|GcoKȋ8-@7PlIX<«jwR@~J#wLVKF*@,O-[?%!lSb&3w{G؂P e"ޔ^]iIOmnNFOp !פӴUnOo5sUd8 xMB^6R}Ugjt ǻ[j.hܩt/ڦgG03ܗh+Ҙ)/50q qMnpέ`8/x.,O9_&XgsUr隊t!WLN3)pq1ݣOȭl!ڍp;MHDCRPzcV '(6sG%=vP !T]03W~"y$0||hb ]aܧURu`l[K7` `Nowa4:v?8B Tg56nTvbuc Ǫؘ:wC#"'Tر ibszB*e >s ـb1ypyf7ALhM';SÞ%G7IiKxw;o)O]MQbp顑S=sڹd[ yuCȞA1YݽjE錎b[X]I7PK#Zi`^`ȥX>yF{ t_M' n ly< a]#JTy?Jqǽ9AP `E3- VB9OJYH^NK&®zGI;/ }'q]\+m>׋9ܯ+[&Ȩ@7ʍ}zoJI)?\1g:dqM_17]h.:w+r.X 8Ǧ7̚$d<[0T-UrbD${Fg5=弿q$^z-f፟%YqG) Ӳ @/pYK9.݃Ap~FΤQ^}z뱆~tUDRKsl?.VMP.ӃRΧ&h.؆\L p~Sγtz(S3OUQ|<~NmםOEj啙>0^ phk(>~eG٫;}c_J"@K$J)pwv9 ڼp c/g#cydzۤ0\]d*%Xn|69Gbzŭ[#vR;oQ{bIA1E 5ס5)Mb'Q6kp\Os&5x`N*I2좁܆S|hxDr;y;y %Wh4|4V^f.MCM_*TBLRaC:&mޮU2J b:(.܆H&n!ŦWk.Ƃ%T0]AbYI)iӴv$_9=v&Utq?f/uwg?|UU7Bj~d M$Qn-Whb:΃ϥ;}P>JZkɨdזZCRgJ*R* o\%59ɤoiN{G")~N"پZp@IwU6\K}vm]u`l([ܔLSEBYm^iJB$r>/2]S\4 (pɾn.(Wڐ)S5i[|¤E^`x !1 n#p (f ,#Y-d krЎtKl$]S 8 wgt}`7:gb#7RG 'i,wi +)uaԘ Ʈ3v[Pv)- W p0oJZ0'sk`>Uq/m}mLF'aQD?0{ f90uKbZ.G,zxv=dJ!y a-ju#6q rnlC}yJ xK7xZfsALý4ou!)Uc?AK͑с\S벥+N]2˥&Bx!} I[rg_p ת@7f/p+A'h+ݣoơnȥg bxmEHSsmH)+oƔC!NdeFVWrk$x]~|"'+b2ջ(\szf[70 *F]jH3=^S%lFa v.h^io4y-L*_us穲]̀\?i<'jyi%1bێ.Cv͔Eqwv&,9ElB8Xm;Ml%z $e`ĊjJ"^uPCF'5垺FWN~12|>GA8 PU]-eqYXkwT`ma0:ux< v84X4 ,7  :lRr{1:\[)*pǪsT.";hR܋Rm^2 Ib)9KdӘ mZkz{Oγ>.ZPՑNѫIhH*LV-&,U`Cm\4Xi-{ 7 ^# 4 IkC醲6|%'CL+a%XՖ>a|(zhOǚ4"N q#ǵ.>!np?2~-vH;*D4q%ZX+:_tK$suJaۃ_ _`dd۰p 0Gs]HitZp\98HLc {63LSĢ fck/Xc/aV.j+'\p)u$*%+.Lӹ K_f¥؊)T]X|7s3N[v#X_HZꦉUOUi};V kxc«p=MN-V#L2BɯыQIC`n>;vMHZohOpOT%KKЍb_\vASP8r?".ci?>E삁.6 暽_xl5e 3?4Dlj Set1jS}+I?97 d3ykXԅZÐ 2 +L =%kfh~)-{HMbx{f SJ h ?5L,HrT)+T eӮYf1Xrݕܖ5@ӿpUjT}i5eЇRe߻@&rBve]$ |]a| 9.D=wT{JeG=WbWZ'L?΄(!$W` Ǩ!ӿ1E2²60.nR X r{,/fe|krB_W9䝬SBF)4Gw/X &lk.09Rs'o]opxFצ$Z)`p"NQx)\3q8W&psq:\aJ厮QdئVG1!P/lFGlzgspv ͤFh!yi$o\J@{r%G!%J^`:)4JOMUV\?H㦿4>:(aFs3ډDOi(-Ӿ~Bk\ۓ>YLu.&57î2tt#ihB!pkk|Q)3ف!/<0nmƊ$}Y)cWR!k3g9{ym,iqE?C7P(,ᜈRaka~m-bNpT٦J~C`!V㩕7h%([_SG; ?f+x=a7\d%/3mHaRm,x T#)X~J!^f))Uُ.=xs8s۠Ҷ4l}x %,& lJcؚ;!$<6 ."-a@^+Кrrm-z|Gb^\ }Qu0m734 x?@Ri\97Np 11,ď`87æ G b>HF)mI 5 ])q9W8\BlR'LQrxPN ]FvT}F1@W.$%K7u`|ngA9:7YKGWs|W|SMBewBs=SYh^k܋_\w[25@5Gg5 'jby㺫C2[6sXZ)TԦ78%X376QBnXOqUxVRH}x ŢTe]t JNteS9X+vGp2&̆6YɁE ׋8]ȯEP.(̇8# u)*Q^'w"'Q^bzM?轲vC!9嬾S wp͕O> G(F0#ͼ |J e5vHytp;>N![8pg?Xcp?!K폷w_`!]OgJKB?(yԥzߞG4ZSB\ym˻!u2oHW#s yP VO\[pB̆ZK]{3. ^<zM789}Nmuog=V9W̠Gۘod6RvSRii\݁H18O)"܃jdI^몺ofo-ߒ`*$>¼.?Sw_|ɮ]JY͞¿8b,5rBr_>P @r:y|K.YJƶ5>Z 5rFc DnA~b1WOؓ_Ho3qb.D64S 9Jw]gUM!3<#Ju]_^JXYF¦Tsȟ<]a7Nr>U^La>Ov)=lKR颿 @wl=L$5`31&,74aEѫe-&3ۄ۵Xl!"nRs|&ԫ&_yK{> kM $K!8VvIⰫjW7#תx XD~ 1BJ|׆%<)N_9߱*ROI\3I /ևKf[~ &Y@a:܂<a\ށi7tÎn3R& M v2l *֡a< Q\m[:۹58mW=)F-lh+©v[Dy!m[vΤPI *KGGM_mmh03-V ;cSlloqIdRx Tʬe rR}sZg7żw4#2N-骅)I;0Zv@"J}:zn~"?9Q.F7'lc3l`~' Ҫrt^K#+-_8m ,&l ^RL*ɳ8߱ of%tEXtdate:create2014-07-04T18:58:07-07:00r0%tEXtdate:modify2014-07-04T18:58:07-07:00/8IENDB`pgmodeler-0.9.2/libpgmodeler_ui/src/000077500000000000000000000000001360462764600174475ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/src/aboutwidget.cpp000066400000000000000000000035641360462764600225010ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "aboutwidget.h" #include "pgmodeleruins.h" #include "baseobjectview.h" #include #include AboutWidget::AboutWidget(QWidget *parent) : QWidget(parent) { setupUi(this); QGraphicsDropShadowEffect * drop_shadow=new QGraphicsDropShadowEffect(this); drop_shadow->setOffset(5,5); drop_shadow->setBlurRadius(30); this->setGraphicsEffect(drop_shadow); PgModelerUiNs::configureWidgetFont(title_lbl, PgModelerUiNs::HugeFontFactor); PgModelerUiNs::configureWidgetFont(pgmodeler_ver_lbl, PgModelerUiNs::HugeFontFactor); PgModelerUiNs::configureWidgetFont(build_lbl, PgModelerUiNs::BigFontFactor); PgModelerUiNs::configureWidgetFont(build_num_lbl, PgModelerUiNs::BigFontFactor); pgmodeler_ver_lbl->setText(QString("v%1 ").arg(GlobalAttributes::PgModelerVersion)); build_num_lbl->setText(QString("%1 Qt %2").arg(GlobalAttributes::PgModelerBuildNumber).arg(QT_VERSION_STR)); connect(hide_tb, &QToolButton::clicked, this, [&](){ this->close(); emit s_visibilityChanged(false); }); double factor = BaseObjectView::getScreenDpiFactor(); this->adjustSize(); this->resize(this->minimumWidth() * factor, this->minimumHeight() * factor); } pgmodeler-0.9.2/libpgmodeler_ui/src/aboutwidget.h000066400000000000000000000023001360462764600221310ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class AboutForm \brief Form that contains information about software authoring and licensing. */ #ifndef ABOUT_WIDGET_H #define ABOUT_WIDGET_H #include #include #include "ui_aboutwidget.h" #include "globalattributes.h" class AboutWidget: public QWidget, public Ui::AboutWidget { private: Q_OBJECT public: AboutWidget(QWidget *parent = nullptr); signals: void s_visibilityChanged(bool value); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/aggregatewidget.cpp000066400000000000000000000142521360462764600233110ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "aggregatewidget.h" AggregateWidget::AggregateWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Aggregate) { try { QGridLayout *grid=nullptr; Ui_AggregateWidget::setupUi(this); QSpacerItem *spacer=nullptr; QFrame *frame=nullptr; initial_cond_hl=new SyntaxHighlighter(initial_cond_txt); initial_cond_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); final_func_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); transition_func_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); sort_op_sel=new ObjectSelectorWidget(ObjectType::Operator, true, this); input_type=new PgSQLTypeWidget(this, trUtf8("Input Data Type")); state_type=new PgSQLTypeWidget(this, trUtf8("State Data Type")); input_types_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::EditButton, true, this); input_types_tab->setColumnCount(1); funcaoagregacao_grid->addWidget(final_func_sel,0,1,1,1); funcaoagregacao_grid->addWidget(transition_func_sel,1,1,1,1); funcaoagregacao_grid->addWidget(sort_op_sel,2,1,1,1); grid=new QGridLayout; grid->setContentsMargins(2,2,2,2); grid->addWidget(input_type,0,0); grid->addWidget(input_types_tab,1,0); state_input_types_twg->widget(0)->setLayout(grid); grid=new QGridLayout; spacer=new QSpacerItem(20, 1, QSizePolicy::Minimum, QSizePolicy::Expanding); grid->setContentsMargins(2,2,2,2); grid->addWidget(state_type,0,0); grid->addItem(spacer,1,0); state_input_types_twg->widget(1)->setLayout(grid); connect(input_types_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleDataType(int))); connect(input_types_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleDataType(int))); frame=generateInformationFrame(trUtf8("An aggregate function that accepts the types typeA and typeB as input types and which type of state is state_type, must obey the following rules:

   • Final Function: void final_function(state_type)
   • Transition Function: state_type transition_function(state_type, typeA, typeB)")); funcaoagregacao_grid->addWidget(frame, funcaoagregacao_grid->count()+1, 0, 1, 2); frame->setParent(this); configureFormLayout(funcaoagregacao_grid, ObjectType::Aggregate); setRequiredField(state_type); setRequiredField(input_type); setRequiredField(transition_func_sel); setRequiredField(transition_func_lbl); configureTabOrder({ final_func_sel, transition_func_sel, sort_op_sel }); setMinimumSize(620,700); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void AggregateWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Aggregate *aggregate) { unsigned count, i; PgSqlType type; BaseObjectWidget::setAttributes(model,op_list, aggregate, schema); input_type->setAttributes(type, model); state_type->setAttributes(type, model); final_func_sel->setModel(model); transition_func_sel->setModel(model); sort_op_sel->setModel(model); if(aggregate) { final_func_sel->setSelectedObject(aggregate->getFunction(Aggregate::FinalFunc)); transition_func_sel->setSelectedObject(aggregate->getFunction(Aggregate::TransitionFunc)); sort_op_sel->setSelectedObject(aggregate->getSortOperator()); initial_cond_txt->setPlainText(aggregate->getInitialCondition()); input_types_tab->blockSignals(true); count=aggregate->getDataTypeCount(); for(i=0; i < count; i++) { input_types_tab->addRow(); type=aggregate->getDataType(i); input_types_tab->setRowData(QVariant::fromValue(type), i); input_types_tab->setCellText(*type,i,0); } input_types_tab->blockSignals(false); input_types_tab->clearSelection(); state_type->setAttributes(aggregate->getStateType(), model); } } void AggregateWidget::handleDataType(int row) { try { PgSqlType type; type=input_type->getPgSQLType(); input_types_tab->setRowData(QVariant::fromValue(type), row); input_types_tab->setCellText(*type,row,0); } catch(Exception &e) { if(input_types_tab->getCellText(row, 0).isEmpty()) input_types_tab->removeRow(row); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void AggregateWidget::applyConfiguration(void) { try { Aggregate *aggregate=nullptr; unsigned count, i; startConfiguration(); aggregate=dynamic_cast(this->object); aggregate->setInitialCondition(initial_cond_txt->toPlainText()); aggregate->setStateType(state_type->getPgSQLType()); aggregate->removeDataTypes(); count=input_types_tab->getRowCount(); for(i=0; i < count; i++) aggregate->addDataType(input_types_tab->getRowData(i).value()); aggregate->setFunction(Aggregate::TransitionFunc, dynamic_cast(transition_func_sel->getSelectedObject())); aggregate->setFunction(Aggregate::FinalFunc, dynamic_cast(final_func_sel->getSelectedObject())); aggregate->setSortOperator(dynamic_cast(sort_op_sel->getSelectedObject())); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/aggregatewidget.h000066400000000000000000000037371360462764600227640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class AggregateWidget \brief Implements the operations to create/edit aggregates via form. */ #ifndef AGGREGATE_WIDGET_H #define AGGREGATE_WIDGET_H #include #include "baseobjectwidget.h" #include "ui_aggregatewidget.h" #include "pgsqltypewidget.h" #include "objectstablewidget.h" class AggregateWidget: public BaseObjectWidget, public Ui::AggregateWidget { private: Q_OBJECT //! \brief Function input data type widget PgSQLTypeWidget *input_type, //! \brief Function state type widget *state_type; /*! \brief Table that stores the multiple input data types. The elements in this table are converted to class PgSQLType and assigned as input types to the aggregat */ ObjectsTableWidget *input_types_tab; //! \brief Syntax highlighter used by the initial condition field SyntaxHighlighter *initial_cond_hl; //! \brief Aggregate functions selectors ObjectSelectorWidget *sort_op_sel, *final_func_sel, *transition_func_sel; public: AggregateWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Aggregate *aggregate); private slots: void handleDataType(int row); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/appearanceconfigwidget.cpp000066400000000000000000000340221360462764600246450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "appearanceconfigwidget.h" map AppearanceConfigWidget::config_params; AppearanceConfigWidget::AppearanceConfigWidget(QWidget * parent) : BaseConfigWidget(parent) { setupUi(this); QString conf_ids[]={ /* 00 */ Attributes::Global, /* 01 */ Attributes::Constraints, /* 02 */ Attributes::ObjSelection, /* 03 */ Attributes::PositionInfo, /* 04 */ Attributes::PositionInfo, /* 05 */ Attributes::ObjectType, /* 06 */ Attributes::LockerArc, /* 07 */ Attributes::LockerBody, /* 08 */ Attributes::TableSchemaName, /* 09 */ Attributes::TableName, /* 10 */ Attributes::TableBody, /* 11 */ Attributes::TableExtBody, /* 12 */ Attributes::TableTitle, /* 13 */ BaseObject::getSchemaName(ObjectType::Rule), /* 14 */ BaseObject::getSchemaName(ObjectType::Rule), /* 15 */ BaseObject::getSchemaName(ObjectType::Index), /* 16 */ BaseObject::getSchemaName(ObjectType::Index), /* 17 */ BaseObject::getSchemaName(ObjectType::Trigger), /* 18 */ BaseObject::getSchemaName(ObjectType::Trigger), /* 19 */ BaseObject::getSchemaName(ObjectType::Constraint), /* 20 */ BaseObject::getSchemaName(ObjectType::Constraint), /* 21 */ BaseObject::getSchemaName(ObjectType::Policy), /* 22 */ BaseObject::getSchemaName(ObjectType::Policy), /* 23 */ Attributes::ViewSchemaName, /* 24 */ Attributes::ViewName, /* 25 */ Attributes::ViewBody, /* 26 */ Attributes::ViewExtBody, /* 27 */ Attributes::ViewTitle, /* 28 */ Attributes::Alias, /* 29 */ Attributes::RefColumn, /* 30 */ Attributes::RefTable, /* 31 */ Attributes::Reference, /* 32 */ BaseObject::getSchemaName(ObjectType::Textbox), /* 33 */ Attributes::Column, /* 34 */ Attributes::Column, /* 35 */ Attributes::InhColumn, /* 36 */ Attributes::ProtColumn, /* 37 */ Attributes::PkColumn, /* 38 */ Attributes::PkColumn, /* 39 */ Attributes::FkColumn, /* 40 */ Attributes::FkColumn, /* 41 */ Attributes::UqColumn, /* 42 */ Attributes::UqColumn, /* 43 */ Attributes::NnColumn, /* 44 */ Attributes::NnColumn, /* 45 */ Attributes::Relationship, /* 46 */ Attributes::Label, /* 47 */ Attributes::Label, /* 48 */ Attributes::Attribute, /* 49 */ Attributes::Attribute, /* 50 */ Attributes::Tag, /* 51 */ Attributes::Tag, /* 52 */ Attributes::Placeholder, /* 53 */ Attributes::ForeignTableSchemaName, /* 54 */ Attributes::ForeignTableName, /* 55 */ Attributes::ForeignTableBody, /* 56 */ Attributes::ForeignTableExtBody, /* 57 */ Attributes::ForeignTableTitle }; int i, count=element_cmb->count(), //This auxiliary vector stores the id of elements that represents color/font confing of graphical objects obj_conf_ids_vect[]={ 2, 4, 6, 7, 10, 11, 12, 14, 16, 18, 20, 22, 25, 26, 27, 31, 32, 34, 38, 40, 42, 44, 45, 47, 49, 51, 52, 55, 56, 57 }; vector conf_obj_ids(obj_conf_ids_vect, obj_conf_ids_vect + sizeof(obj_conf_ids_vect) / sizeof(int)); conf_items.resize(count); for(i=0; i < count; i++) { conf_items[i].conf_id=conf_ids[i]; conf_items[i].obj_conf=(std::find(conf_obj_ids.begin(), conf_obj_ids.end(), i) != conf_obj_ids.end()); } color_picker=new ColorPickerWidget(3, this); model=new DatabaseModel; scene=new ObjectsScene; scene->setSceneRect(QRectF(0,0,500,500)); placeholder=new RoundedRectItem; viewp=new QGraphicsView(scene); viewp->setEnabled(false); viewp->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); viewp->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); viewp->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); viewp->setRenderHint(QPainter::Antialiasing); viewp->setRenderHint(QPainter::TextAntialiasing); viewp->setRenderHint(QPainter::SmoothPixmapTransform); viewp->setAlignment(Qt::AlignLeft | Qt::AlignTop); viewp->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); viewp->centerOn(0,0); QGridLayout *grid=dynamic_cast(appearance_frm->layout()); grid->addWidget(color_picker, 3, 1, 1, 4); grid->addWidget(viewp, 4 , 0, 1, 5); connect(element_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(enableConfigElement(void))); connect(font_cmb, SIGNAL(currentFontChanged(QFont)), this, SLOT(applyFontStyle(void))); connect(font_size_spb, SIGNAL(valueChanged(double)), this, SLOT(applyFontStyle(void))); connect(bold_chk, SIGNAL(toggled(bool)), this, SLOT(applyFontStyle(void))); connect(underline_chk, SIGNAL(toggled(bool)), this, SLOT(applyFontStyle(void))); connect(italic_chk, SIGNAL(toggled(bool)), this, SLOT(applyFontStyle(void))); connect(color_picker, SIGNAL(s_colorChanged(unsigned, QColor)), this, SLOT(applyElementColor(unsigned, QColor))); connect(color_picker, &ColorPickerWidget::s_colorsChanged, [&](){ for(unsigned i=0; i < color_picker->getColorCount(); i++) applyElementColor(i, color_picker->getColor(i)); }); } AppearanceConfigWidget::~AppearanceConfigWidget(void) { scene->removeItem(placeholder); delete(placeholder); delete(viewp); delete(scene); delete(model); } map AppearanceConfigWidget::getConfigurationParams(void) { return(config_params); } void AppearanceConfigWidget::loadExampleModel(void) { try { RelationshipView *rel=nullptr; StyledTextboxView *txtbox=nullptr; TableView *tab=nullptr; GraphicalView *view=nullptr; unsigned count, i; if(model->getObjectCount()==0) { model->loadModel(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::ExampleModel); count=model->getObjectCount(ObjectType::Table); for(i=0; i < count; i++) { tab=new TableView(model->getTable(i)); tab->setSelected(i==1); scene->addItem(tab); } count=model->getObjectCount(ObjectType::ForeignTable); for(i=0; i < count; i++) { tab=new TableView(model->getForeignTable(i)); scene->addItem(tab); } count=model->getObjectCount(ObjectType::View); for(i=0; i < count; i++) { view=new GraphicalView(model->getView(i)); scene->addItem(view); } count=model->getObjectCount(ObjectType::Relationship); for(i=0; i < count; i++) { rel=new RelationshipView(model->getRelationship(i, ObjectType::Relationship)); scene->addItem(rel); } count=model->getObjectCount(ObjectType::BaseRelationship); for(i=0; i < count; i++) { rel=new RelationshipView(model->getRelationship(i, ObjectType::BaseRelationship)); scene->addItem(rel); } count=model->getObjectCount(ObjectType::Textbox); for(i=0; i < count; i++) { txtbox=new StyledTextboxView(model->getTextbox(i)); txtbox->setSelected(i==0); scene->addItem(txtbox); } placeholder->setRect(QRectF(170, 280, 100,50)); updatePlaceholderItem(); scene->addItem(placeholder); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void AppearanceConfigWidget::updatePlaceholderItem(void) { placeholder->setBrush(BaseObjectView::getFillStyle(Attributes::Placeholder)); QPen pen=BaseObjectView::getBorderStyle(Attributes::Placeholder); pen.setStyle(Qt::DashLine); placeholder->setPen(pen); } void AppearanceConfigWidget::loadConfiguration(void) { try { int i, count=conf_items.size(); BaseObjectView::loadObjectsStyle(); this->loadExampleModel(); for(i=0; i < count; i++) { if(conf_items[i].obj_conf) { BaseObjectView::getFillStyle(conf_items[i].conf_id, conf_items[i].colors[0], conf_items[i].colors[1]); conf_items[i].colors[2]=BaseObjectView::getBorderStyle(conf_items[i].conf_id).color(); } else conf_items[i].font_fmt=BaseObjectView::getFontStyle(conf_items[i].conf_id); } this->enableConfigElement(); font_cmb->setCurrentFont(BaseObjectView::getFontStyle(Attributes::Global).font()); model->setObjectsModified(); updatePlaceholderItem(); scene->update(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo()); } } void AppearanceConfigWidget::saveConfiguration(void) { try { attribs_map attribs; vector::iterator itr, itr_end; AppearanceConfigItem item; QString attrib_id; QFont font; itr=conf_items.begin(); itr_end=conf_items.end(); while(itr!=itr_end) { item=(*itr); itr++; //If the item is a object color config if(item.obj_conf) { //Creates an attribute that stores the fill color attrib_id=item.conf_id + QString("-color"); if(item.colors[0]==item.colors[1]) attribs[attrib_id]=item.colors[0].name(); else attribs[attrib_id]=item.colors[0].name() + QString(",") + item.colors[1].name(); //Creates an attribute that stores the border color attrib_id=item.conf_id + QString("-bcolor"); attribs[attrib_id]=item.colors[2].name(); } //If the item is a font config else if(item.conf_id!=Attributes::Global && !item.obj_conf) { font=item.font_fmt.font(); //Creates an attribute to store the font color attrib_id=item.conf_id + QString("-fcolor"); attribs[attrib_id]=item.font_fmt.foreground().color().name(); attrib_id=item.conf_id + QString("-") + Attributes::Italic; attribs[attrib_id]=(font.italic() ? Attributes::True : Attributes::False); attrib_id=item.conf_id + QString("-") + Attributes::Bold; attribs[attrib_id]=(font.bold() ? Attributes::True : Attributes::False); attrib_id=item.conf_id + QString("-") + Attributes::Underline; attribs[attrib_id]=(font.underline() ? Attributes::True : Attributes::False); } //Special case: treating the global font element else { attribs[QString("font-name")]=QFontInfo(item.font_fmt.font()).family(); attribs[QString("font-size")]=QString("%1").arg(item.font_fmt.font().pointSizeF()); } } config_params[GlobalAttributes::ObjectsStyleConf]=attribs; BaseConfigWidget::saveConfiguration(GlobalAttributes::ObjectsStyleConf, config_params); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void AppearanceConfigWidget::enableConfigElement(void) { //QPalette pal; int idx=element_cmb->currentIndex(); //Widgets enabled only when the global font element is selected (idx==0) font_cmb->setEnabled(idx==0); font_lbl->setEnabled(idx==0); font_size_spb->setEnabled(idx==0); unity_lbl->setEnabled(idx==0); //Widgets enabled when a font configuration element is selected underline_chk->setEnabled(idx!=0 && !conf_items[idx].obj_conf); bold_chk->setEnabled(idx!=0 && !conf_items[idx].obj_conf); italic_chk->setEnabled(idx!=0 && !conf_items[idx].obj_conf); colors_lbl->setVisible(idx!=0); color_picker->setVisible(colors_lbl->isVisible()); //Buttons visible when a object configuration element is selected color_picker->setButtonVisible(1, conf_items[idx].obj_conf); color_picker->setButtonVisible(2, conf_items[idx].obj_conf); underline_chk->blockSignals(true); italic_chk->blockSignals(true); bold_chk->blockSignals(true); font_cmb->blockSignals(true); font_size_spb->blockSignals(true); if(!conf_items[idx].obj_conf) { QTextCharFormat fmt=BaseObjectView::getFontStyle(conf_items[idx].conf_id); color_picker->setColor(0, fmt.foreground().color()); underline_chk->setChecked(fmt.font().underline()); italic_chk->setChecked(fmt.font().italic()); bold_chk->setChecked(fmt.font().bold()); font_cmb->setCurrentFont(fmt.font()); font_size_spb->setValue(fmt.font().pointSizeF()); } else { QColor color1, color2; BaseObjectView::getFillStyle(conf_items[idx].conf_id, color1, color2); color_picker->setColor(0, color1); color_picker->setColor(1, color2); color_picker->setColor(2, BaseObjectView::getBorderStyle(conf_items[idx].conf_id).color()); underline_chk->setChecked(false); italic_chk->setChecked(false); bold_chk->setChecked(false); } underline_chk->blockSignals(false); italic_chk->blockSignals(false); bold_chk->blockSignals(false); font_cmb->blockSignals(false); font_size_spb->blockSignals(false); } void AppearanceConfigWidget::applyElementColor(unsigned color_idx, QColor color) { if(conf_items[element_cmb->currentIndex()].obj_conf) { conf_items[element_cmb->currentIndex()].colors[color_idx]=color; BaseObjectView::setElementColor(conf_items[element_cmb->currentIndex()].conf_id, color, color_idx); updatePlaceholderItem(); } else if(color_idx == 0) { conf_items[element_cmb->currentIndex()].font_fmt.setForeground(color); BaseObjectView::setFontStyle(conf_items[element_cmb->currentIndex()].conf_id, conf_items[element_cmb->currentIndex()].font_fmt); } model->setObjectsModified(); scene->update(); setConfigurationChanged(true); } void AppearanceConfigWidget::applyFontStyle(void) { QFont font; font=font_cmb->currentFont(); font.setBold(bold_chk->isChecked()); font.setItalic(italic_chk->isChecked()); font.setUnderline(underline_chk->isChecked()); font.setPointSizeF(font_size_spb->value()); conf_items[element_cmb->currentIndex()].font_fmt.setFont(font); BaseObjectView::setFontStyle(conf_items[element_cmb->currentIndex()].conf_id, conf_items[element_cmb->currentIndex()].font_fmt); model->setObjectsModified(); scene->update(); setConfigurationChanged(true); } void AppearanceConfigWidget::restoreDefaults(void) { try { BaseConfigWidget::restoreDefaults(GlobalAttributes::ObjectsStyleConf, false); this->loadConfiguration(); setConfigurationChanged(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/appearanceconfigwidget.h000066400000000000000000000052321360462764600243130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class AppearanceConfigWidget \brief Implements the operations to manage graphical objects appearance configuration. */ #ifndef APPEARANCE_CONFIG_WIDGET_H #define APPEARANCE_CONFIG_WIDGET_H #include "ui_appearanceconfigwidget.h" #include "baseconfigwidget.h" #include "colorpickerwidget.h" #include "objectsscene.h" #include "databasemodel.h" #include class AppearanceConfigWidget: public BaseConfigWidget, public Ui::AppearanceConfigWidget { private: Q_OBJECT static map config_params; //! \brief Auxiliary class that stores the formating data of each element class AppearanceConfigItem { public: QString conf_id; QTextCharFormat font_fmt; QColor colors[3]; bool obj_conf; }; RoundedRectItem *placeholder; ColorPickerWidget *color_picker; //! \brief Color picker dialog QColorDialog color_dlg; //! \brief Viewport used to show the example model QGraphicsView *viewp; //! \brief Object scene used to store the graphical objects ObjectsScene *scene; //! \brief Database model used to store the example base objects DatabaseModel *model; //! \brief Stores the element configuration items vector conf_items; //! \brief Loads the example model from file (conf/exampledb.dbm) void loadExampleModel(void); //! \brief Updates the color configuration for the placeholder item void updatePlaceholderItem(void); public: AppearanceConfigWidget(QWidget * parent = nullptr); ~AppearanceConfigWidget(void); void saveConfiguration(void); void loadConfiguration(void); static map getConfigurationParams(void); private slots: void enableConfigElement(void); void applyFontStyle(void); void applyElementColor(unsigned color_idx, QColor color); /*! \brief Disabled method */ void applyConfiguration(void){} public slots: void restoreDefaults(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/baseconfigwidget.cpp000066400000000000000000000160411360462764600234610ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baseconfigwidget.h" #include "messagebox.h" BaseConfigWidget::BaseConfigWidget(QWidget *parent) : QWidget(parent) { config_changed=false; } void BaseConfigWidget::addConfigurationParam(map &config_params, const QString ¶m, const attribs_map &attribs) { if(!param.isEmpty() && !attribs.empty()) config_params[param]=attribs; } void BaseConfigWidget::showEvent(QShowEvent *) { config_changed=false; } void BaseConfigWidget::setConfigurationChanged(bool changed) { config_changed=changed; } bool BaseConfigWidget::isConfigurationChanged(void) { return(config_changed); } void BaseConfigWidget::saveConfiguration(const QString &conf_id, map &config_params) { QByteArray buf; //Configures the schema filename for the configuration QString sch_filename=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + conf_id + GlobalAttributes::SchemaExt, //Cofnigures the filename for the configuration file cfg_filename=GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + conf_id + GlobalAttributes::ConfigurationExt; QFile output(cfg_filename); attribs_map attribs; map::iterator itr, itr_end; try { itr=config_params.begin(); itr_end=config_params.end(); while(itr!=itr_end) { attribs.insert((itr->second).begin(), (itr->second).end()); itr++; } //Generates the configuration from the schema file schparser.ignoreEmptyAttributes(true); buf.append(schparser.convertCharsToXMLEntities(schparser.getCodeDefinition(sch_filename, attribs))); output.open(QFile::WriteOnly); if(!output.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(cfg_filename), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Writes the generated configuration to the output file output.write(buf.data(), buf.size()); output.close(); config_params.erase(conf_id); } catch(Exception &e) { if(output.isOpen()) output.close(); throw Exception(Exception::getErrorMessage(ErrorCode::FileNotWrittenInvalidDefinition).arg(cfg_filename), ErrorCode::FileNotWrittenInvalidDefinition,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void BaseConfigWidget::restoreDefaults(const QString &conf_id, bool silent) { QString current_file, default_file; //Build the path to the current configuration (conf/[conf_id].conf current_file=GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + conf_id + GlobalAttributes::ConfigurationExt; //Build the path to the default configuration file (conf/defaults/[conf_id].conf default_file=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::DefaultConfsDir+ GlobalAttributes::DirSeparator + conf_id + GlobalAttributes::ConfigurationExt; //Raises an error if the default file doesn't exists if(!QFile::exists(default_file)) throw Exception(Exception::getErrorMessage(ErrorCode::DefaultConfigNotRestored).arg(default_file), ErrorCode::DefaultConfigNotRestored,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { bool bkp_saved = false; QFileInfo fi(current_file); QDir dir; QString bkp_dir = fi.absolutePath() + GlobalAttributes::DirSeparator + GlobalAttributes::ConfsBackupsDir, bkp_filename = bkp_dir + GlobalAttributes::DirSeparator + QString("%1.bkp_%2").arg(fi.fileName()).arg(QDateTime::currentDateTime().toString("yyyyMMd_hhmmss")); dir.mkpath(bkp_dir); bkp_saved = QFile::rename(current_file, bkp_filename); QFile::copy(default_file, current_file); if(bkp_saved && !silent) { Messagebox msg_box; msg_box.show(trUtf8("A backup of the previous settings was saved into %1!").arg(bkp_filename), Messagebox::InfoIcon); } } } void BaseConfigWidget::loadConfiguration(const QString &conf_id, map &config_params, const vector &key_attribs) { QString filename; try { filename = GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + conf_id + GlobalAttributes::ConfigurationExt; config_params.clear(); xmlparser.restartParser(); xmlparser.setDTDFile(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectDTDDir + GlobalAttributes::DirSeparator + conf_id + GlobalAttributes::ObjectDTDExt, conf_id); xmlparser.loadXMLFile(filename); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { this->getConfigurationParams(config_params, key_attribs); if(xmlparser.hasElement(XmlParser::ChildElement, XML_ELEMENT_NODE)) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); if(xmlparser.getElementType()!=XML_TEXT_NODE) { do { this->getConfigurationParams(config_params, key_attribs); } while(xmlparser.accessElement(XmlParser::NextElement)); } xmlparser.restorePosition(); } } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, filename); } } void BaseConfigWidget::getConfigurationParams(map &config_params, const vector &key_attribs) { attribs_map aux_attribs; attribs_map::iterator itr, itr_end; QString key; xmlparser.getElementAttributes(aux_attribs); itr=aux_attribs.begin(); itr_end=aux_attribs.end(); while(itr!=itr_end && key.isEmpty()) { if(key.isEmpty() && std::find(key_attribs.begin(), key_attribs.end(), itr->first)!=key_attribs.end()) key=itr->second; itr++; } if(key.isEmpty()) key=xmlparser.getElementName(); //Extract the contents of the child element and create a special element on map called "_contents_" if(xmlparser.hasElement(XmlParser::ChildElement, XML_TEXT_NODE)) { xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); aux_attribs[Attributes::Contents]=xmlparser.getElementContent(); xmlparser.restorePosition(); } if(!aux_attribs.empty()) config_params[key]=aux_attribs; } pgmodeler-0.9.2/libpgmodeler_ui/src/baseconfigwidget.h000066400000000000000000000065261360462764600231350ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class BaseConfigWidget \brief Implements base operations to load/save XML based configuration files. This class reunites basic methods to perform the load and save operation. Each subclass must satisfy the contract (implement abstract methods) and have their own static configuration parameter set as following: map */ #ifndef BASE_CONF_WIDGET_H #define BASE_CONF_WIDGET_H #include "exception.h" #include "xmlparser.h" #include "attributes.h" #include #include class BaseConfigWidget: public QWidget { private: Q_OBJECT bool config_changed; protected: XmlParser xmlparser; SchemaParser schparser; /*! \brief Saves the configuration params on file. The conf_id param indicates the type of configuration to be saved. (see GlobalAttributes::*_CONF) and config_params the map containing the configuration values */ void saveConfiguration(const QString &conf_id, map &config_params); /*! \brief Loads a configuration from file. The vector key_attribs is used to specify the xml element name considered as a key on the configuration map */ void loadConfiguration(const QString &conf_id, map &config_params, const vector &key_attribs=vector()); //! \brief Get a configuratoin key from the xml parser void getConfigurationParams(map &config_params, const vector &key_attribs); /*! \brief Restore the configuration specified by conf_in loading them from the original file (conf/defaults) * The silent parameter indicates that the restoration should not emit a message box informing the restoration sucess */ void restoreDefaults(const QString &conf_id, bool silent); //! \brief Adds a parameter to the specified configuration parameters set static void addConfigurationParam(map &config_params, const QString ¶m, const attribs_map &attribs); void showEvent(QShowEvent *); public: BaseConfigWidget(QWidget *parent = nullptr); ~BaseConfigWidget(void){} bool isConfigurationChanged(void); //! \brief Applies the configuration to object virtual void applyConfiguration(void)=0; //! \brief Loads a set of configurations from a file virtual void loadConfiguration(void)=0; //! \brief Saves the current settings to a file virtual void saveConfiguration(void)=0; //! \brief Destroy the current configuration file and makes a copy of the default one located at conf/defaults virtual void restoreDefaults(void)=0; public slots: void setConfigurationChanged(bool changed=true); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/baseform.cpp000066400000000000000000000112451360462764600217540ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baseform.h" BaseForm::BaseForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); this->setWindowFlags((this->windowFlags() | Qt::WindowMinMaxButtonsHint) ^ Qt::WindowContextHelpButtonHint); } void BaseForm::setButtonConfiguration(unsigned button_conf) { if(button_conf==Messagebox::OkCancelButtons) { apply_ok_btn->setText(trUtf8("&Apply")); cancel_btn->setVisible(true); } else { apply_ok_btn->setText(trUtf8("&Ok")); cancel_btn->setVisible(false); } } void BaseForm::resizeForm(QWidget *widget) { QVBoxLayout *vbox=new QVBoxLayout; QSize min_size=widget->minimumSize(); int max_h = 0, max_w = 0, curr_w =0, curr_h = 0, screen_id = qApp->desktop()->screenNumber(qApp->activeWindow()); QScreen *screen=qApp->screens().at(screen_id); double dpi_factor = 0; double pixel_ratio = 0; max_w = screen->size().width() * 0.70; max_h = screen->size().height() * 0.70; dpi_factor = screen->logicalDotsPerInch() / 96.0; pixel_ratio = screen->devicePixelRatio(); if(dpi_factor <= 1.01) dpi_factor = 1.0; vbox->setContentsMargins(2,2,2,2); /* If the widget's minimum size is zero then we need to do a size adjustment on the widget prior to insert it into the dialog */ if(min_size.height() <= 0 || min_size.width() <= 0) { widget->adjustSize(); min_size=widget->size(); } //Insert the widget into a scroll area if it's minimum size exceeds the 70% of screen's dimensions if(max_w < min_size.width() || max_h < min_size.height()) { QScrollArea *scrollarea=nullptr; scrollarea=new QScrollArea(main_frm); scrollarea->setFrameShape(QFrame::NoFrame); scrollarea->setFrameShadow(QFrame::Plain); scrollarea->setWidget(widget); scrollarea->setWidgetResizable(true); widget->setParent(scrollarea); vbox->addWidget(scrollarea); } else { vbox->addWidget(widget); widget->setParent(main_frm); } main_frm->setLayout(vbox); this->adjustSize(); curr_h=this->height(); curr_w=min_size.width(); // If the current height is greater than the widget's minimum height we will use a medium value if(curr_h > min_size.height() && min_size.height() < max_h) curr_h = (curr_h + min_size.height())/2.5; //Using the maximum height if the widget's minimum height exceeds the maximum allowed else if(min_size.height() >= max_h) curr_h = max_h; curr_w += (vbox->contentsMargins().left() + vbox->contentsMargins().right()) * 6; curr_h += baselogo_lbl->minimumHeight() + ((buttons_lt->contentsMargins().top() + buttons_lt->contentsMargins().bottom()) * 6); curr_w *= dpi_factor * pixel_ratio; curr_h *= dpi_factor * pixel_ratio; if(curr_w > screen->size().width()) curr_w = screen->size().width() * 0.80; if(curr_h > screen->size().height()) curr_h = screen->size().height() * 0.80; this->setMinimumSize(min_size); this->resize(curr_w, curr_h); this->adjustSize(); } void BaseForm::closeEvent(QCloseEvent *) { this->reject(); } void BaseForm::setMainWidget(BaseObjectWidget *widget) { if(!widget) return; if(widget->getHandledObjectType()!=ObjectType::BaseObject && widget->windowTitle().isEmpty()) setWindowTitle(trUtf8("%1 properties").arg(BaseObject::getTypeName(widget->getHandledObjectType()))); else setWindowTitle(widget->windowTitle()); apply_ok_btn->setDisabled(widget->isHandledObjectProtected()); resizeForm(widget); setButtonConfiguration(Messagebox::OkCancelButtons); connect(cancel_btn, SIGNAL(clicked(bool)), widget, SLOT(cancelConfiguration())); connect(cancel_btn, SIGNAL(clicked(bool)), this, SLOT(reject())); connect(apply_ok_btn, SIGNAL(clicked(bool)), widget, SLOT(applyConfiguration())); connect(widget, SIGNAL(s_closeRequested()), this, SLOT(accept())); } void BaseForm::setMainWidget(QWidget *widget) { if(!widget) return; setWindowTitle(widget->windowTitle()); resizeForm(widget); setButtonConfiguration(Messagebox::OkButton); connect(cancel_btn, SIGNAL(clicked(bool)), this, SLOT(reject())); connect(apply_ok_btn, SIGNAL(clicked(bool)), this, SLOT(accept())); } pgmodeler-0.9.2/libpgmodeler_ui/src/baseform.h000066400000000000000000000044251360462764600214230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class BaseForm \brief A basic form implementation, contains only an apply and a cancel button. */ #ifndef BASE_FORM_H #define BASE_FORM_H #include #include "ui_baseform.h" #include "exception.h" #include "messagebox.h" #include "baseobjectwidget.h" class BaseForm: public QDialog, public Ui::BaseForm { private: Q_OBJECT /*! \brief Resizes the dialog according to the minimum sizes of the provided widget. If the widget size exceed 70% of the screen size a scroll area will be created and the widget reparented to it. If the minimum size of the widget is 0 then the size is automatically calculated (no so precise). This method acts only in height and try to preserve the minimum width */ void resizeForm(QWidget *widget); void closeEvent(QCloseEvent *); public: BaseForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); void setButtonConfiguration(unsigned button_conf=Messagebox::OkCancelButtons); /*! \brief Injects the specified object into the form and turns it the main widget. The widget is reparented to the stack widget within the form */ void setMainWidget(QWidget *widget); /*! \brief Injects the specified object into the form and turns it the main widget. The widget is reparented to the stack widget within the form. This version of method does additional configurations like signal connection, automatic sizing and custom title configuration based upont the object handled by the BaseObjectWidget instance */ void setMainWidget(BaseObjectWidget *widget); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/baseobjectwidget.cpp000066400000000000000000000747151360462764600234760ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baseobjectwidget.h" #include "permissionwidget.h" #include "customsqlwidget.h" #include "baseform.h" #include "generalconfigwidget.h" const QColor BaseObjectWidget::ProtRowBgColor=QColor(255,180,180); const QColor BaseObjectWidget::ProtRowFgColor=QColor(80,80,80); const QColor BaseObjectWidget::RelAddedRowBgColor=QColor(164,249,176); const QColor BaseObjectWidget::RelAddedRowFgColor=QColor(80,80,80); BaseObjectWidget::BaseObjectWidget(QWidget *parent, ObjectType obj_type): QWidget(parent) { try { QSpacerItem *spacer=nullptr; setWindowTitle(QString()); setupUi(this); handled_obj_type=obj_type; operation_count=0; new_object=false; model=nullptr; table=nullptr; relationship=nullptr; prev_schema=nullptr; op_list=nullptr; object=nullptr; object_px=DNaN; object_py=DNaN; schema_sel=nullptr; owner_sel=nullptr; tablespace_sel=nullptr; object_protected = false; PgModelerUiNs::configureWidgetFont(protected_obj_lbl, PgModelerUiNs::MediumFontFactor); connect(edt_perms_tb, SIGNAL(clicked(bool)),this, SLOT(editPermissions(void))); connect(append_sql_tb, SIGNAL(clicked(bool)),this, SLOT(editCustomSQL(void))); schema_sel=new ObjectSelectorWidget(ObjectType::Schema, true, this); collation_sel=new ObjectSelectorWidget(ObjectType::Collation, true, this); tablespace_sel=new ObjectSelectorWidget(ObjectType::Tablespace, true, this); owner_sel=new ObjectSelectorWidget(ObjectType::Role, true, this); alias_ht=new HintTextWidget(alias_hint, this); alias_ht->setText(alias_edt->statusTip()); baseobject_grid = new QGridLayout; baseobject_grid->setObjectName("objetobase_grid"); baseobject_grid->addWidget(protected_obj_frm, 0, 0, 1, 0); baseobject_grid->addWidget(name_lbl, 1, 0, 1, 1); baseobject_grid->addWidget(name_edt, 1, 1, 1, 1); baseobject_grid->addWidget(id_ico_wgt, 1, 2, 1, 3); baseobject_grid->addWidget(logical_name_lbl, 2, 0, 1, 1); baseobject_grid->addWidget(alias_edt, 2, 1, 1, 1); baseobject_grid->addWidget(alias_hint_wgt, 2, 2, 1, 3); baseobject_grid->addWidget(schema_lbl, 4, 0, 1, 1); baseobject_grid->addWidget(schema_sel, 4, 1, 1, 4); baseobject_grid->addWidget(collation_lbl, 5, 0, 1, 1); baseobject_grid->addWidget(collation_sel, 5, 1, 1, 4); baseobject_grid->addWidget(tablespace_lbl, 6, 0, 1, 1); baseobject_grid->addWidget(tablespace_sel, 6, 1, 1, 4); baseobject_grid->addWidget(owner_lbl, 7, 0, 1, 1); baseobject_grid->addWidget(owner_sel, 7, 1, 1, 4); baseobject_grid->addWidget(comment_lbl, 8, 0, 1, 1); baseobject_grid->addWidget(comment_edt, 8, 1, 1, 4); misc_btns_lt=new QHBoxLayout; spacer=new QSpacerItem(20,1,QSizePolicy::Expanding); misc_btns_lt->addItem(spacer); misc_btns_lt->addWidget(append_sql_tb); misc_btns_lt->addWidget(edt_perms_tb); misc_btns_lt->addWidget(disable_sql_chk); baseobject_grid->addLayout(misc_btns_lt,9,0,1,5); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } BaseObjectWidget::~BaseObjectWidget(void) { } bool BaseObjectWidget::eventFilter(QObject *object, QEvent *event) { //Filters the ENTER/RETURN pressing forcing the parent form activate the "Apply" button if(event->type() == QEvent::KeyPress) { QKeyEvent *kevent=dynamic_cast(event); if(kevent->key()==Qt::Key_Return || kevent->key()==Qt::Key_Enter) { applyConfiguration(); return(true); } } return(QWidget::eventFilter(object, event)); } ObjectType BaseObjectWidget::getHandledObjectType(void) { return(handled_obj_type); } bool BaseObjectWidget::isHandledObjectProtected(void) { return(object_protected); } void BaseObjectWidget::showEvent(QShowEvent *) { name_edt->setFocus(); } void BaseObjectWidget::setRequiredField(QWidget *widget) { if(widget) { QLabel *lbl=qobject_cast(widget); QLineEdit *edt=qobject_cast(widget); QTextEdit *txt=qobject_cast(widget); QGroupBox *grp=qobject_cast(widget); ObjectSelectorWidget *sel=dynamic_cast(widget); PgSQLTypeWidget *pgtype=dynamic_cast(widget); QString str_aux=QString(" * "); QColor bgcolor=QColor(QString("#ffffc0")); if(lbl || pgtype || grp) { if(lbl) lbl->setText(str_aux + lbl->text()); if(!grp) widget->setStyleSheet(QString("QWidget { font-weight: bold; }")); else grp->setStyleSheet(QString("QGroupBox { font-weight: bold; }")); } else if(edt || txt || sel) { if(sel) { widget=sel->obj_name_txt; widget->setStyleSheet(QString("ObjectSelectorWidget > QPlainTextEdit { background-color: %1; }").arg(bgcolor.name())); } else { QPalette pal; pal.setColor(QPalette::Base, bgcolor); pal.setColor(QPalette::Text, QColor(0,0,0)); widget->setPalette(pal); } } str_aux=(!widget->toolTip().isEmpty() ? QString("\n") : QString()); widget->setToolTip(widget->toolTip() + str_aux + trUtf8("Required field. Leaving this empty will raise errors!")); } } void BaseObjectWidget::setAttributes(DatabaseModel *model, BaseObject *object, BaseObject *parent_obj) { setAttributes(model, nullptr, object, parent_obj, DNaN, DNaN, false); } void BaseObjectWidget::disableReferencesSQL(BaseObject *object) { vector refs; TableObject *tab_obj=nullptr; model->getObjectReferences(object, refs); while(!refs.empty()) { tab_obj=dynamic_cast(refs.back()); //If the object is a relationship added does not do anything since the relationship itself will be disabled if(!tab_obj || (tab_obj && !tab_obj->isAddedByRelationship())) { refs.back()->setSQLDisabled(disable_sql_chk->isChecked()); //Update the parent table graphical representation to show the disabled child object if(tab_obj) tab_obj->getParentTable()->setModified(true); //Disable the references of the current object too disableReferencesSQL(refs.back()); } refs.pop_back(); } } void BaseObjectWidget::configureTabOrder(vector widgets) { ObjectSelectorWidget *obj_sel=nullptr; PgSQLTypeWidget *type_wgt=nullptr; vector children, tab_order; int idx=0, cnt=0; widgets.insert(widgets.begin(), { name_edt, alias_edt, alias_ht, schema_sel , collation_sel, owner_sel, tablespace_sel, comment_edt, append_sql_tb, edt_perms_tb, disable_sql_chk }); for(auto &wgt : widgets) { wgt->setFocusPolicy(Qt::StrongFocus); obj_sel=dynamic_cast(wgt); type_wgt=dynamic_cast(wgt); if(obj_sel) children={ obj_sel->rem_object_tb, obj_sel->sel_object_tb }; else if(type_wgt) { children={ type_wgt->type_cmb, type_wgt->length_sb, type_wgt->precision_sb, type_wgt->dimension_sb, type_wgt->interval_cmb, type_wgt->spatial_cmb, type_wgt->srid_spb, type_wgt->var_z_chk, type_wgt->var_m_chk, type_wgt->timezone_chk }; } tab_order.push_back(wgt); for(auto &child : children) { child->setFocusPolicy(Qt::StrongFocus); tab_order.push_back(child); } } cnt=tab_order.size()-1; for(idx=0; idx < cnt; idx++) QWidget::setTabOrder(tab_order[idx], tab_order[idx+1]); } BaseObject *BaseObjectWidget::getHandledObject(void) { return(object); } void BaseObjectWidget::cancelChainedOperation(void) { bool op_list_changed=false; if(op_list->isOperationChainStarted()) op_list->finishOperationChain(); if(operation_count < op_list->getCurrentSize()) { op_list_changed=true; BaseObjectWidget::cancelConfiguration(); } if(new_object && this->object) { if(!op_list_changed) delete(this->object); this->object=nullptr; } } void BaseObjectWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *object, BaseObject *parent_obj, double obj_px, double obj_py, bool uses_op_list) { ObjectType obj_type, parent_type=ObjectType::BaseObject; /* Reseting the objects attributes in order to force them to be redefined every time this method is called */ this->object=nullptr; this->model=nullptr; this->op_list=nullptr; this->relationship=nullptr; this->table=nullptr; if(!model || (uses_op_list && !op_list)) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(op_list) operation_count = op_list->getCurrentSize(); this->model=model; if(parent_obj) { parent_type=parent_obj->getObjectType(); if(BaseTable::isBaseTable(parent_type)) this->table=dynamic_cast(parent_obj); else if(parent_type==ObjectType::Relationship) this->relationship=dynamic_cast(parent_obj); else if(parent_type!=ObjectType::Database && parent_type!=ObjectType::Schema) throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { TableObject *tab_obj=dynamic_cast(object); if(object && object->getSchema()) parent_obj=object->getSchema(); else if(tab_obj && tab_obj->getParentTable()) parent_obj=tab_obj->getParentTable(); else parent_obj=model; } if(dynamic_cast(object)) dynamic_cast(object)->setModified(false); this->op_list=op_list; this->object=object; if(this->table) { this->object_px=this->table->getPosition().x(); this->object_py=this->table->getPosition().y(); } else { this->object_px=obj_px; this->object_py=obj_py; } name_edt->setFocus(); edt_perms_tb->setEnabled(object!=nullptr && !new_object); append_sql_tb->setEnabled(object!=nullptr && !new_object); owner_sel->setModel(model); owner_sel->setSelectedObject(model->getDefaultObject(ObjectType::Role)); schema_sel->setModel(model); schema_sel->setSelectedObject(model->getDefaultObject(ObjectType::Schema)); tablespace_sel->setModel(model); tablespace_sel->setSelectedObject(model->getDefaultObject(ObjectType::Tablespace)); collation_sel->setModel(model); collation_sel->setSelectedObject(model->getDefaultObject(ObjectType::Collation)); if(object) { obj_id_lbl->setVisible(true); obj_id_lbl->setText(QString("ID: %1").arg(object->getObjectId())); if(handled_obj_type != ObjectType::BaseObject) name_edt->setText(object->getName()); else name_edt->setText(object->getSignature()); comment_edt->setPlainText(object->getComment()); alias_edt->setText(object->getAlias()); /* When creating a new table or relationship the object is pre allocated and the flag new_object is set. In order to avoid the selectors to have empty values, we check if the flag is false which means that the object is not new at all */ if(!new_object) { schema_sel->setSelectedObject(object->getSchema()); tablespace_sel->setSelectedObject(object->getTablespace()); owner_sel->setSelectedObject(object->getOwner()); collation_sel->setSelectedObject(object->getCollation()); } /* Some objects like tables and views came with a pre selected schema even when they are new objects. So we need to show this selected schema instead of the default one */ else if(new_object && object->getSchema()) schema_sel->setSelectedObject(object->getSchema()); obj_type=object->getObjectType(); object_protected=(parent_type!=ObjectType::Relationship && (object->isProtected() || ((obj_type==ObjectType::Column || obj_type==ObjectType::Constraint) && dynamic_cast(object)->isAddedByRelationship()))); protected_obj_frm->setVisible(object_protected); disable_sql_chk->setChecked(object->isSQLDisabled()); } else { object_protected = false; obj_id_lbl->setVisible(false); protected_obj_frm->setVisible(false); if(parent_obj && parent_obj->getObjectType()==ObjectType::Schema) schema_sel->setSelectedObject(parent_obj); } } void BaseObjectWidget::configureFormLayout(QGridLayout *grid, ObjectType obj_type) { bool show_comment; QObjectList chld_list; QWidget *wgt=nullptr; if(grid) { QLayoutItem *item=nullptr; int lin, col, col_span,row_span, item_id, item_count; /* Move all the widgets of the passed grid layout one row down, permiting the insertion of the 'baseobject_grid' at the top of the items */ item_count=grid->count(); for(item_id=item_count-1; item_id >= 0; item_id--) { item=grid->itemAt(item_id); grid->getItemPosition(item_id, &lin, &col, &row_span, &col_span); grid->removeItem(item); grid->addItem(item, lin+1, col, row_span, col_span); /* Configuring QTextEdit to accept tabs as focus changes. This code only applies to widgets directly linked to the layout. If there is some QTextEdit nested in some child widget this is not applied */ if(dynamic_cast(item->widget())) dynamic_cast(item->widget())->setTabChangesFocus(true); } //Adding the base layout on the top grid->addLayout(baseobject_grid, 0,0,1,0); baseobject_grid=grid; } else this->setLayout(baseobject_grid); baseobject_grid->setContentsMargins(4, 4, 4, 4); disable_sql_chk->setVisible(obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::Permission && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::Tag && obj_type!=ObjectType::Parameter); alias_edt->setVisible(BaseObject::acceptsAlias(obj_type)); alias_hint_wgt->setVisible(BaseObject::acceptsAlias(obj_type)); logical_name_lbl->setVisible(BaseObject::acceptsAlias(obj_type)); edt_perms_tb->setVisible(Permission::acceptsPermission(obj_type)); append_sql_tb->setVisible(BaseObject::acceptsCustomSQL(obj_type)); schema_lbl->setVisible(BaseObject::acceptsSchema(obj_type)); schema_sel->setVisible(BaseObject::acceptsSchema(obj_type)); owner_lbl->setVisible(BaseObject::acceptsOwner(obj_type)); owner_sel->setVisible(BaseObject::acceptsOwner(obj_type)); tablespace_lbl->setVisible(BaseObject::acceptsTablespace(obj_type)); tablespace_sel->setVisible(BaseObject::acceptsTablespace(obj_type)); collation_lbl->setVisible(BaseObject::acceptsCollation(obj_type)); collation_sel->setVisible(BaseObject::acceptsCollation(obj_type)); show_comment=obj_type!=ObjectType::Relationship && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::Parameter && obj_type!=ObjectType::UserMapping && obj_type!=ObjectType::Permission; comment_lbl->setVisible(show_comment); comment_edt->setVisible(show_comment); if(obj_type!=ObjectType::BaseObject) { obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(obj_type))); obj_icon_lbl->setToolTip(BaseObject::getTypeName(obj_type)); if(obj_type!=ObjectType::Permission && obj_type!=ObjectType::Cast && obj_type!=ObjectType::UserMapping) { setRequiredField(name_lbl); setRequiredField(name_edt); } else { QFont font=name_edt->font(); name_edt->setReadOnly(true); font.setItalic(true); name_edt->setFont(font); } if(obj_type!=ObjectType::Extension) { setRequiredField(schema_lbl); setRequiredField(schema_sel); } } if(BaseObject::acceptsCollation(obj_type)) { QFrame *frame=nullptr; map > fields_map; fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion91)].push_back(collation_lbl); frame=generateVersionWarningFrame(fields_map); baseobject_grid->addWidget(frame, baseobject_grid->count()+1, 0, 1, 0); frame->setParent(this); } //Install the event filter into all children object in order to capture key press chld_list=this->children(); while(!chld_list.isEmpty()) { wgt=dynamic_cast(chld_list.front()); //Avoids install event filters in objects that are inteneded to edit multiple lines if(wgt && wgt->metaObject()->className()!=QString("QPlainTextEdit") && wgt->metaObject()->className()!=QString("NumberedTextEditor")) wgt->installEventFilter(this); chld_list.pop_front(); } } QString BaseObjectWidget::generateVersionsInterval(unsigned ver_interv_id, const QString &ini_ver, const QString &end_ver) { if(ver_interv_id==UntilVersion && !ini_ver.isEmpty()) return(XmlParser::CharLt + QString("= ") + ini_ver); else if(ver_interv_id==VersionsInterval && !ini_ver.isEmpty() && !end_ver.isEmpty()) return(XmlParser::CharGt + QString("= ") + ini_ver + XmlParser::CharAmp + XmlParser::CharLt + QString("= ") + end_ver); else if(ver_interv_id==AfterVersion && !ini_ver.isEmpty()) return(XmlParser::CharGt + QString("= ") + ini_ver); else return(QString()); } QFrame *BaseObjectWidget::generateInformationFrame(const QString &msg) { QFrame *info_frm=nullptr; QGridLayout *grid=nullptr; QLabel *ico_lbl=nullptr, *msg_lbl=nullptr; QFont font; info_frm = new QFrame; font.setItalic(false); font.setBold(false); info_frm->setFont(font); PgModelerUiNs::configureWidgetFont(info_frm, PgModelerUiNs::MediumFontFactor); info_frm->setObjectName("info_frm"); info_frm->setFrameShape(QFrame::StyledPanel); info_frm->setFrameShadow(QFrame::Raised); info_frm->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); grid = new QGridLayout(info_frm); grid->setContentsMargins(4, 4, 4, 4); grid->setObjectName("grid"); ico_lbl = new QLabel(info_frm); ico_lbl->setObjectName("icone_lbl"); ico_lbl->setMinimumSize(QSize(24, 24)); ico_lbl->setMaximumSize(QSize(24, 24)); ico_lbl->setScaledContents(true); ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); ico_lbl->setAlignment(Qt::AlignLeft|Qt::AlignTop); grid->addWidget(ico_lbl, 0, 0, 1, 1); msg_lbl = new QLabel(info_frm); msg_lbl->setFont(font); msg_lbl->setObjectName("message_lbl"); msg_lbl->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); msg_lbl->setWordWrap(true); msg_lbl->setText(msg); grid->addWidget(msg_lbl, 0, 1, 1, 1); grid->setContentsMargins(4,4,4,4); return(info_frm); } void BaseObjectWidget::highlightVersionSpecificFields(map > &fields, map< QWidget *, vector > *values) { QString field_name; QColor color=QColor(0,0,128); for(auto itr : fields) { for(auto wgt : itr.second) { if(values && values->count(wgt) > 0) { field_name+=QString("
") + trUtf8("Value(s)") + QString(": ("); for(auto value : values->at(wgt)) { field_name += value; field_name+=", "; } field_name.remove(field_name.length() - 2, 2); field_name+=")"; } wgt->setStyleSheet(QString("QWidget { font-weight: bold; font-style: italic; color: %1}").arg(color.name())); wgt->setToolTip(QString("") + trUtf8("Version ") + itr.first + QString(" %1").arg(field_name)); } } } QFrame *BaseObjectWidget::generateVersionWarningFrame(map > &fields, map< QWidget *, vector > *values) { QFrame *alert_frm=nullptr; QGridLayout *grid=nullptr; QLabel *ico_lbl=nullptr, *msg_lbl=nullptr; QFont font; QColor color=QColor(0,0,128); highlightVersionSpecificFields(fields, values); alert_frm = new QFrame; font.setItalic(false); font.setBold(false); PgModelerUiNs::configureWidgetFont(alert_frm, PgModelerUiNs::MediumFontFactor); alert_frm->setObjectName("alerta_frm"); alert_frm->setFrameShape(QFrame::StyledPanel); alert_frm->setFrameShadow(QFrame::Raised); alert_frm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); grid = new QGridLayout(alert_frm); grid->setObjectName("grid"); ico_lbl = new QLabel(alert_frm); ico_lbl->setObjectName("icone_lbl"); ico_lbl->setMinimumSize(QSize(24, 24)); ico_lbl->setMaximumSize(QSize(24, 24)); ico_lbl->setScaledContents(true); ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); ico_lbl->setAlignment(Qt::AlignLeft|Qt::AlignTop); grid->addWidget(ico_lbl, 0, 0, 1, 1); msg_lbl = new QLabel(alert_frm); msg_lbl->setFont(font); msg_lbl->setObjectName("mensagelm_lb"); msg_lbl->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); msg_lbl->setWordWrap(true); msg_lbl->setText(trUtf8("The highlighted fields in the form or one of their values are available only on specific PostgreSQL versions. \ Generating SQL code for versions other than those specified in the fields' tooltips may create incompatible code.").arg(color.name())); grid->addWidget(msg_lbl, 0, 1, 1, 1); grid->setContentsMargins(4,4,4,4); alert_frm->adjustSize(); return(alert_frm); } void BaseObjectWidget::editPermissions(void) { BaseObject *parent_obj=nullptr; BaseForm parent_form(this); PermissionWidget *permission_wgt=new PermissionWidget; if(this->relationship) parent_obj=this->relationship; permission_wgt->setAttributes(this->model, parent_obj, this->object); parent_form.setMainWidget(permission_wgt); parent_form.setButtonConfiguration(Messagebox::OkButton); GeneralConfigWidget::restoreWidgetGeometry(&parent_form, permission_wgt->metaObject()->className()); parent_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&parent_form, permission_wgt->metaObject()->className()); } void BaseObjectWidget::editCustomSQL(void) { BaseForm parent_form(this); CustomSQLWidget *customsql_wgt=new CustomSQLWidget; customsql_wgt->setAttributes(this->model, this->object); parent_form.setMainWidget(customsql_wgt); GeneralConfigWidget::restoreWidgetGeometry(&parent_form, customsql_wgt->metaObject()->className()); parent_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&parent_form, customsql_wgt->metaObject()->className()); } void BaseObjectWidget::applyConfiguration(void) { if(object) { try { BaseObject *aux_obj=nullptr, *aux_obj1=nullptr, *parent_obj=nullptr; bool new_obj; ObjectType obj_type=object->getObjectType(); QString obj_name; QApplication::setOverrideCursor(Qt::WaitCursor); obj_name=BaseObject::formatName(name_edt->text().toUtf8(), obj_type==ObjectType::Operator); if(this->object->acceptsSchema() && schema_sel->getSelectedObject()) obj_name=schema_sel->getSelectedObject()->getName(true) + "." + obj_name; //Checking the object duplicity if(obj_type!=ObjectType::Database && obj_type!=ObjectType::Permission && obj_type!=ObjectType::Parameter) { if(table) { //Validationg the object against the siblings on parent table parent_obj=table; aux_obj=table->getObject(obj_name,obj_type); aux_obj1=table->getObject(object->getName(),obj_type); new_obj=(!aux_obj && !aux_obj1); } else if(relationship) { //Validationg the object against the siblings on parent relationship parent_obj=relationship; aux_obj=relationship->getObject(obj_name,obj_type); aux_obj1=relationship->getObject(object->getName(),obj_type); new_obj=(!aux_obj && !aux_obj1); } //Validationg the object against the other objects on model else { parent_obj=model; aux_obj=model->getObject(obj_name,obj_type); /* Special case for tables and views. Its necessary to make an additional checking on table list when the configured object is a view or a checking on view list when the configured object is a table, this because PostgreSQL does not accepts tables and views have the same name on the same schema */ aux_obj = model->getObject(obj_name, { ObjectType::Table, ObjectType::ForeignTable, ObjectType::View }); new_obj = (aux_obj == nullptr); } //Raises an error if another object is found with the same name as the editing object if(!new_obj && aux_obj && aux_obj!=object) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(obj_name) .arg(BaseObject::getTypeName(obj_type)) .arg(parent_obj->getName(true)) .arg(parent_obj->getTypeName()), ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } //Renames the object (only cast object aren't renamed) if(obj_type!=ObjectType::Cast) { prev_name=object->getName(); object->setName(name_edt->text().trimmed().toUtf8()); } if(alias_edt->isVisible()) object->setAlias(alias_edt->text().trimmed()); //Sets the object's comment if(comment_edt->isVisible()) object->setComment(comment_edt->toPlainText().toUtf8()); //Sets the object's tablespace if(tablespace_sel->isVisible()) object->setTablespace(tablespace_sel->getSelectedObject()); //Sets the object's owner if(owner_sel->isVisible()) object->setOwner(owner_sel->getSelectedObject()); //Sets the object's collation if(collation_sel->isVisible()) object->setCollation(collation_sel->getSelectedObject()); //Sets the object's schema if(schema_sel->isVisible()) { Schema *esquema=dynamic_cast(schema_sel->getSelectedObject()); this->prev_schema=dynamic_cast(object->getSchema()); object->setSchema(esquema); } if(!object->isProtected() && !object->isSystemObject()) PgModelerUiNs::disableObjectSQL(object, disable_sql_chk->isChecked()); } catch(Exception &e) { QApplication::restoreOverrideCursor(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void BaseObjectWidget::finishConfiguration(void) { try { if(this->object) { ObjectType obj_type=this->object->getObjectType(); BaseGraphicObject *graph_obj=dynamic_cast(this->object); TableObject *tab_obj=dynamic_cast(this->object); vector ref_objs; if(new_object) { //If the object is a table object and the parent table is specified, adds it to table if(table && TableObject::isTableObject(obj_type)) table->addObject(this->object); //Adding the object on the relationship, if specified else if(relationship && (obj_type==ObjectType::Column || obj_type==ObjectType::Constraint)) relationship->addObject(dynamic_cast(this->object)); //Adding the object on the model else if(obj_type!=ObjectType::Parameter) model->addObject(this->object); registerNewObject(); new_object=false; } else { //If the object is being updated, validates its SQL definition if(obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Textbox || obj_type==ObjectType::Tag) this->object->getCodeDefinition(SchemaParser::XmlDefinition); else this->object->getCodeDefinition(SchemaParser::SqlDefinition); } model->getObjectReferences(object, ref_objs); for(auto &obj : ref_objs) { obj->setCodeInvalidated(true); if(obj->getObjectType()==ObjectType::Column) dynamic_cast(obj)->getParentTable()->setModified(true); } object->setCodeInvalidated(true); //If the object is graphical (or a table object), updates it (or its parent) on the scene if(graph_obj || tab_obj) { if(!graph_obj && tab_obj && tab_obj->getObjectType()!=ObjectType::Parameter) { if(this->table) graph_obj=dynamic_cast(this->table); else graph_obj=dynamic_cast(this->relationship); graph_obj->setModified(true); graph_obj->setCodeInvalidated(true); } else if(graph_obj) { if(!std::isnan(object_px) && !std::isnan(object_py)) graph_obj->setPosition(QPointF(object_px, object_py)); graph_obj->setModified(true); } /* Updates the visual schemas when the objects is moved to another or a table object is added to a table */ if(object->getSchema()) dynamic_cast(object->getSchema())->setModified(true); else if(tab_obj && tab_obj->getParentTable() && tab_obj->getParentTable()->getSchema()) dynamic_cast(tab_obj->getParentTable() ->getSchema())->setModified(true); if(prev_schema && object->getSchema()!=prev_schema) prev_schema->setModified(true); } emit s_objectManipulated(); emit s_closeRequested(); } QApplication::restoreOverrideCursor(); } catch(Exception &e) { QApplication::restoreOverrideCursor(); if(e.getErrorCode()==ErrorCode::AsgObjectInvalidDefinition) throw Exception(Exception::getErrorMessage(ErrorCode::RequiredFieldsNotFilled) .arg(this->object->getName()).arg(this->object->getTypeName()), ErrorCode::RequiredFieldsNotFilled,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void BaseObjectWidget::cancelConfiguration(void) { if(!object) return; ObjectType obj_type; obj_type=this->object->getObjectType(); if(new_object) { TableObject *tab_obj=dynamic_cast(this->object); //Removes the object from its parent if(!table && !tab_obj && model->getObjectIndex(this->object) >= 0) model->removeObject(this->object); else if(table && table->getObjectIndex(tab_obj) >= 0) table->removeObject(tab_obj); else if(relationship && relationship->getObjectIndex(tab_obj) >= 0) relationship->removeObject(tab_obj); if(!BaseTable::isBaseTable(obj_type) && obj_type != ObjectType::Relationship) { if(!op_list->isObjectRegistered(this->object, Operation::ObjectCreated)) delete(this->object); this->object=nullptr; } } //If the object is not a new one, restore its previous state if(op_list && ((!new_object && obj_type!=ObjectType::Database && obj_type!=ObjectType::Permission && operation_count != op_list->getCurrentSize()) || (new_object && (BaseTable::isBaseTable(obj_type) || obj_type==ObjectType::Relationship)))) { try { op_list->undoOperation(); op_list->removeLastOperation(); } catch(Exception &){} } QApplication::restoreOverrideCursor(); emit s_objectManipulated(); } void BaseObjectWidget::registerNewObject(void) { try { if(this->new_object && op_list && !op_list->isObjectRegistered(this->object, Operation::ObjectCreated)) { //If the object is a new one is necessary register it on the operation list if(this->table) op_list->registerObject(this->object, Operation::ObjectCreated, -1, this->table); else if(this->relationship) op_list->registerObject(this->object, Operation::ObjectCreated, -1, this->relationship); else op_list->registerObject(this->object, Operation::ObjectCreated); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/baseobjectwidget.h000066400000000000000000000203261360462764600231300ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class BaseObjectWidget \brief Implements the basic operations to create/edit database objects via form. */ #ifndef BASE_OBJECT_WIDGET_H #define BASE_OBJECT_WIDGET_H #include #include "databasemodel.h" #include "operationlist.h" #include "modelobjectswidget.h" #include "objectselectorwidget.h" #include "ui_baseobjectwidget.h" #include "pgsqltypewidget.h" #include "pgmodeleruins.h" #include "hinttextwidget.h" /* Declaring the PgSQLType class as a Qt metatype in order to permit that instances of the class be used as data of QVariant and QMetaType */ #include Q_DECLARE_METATYPE(PgSqlType) class BaseObjectWidget: public QWidget, public Ui::BaseObjectWidget { private: Q_OBJECT protected: static constexpr int MaxObjectSize=16777215; static const QColor ProtRowBgColor, ProtRowFgColor, RelAddedRowBgColor, RelAddedRowFgColor; bool object_protected; QHBoxLayout *misc_btns_lt; HintTextWidget *alias_ht; //! \brief Store the kind of object being handled by the widget (configured in the constructor) ObjectType handled_obj_type; /*! \brief Operation list element count before editing an object. This attribute is used to know, in case of cancel the edition, the operation (count) that is needed to be removed. This attribute applies only if the object creation is chained (like in tables, views or relationships) See: cancelChainedConfiguration() */ unsigned operation_count; //! \brief Reference database model DatabaseModel *model; //! \brief Reference table/view (used only when editing table objects) BaseTable *table; //! \brief Stores the object previous name (used to validate schema renaming) QString prev_name; //! \brief Store the object previous schema (used to update the schemas when moving tables/views from one to another) Schema *prev_schema; //! \brief Reference relationship (used only when editing relationship attributes) Relationship *relationship; //! \brief Reference operation list where all modifications in the form are registered OperationList *op_list; //! \brief Object that is being edited / created BaseObject *object; /*! \brief Stores the object position (generally the mouse position) when the dialog was called (used only when creating graphical objects) */ double object_px, object_py; //! \brief Grid layout used to organize the widgets over the form QGridLayout *baseobject_grid; //! \brief Indicates if the object is a new one or is being edited bool new_object; //! \brief Object selectors for schema, owner, tablespace and collation ObjectSelectorWidget *schema_sel, *owner_sel, *tablespace_sel, *collation_sel; /*! \brief Merges the specified grid layout with the 'baseobject_grid' creating a single form. The obj_type parameter must be specified to show the object type icon */ void configureFormLayout(QGridLayout *grid=nullptr, ObjectType obj_type=ObjectType::BaseObject); /*! \brief Starts a object configuration, alocating a new one if necessary, registering the object on the operation list. This method doens't applies to database model edition */ template void startConfiguration(void); /*! \brief Finishes the edition / creation of object, registering it on the operation list and inserts is on the parent object */ void finishConfiguration(void); //! \brief Apply the basic configurations to the object (name, schema, comment, owner, tablespace) virtual void applyConfiguration(void); void showEvent(QShowEvent *); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *object, BaseObject *parent_obj=nullptr, double obj_px=DNaN, double obj_py=DNaN, bool uses_op_list=true); /*! \brief This method is a simplification of the original setAttributes. This method must be used only on forms that does not make use of operaton list and not treat graphical objects, since it calls this original one whit the op_list=nullptr and obj_px=DoubleNaN, obj_py=DoubleNaN */ void setAttributes(DatabaseModel *model, BaseObject *object, BaseObject *parent_obj); //! \brief Disable the object's refereces SQL code void disableReferencesSQL(BaseObject *object); void configureTabOrder(vector widgets={}); BaseObject *getHandledObject(void); public: //! \brief Constants used to generate version intervals for version alert frame static constexpr unsigned UntilVersion=0, VersionsInterval=1, AfterVersion=2; BaseObjectWidget(QWidget * parent = nullptr, ObjectType obj_type=ObjectType::BaseObject); virtual ~BaseObjectWidget(void); //! \brief Generates a string containing the specified version interval static QString generateVersionsInterval(unsigned ver_interv_id, const QString &ini_ver, const QString &end_ver=QString()); /*! \brief Generates a alert frame highlighting the fields of exclusive use on the specified PostgreSQL versions. On the first map (fields) the key is the PostgreSQL versions and the values are the reference to the widget. The second map is used to specify the values of widgets specific for each version. */ static QFrame *generateVersionWarningFrame(map > &fields, map > *values=nullptr); //! \brief Generates a informative frame containing the specified message static QFrame *generateInformationFrame(const QString &msg); static void highlightVersionSpecificFields(map > &fields, map > *values=nullptr); //! \brief Highlights the specified widget as a required field static void setRequiredField(QWidget *widget); //! \brief Filters the ENTER/RETURN key press forcing the button "Apply" to be clicked bool eventFilter(QObject *object, QEvent *event); //! \brief Returns the kind of database object handled ObjectType getHandledObjectType(void); virtual bool isHandledObjectProtected(void); protected slots: void editPermissions(void); void editCustomSQL(void); //! \brief Register the new object in the operation history if it is not registered already void registerNewObject(void); /*! \brief Aborts the object configuration, deallocation it if necessary or restoring it to its previous configuration */ virtual void cancelConfiguration(void); //! \brief Executes the proper actions to cancel chained operations. virtual void cancelChainedOperation(void); signals: //! \brief Signal emitted whenever a object is created / edited using the form void s_objectManipulated(void); //! \brief Signal emitted whenever the object editing was successful and the form need to be closed void s_closeRequested(void); friend class BaseForm; friend class ModelWidget; }; template void BaseObjectWidget::startConfiguration(void) { try { Class *new_tmpl_obj=nullptr; //! \brief If the object is already allocated if(this->object && op_list && this->object->getObjectType()!=ObjectType::Database) { if(this->table) op_list->registerObject(this->object, Operation::ObjectModified, -1, this->table); else op_list->registerObject(this->object, Operation::ObjectModified, -1, this->relationship); new_object=false; } //! \brief If there is need to allocate the object else if(!this->object) { new_tmpl_obj=new Class; this->object=new_tmpl_obj; new_object=true; } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } #endif pgmodeler-0.9.2/libpgmodeler_ui/src/bugreportform.cpp000066400000000000000000000122241360462764600230510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "bugreportform.h" #include "exception.h" #include "globalattributes.h" #include "messagebox.h" #include "pgmodeleruins.h" BugReportForm::BugReportForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); PgModelerUiNs::configureWidgetFont(hint_lbl, PgModelerUiNs::MediumFontFactor); connect(cancel_btn, SIGNAL(clicked(void)), this, SLOT(close(void))); connect(create_btn, SIGNAL(clicked(void)), this, SLOT(generateReport(void))); connect(attach_mod_chk, SIGNAL(toggled(bool)), attach_tb, SLOT(setEnabled(bool))); connect(attach_tb, SIGNAL(clicked()), this, SLOT(attachModel())); connect(output_tb, SIGNAL(clicked()), this, SLOT(selectOutput())); connect(actions_txt, SIGNAL(textChanged()), this, SLOT(enableGeneration())); connect(output_edt, SIGNAL(textChanged(QString)), this, SLOT(enableGeneration())); output_edt->setText(QFileInfo(GlobalAttributes::TemporaryDir).absoluteFilePath()); //Installs a syntax highlighter on model_txt widget hl_model_txt=new SyntaxHighlighter(model_txt); hl_model_txt->loadConfiguration(GlobalAttributes::XMLHighlightConfPath); QDir tmp_dir=QDir(GlobalAttributes::TemporaryDir, QString("*.dbm"), QDir::Name, QDir::Files | QDir::NoDotAndDotDot); tmp_dir.setSorting(QDir::Time); QStringList list=tmp_dir.entryList(); if(!list.isEmpty()) { QFile input; //Opens the last modified model file showing it on the proper widget input.setFileName(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + list[0]); input.open(QFile::ReadOnly); model_txt->setPlainText(QString(input.readAll())); input.close(); } } QByteArray BugReportForm::generateReportBuffer(void) { QByteArray buf; buf.append(actions_txt->toPlainText().toUtf8()); buf.append(CharDelimiter); if(attach_mod_chk->isChecked()) buf.append(model_txt->toPlainText().toUtf8()); buf.append(CharDelimiter); return(buf); } void BugReportForm::generateReport(void) { generateReport(generateReportBuffer()); this->accept(); } void BugReportForm::enableGeneration(void) { create_btn->setEnabled(!output_edt->text().isEmpty() && !actions_txt->toPlainText().isEmpty()); } void BugReportForm::generateReport(const QByteArray &buf) { Messagebox msgbox; QFile output; QString filename=QFileInfo(QString(output_edt->text() + GlobalAttributes::DirSeparator + GlobalAttributes::BugReportFile) .arg(QDateTime::currentDateTime().toString(QString("_yyyyMMdd_hhmm")))).absoluteFilePath(); //Opens the file for writting output.setFileName(filename); output.open(QFile::WriteOnly); if(!output.isOpen()) msgbox.show(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(filename), Messagebox::ErrorIcon); else { QByteArray comp_buf; //Compress the buffer (using zlib) in a compression rate at 8 comp_buf=qCompress(buf, 8); //Saves the buffer output.write(comp_buf.data(), comp_buf.size()); output.close(); msgbox.show(trUtf8("Bug report successfuly generated! Please, send the file %1 to %2 in order be analyzed. Thank you for the collaboration!") .arg(QDir::toNativeSeparators(filename)).arg(GlobalAttributes::BugReportEmail), Messagebox::InfoIcon); } } void BugReportForm::attachModel(void) { QFileDialog file_dlg; try { file_dlg.setDefaultSuffix(QString("dbm")); file_dlg.setWindowTitle(trUtf8("Load model")); file_dlg.setNameFilter(trUtf8("Database model (*.dbm);;All files (*.*)")); file_dlg.setFileMode(QFileDialog::AnyFile); file_dlg.setModal(true); if(file_dlg.exec()==QFileDialog::Accepted) { QFile input(file_dlg.selectedFiles().at(0)); QByteArray buf; input.open(QFile::ReadOnly); if(!input.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(file_dlg.selectedFiles().at(0)), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); buf=input.readAll(); model_txt->setPlainText(QString(buf)); input.close(); } } catch(Exception &e) { Messagebox msgbox; msgbox.show(e); } } void BugReportForm::selectOutput(void) { QFileDialog file_dlg; file_dlg.setWindowTitle(trUtf8("Select report output folder")); file_dlg.setFileMode(QFileDialog::DirectoryOnly); file_dlg.setModal(true); if(file_dlg.exec()==QFileDialog::Accepted) output_edt->setText(file_dlg.selectedFiles().at(0)); } pgmodeler-0.9.2/libpgmodeler_ui/src/bugreportform.h000066400000000000000000000035001360462764600225130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class BugReportForm \brief Implements operations to permit user generate bug reports without use the crash handler application. */ #ifndef BUG_REPORT_FORM_H #define BUG_REPORT_FORM_H #include #include "ui_bugreportform.h" #include "syntaxhighlighter.h" class BugReportForm : public QDialog, public Ui::BugReportForm { private: Q_OBJECT //! \brief Syntax highlight for model text widget SyntaxHighlighter *hl_model_txt; protected: //! \brief Delimiter character which separates the sections of the compressed file static constexpr char CharDelimiter = static_cast(3); //! \brief Generates an uncompressed buffer based upon the data in fields virtual QByteArray generateReportBuffer(void); //! \brief Generates the bug report file from uncompressed buffer void generateReport(const QByteArray &buf); public: BugReportForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); public slots: void generateReport(void); private slots: void enableGeneration(void); void attachModel(void); void selectOutput(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/bulkdataeditwidget.cpp000066400000000000000000000016431360462764600240200ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "bulkdataeditwidget.h" BulkDataEditWidget::BulkDataEditWidget(QWidget *parent) : QWidget(parent) { setupUi(this); } void BulkDataEditWidget::showEvent(QShowEvent *) { value_edt->setFocus(); } pgmodeler-0.9.2/libpgmodeler_ui/src/bulkdataeditwidget.h000066400000000000000000000020251360462764600234600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #ifndef BULK_DATA_EDIT_WIDGET_H #define BULK_DATA_EDIT_WIDGET_H #include #include "ui_bulkdataeditwidget.h" class BulkDataEditWidget: public QWidget, public Ui::BulkDataEditWidget { private: Q_OBJECT void showEvent(QShowEvent *); public: BulkDataEditWidget(QWidget *parent = nullptr); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/castwidget.cpp000066400000000000000000000072451360462764600223210ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "castwidget.h" CastWidget::CastWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Cast) { try { QFrame *frame=nullptr; QSpacerItem *spacer=new QSpacerItem(10,1,QSizePolicy::Fixed,QSizePolicy::Expanding); Ui_CastWidget::setupUi(this); src_datatype=new PgSQLTypeWidget(this, trUtf8("Source data type")); trg_datatype=new PgSQLTypeWidget(this, trUtf8("Target data type")); conv_func_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); cast_grid->addWidget(conv_func_sel,1,1,1,4); cast_grid->addWidget(src_datatype,2,0,1,5); cast_grid->addWidget(trg_datatype,3,0,1,5); configureFormLayout(cast_grid, ObjectType::Cast); frame=generateInformationFrame(trUtf8("The function to be assigned to a cast from typeA to typeB must have the following signature: typeB function(typeA, integer, boolean).")); cast_grid->addItem(spacer, cast_grid->count()+1, 0, 1, 0); cast_grid->addWidget(frame, cast_grid->count()+1, 0, 1, 0); frame->setParent(this); setRequiredField(src_datatype); setRequiredField(trg_datatype); configureTabOrder({ explicit_rb, implicit_rb, assignment_rb, input_output_chk, conv_func_sel, src_datatype, trg_datatype }); setMinimumSize(520, 460); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void CastWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Cast *cast) { PgSqlType src_type, trg_type; BaseObjectWidget::setAttributes(model, op_list, cast); conv_func_sel->setModel(model); if(cast) { src_type=cast->getDataType(Cast::SrcType); trg_type=cast->getDataType(Cast::DstType); conv_func_sel->setSelectedObject(cast->getCastFunction()); input_output_chk->setChecked(cast->isInOut()); explicit_rb->setChecked(cast->getCastType()==Cast::Explicit); implicit_rb->setChecked(cast->getCastType()==Cast::Implicit); assignment_rb->setChecked(cast->getCastType()==Cast::Assignment); } src_datatype->setAttributes(src_type,model); trg_datatype->setAttributes(trg_type,model); } void CastWidget::applyConfiguration(void) { try { Cast *cast=nullptr; startConfiguration(); cast=dynamic_cast(this->object); cast->setDataType(Cast::SrcType, src_datatype->getPgSQLType()); cast->setDataType(Cast::DstType, trg_datatype->getPgSQLType()); cast->setInOut(input_output_chk->isChecked()); if(implicit_rb->isChecked()) cast->setCastType(Cast::Implicit); else if(assignment_rb->isChecked()) cast->setCastType(Cast::Assignment); else cast->setCastType(Cast::Explicit); cast->setCastFunction(dynamic_cast(conv_func_sel->getSelectedObject())); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/castwidget.h000066400000000000000000000026331360462764600217620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class CastWidget \brief Implements the operations to create/edit type casts via form. */ #ifndef CAST_WIDGET_H #define CAST_WIDGET_H #include "baseobjectwidget.h" #include "pgsqltypewidget.h" #include "ui_castwidget.h" class CastWidget: public BaseObjectWidget, public Ui::CastWidget { private: Q_OBJECT //! \brief Datatype configurations PgSQLTypeWidget *src_datatype, *trg_datatype; //! \brief Conversion function selector ObjectSelectorWidget *conv_func_sel; public: CastWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Cast *cast); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/codecompletionwidget.cpp000066400000000000000000000460051360462764600243700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "codecompletionwidget.h" #include "generalconfigwidget.h" #include "pgmodeleruins.h" #include "snippetsconfigwidget.h" CodeCompletionWidget::CodeCompletionWidget(QPlainTextEdit *code_field_txt, bool enable_snippets) : QWidget(dynamic_cast(code_field_txt)) { if(!code_field_txt) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->enable_snippets = enable_snippets; popup_timer.setInterval(300); completion_wgt=new QWidget(this); completion_wgt->setWindowFlags(Qt::Popup); name_list=new QListWidget(completion_wgt); name_list->setSpacing(2); name_list->setIconSize(QSize(16,16)); name_list->setSortingEnabled(false); persistent_chk=new QCheckBox(completion_wgt); persistent_chk->setText(trUtf8("Make &persistent")); persistent_chk->setToolTip(trUtf8("Makes the widget closable only by ESC key or mouse click on other controls.")); persistent_chk->setFocusPolicy(Qt::NoFocus); QVBoxLayout *vbox=new QVBoxLayout(completion_wgt); vbox->addWidget(name_list); vbox->addWidget(persistent_chk); vbox->setContentsMargins(4,4,4,4); vbox->setSpacing(6); completion_wgt->setLayout(vbox); PgModelerUiNs::configureWidgetFont(name_list, PgModelerUiNs::MediumFontFactor); this->code_field_txt=code_field_txt; auto_triggered=false; db_model=nullptr; setQualifyingLevel(nullptr); connect(name_list, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(selectItem(void))); connect(name_list, SIGNAL(currentRowChanged(int)), this, SLOT(showItemTooltip(void))); connect(&popup_timer, &QTimer::timeout, [&](){ if(qualifying_level < 2) { auto_triggered=true; this->show(); } }); this->setVisible(false); if(enable_snippets) connect(this, SIGNAL(s_wordSelected(QString)), this, SLOT(handleSelectedWord(QString))); } void CodeCompletionWidget::handleSelectedWord(QString word) { if(SnippetsConfigWidget::isSnippetExists(word)) { QTextCursor tc=code_field_txt->textCursor(); tc.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); tc.removeSelectedText(); tc.insertText(SnippetsConfigWidget::getParsedSnippet(word)); } } bool CodeCompletionWidget::eventFilter(QObject *object, QEvent *event) { QKeyEvent *k_event=dynamic_cast(event); if(k_event && k_event->type()==QEvent::KeyPress) { if(object==code_field_txt) { //Filters the trigger char and shows up the code completion only if there is a valid database model in use if(QChar(k_event->key())==completion_trigger && db_model) { /* If the completion widget is not visible start the timer to give the user a small delay in order to type another character. If no char is typed the completion is triggered */ if(!completion_wgt->isVisible() && !popup_timer.isActive()) popup_timer.start(); if(name_list->isVisible()) { this->selectItem(); this->show(); } } else { popup_timer.stop(); //Filters the Crtl+Space to trigger the code completion if(k_event->key()==Qt::Key_Space && (k_event->modifiers()==Qt::ControlModifier || k_event->modifiers()==Qt::MetaModifier)) { setQualifyingLevel(nullptr); this->show(); return(true); } else if(k_event->key()==Qt::Key_Space || k_event->key()==Qt::Key_Backspace || k_event->key()==Qt::Key_Delete) { QTextCursor tc=code_field_txt->textCursor(); tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); /* Avoiding deleting text using backspace or delete if the current char is the completion trigger (.). This will block the cursor and cause the list to stay in the current qualifying level */ if(completion_wgt->isVisible() && (k_event->key()==Qt::Key_Backspace || k_event->key()==Qt::Key_Delete) && tc.selectedText().contains(completion_trigger)) { event->ignore(); return(true); } else if(k_event->key()==Qt::Key_Space) { setQualifyingLevel(nullptr); if(!persistent_chk->isChecked()) this->close(); } if(persistent_chk->isChecked()) this->show(); } } } else if(object==name_list) { if(k_event->key()==Qt::Key_Escape) { this->close(); return(true); } //Filters the ENTER/RETURN press to close the code completion widget select the name else if(k_event->key()==Qt::Key_Enter || k_event->key()==Qt::Key_Return) { if(!persistent_chk->isChecked()) this->selectItem(); else { //Forcing the line break on the code field when holding Control key and hit return/enter if(k_event->modifiers()==Qt::ControlModifier) { QTextCursor cursor=code_field_txt->textCursor(); code_field_txt->insertPlainText(QChar(QChar::LineFeed)); cursor.movePosition(QTextCursor::Down); code_field_txt->setTextCursor(cursor); } else this->selectItem(); this->show(); } return(true); } //Filters other key press and redirects to the code input field else if(k_event->key()!=Qt::Key_Up && k_event->key()!=Qt::Key_Down && k_event->key()!=Qt::Key_PageUp && k_event->key()!=Qt::Key_PageDown && k_event->key()!=Qt::Key_Home && k_event->key()!=Qt::Key_End && k_event->modifiers()!=Qt::AltModifier) { QCoreApplication::sendEvent(code_field_txt, k_event); this->updateList(); return(true); } } } return(QWidget::eventFilter(object, event)); } void CodeCompletionWidget::configureCompletion(DatabaseModel *db_model, SyntaxHighlighter *syntax_hl, const QString &keywords_grp) { map confs=GeneralConfigWidget::getConfigurationParams(); name_list->clear(); word.clear(); setQualifyingLevel(nullptr); auto_triggered=false; this->db_model=db_model; if(confs[Attributes::Configuration][Attributes::CodeCompletion]==Attributes::True) { code_field_txt->installEventFilter(this); name_list->installEventFilter(this); if(syntax_hl && keywords.isEmpty()) { //Get the keywords from the highlighter vector exprs=syntax_hl->getExpressions(keywords_grp); while(!exprs.empty()) { keywords.push_front(exprs.back().pattern()); exprs.pop_back(); } completion_trigger=syntax_hl->getCompletionTrigger(); } else completion_trigger=QChar('.'); if(enable_snippets) { clearCustomItems(); insertCustomItems(SnippetsConfigWidget::getAllSnippetsAttribute(Attributes::Id), SnippetsConfigWidget::getAllSnippetsAttribute(Attributes::Label), QPixmap(PgModelerUiNs::getIconPath("codesnippet"))); } } else { code_field_txt->removeEventFilter(this); name_list->removeEventFilter(this); } } void CodeCompletionWidget::insertCustomItem(const QString &name, const QString &tooltip, const QPixmap &icon) { if(!name.isEmpty()) { QString item_name=name.simplified(); custom_items[item_name]=icon; custom_items_tips[item_name]=tooltip; } } void CodeCompletionWidget::insertCustomItems(const QStringList &names, const QStringList &tooltips, const QPixmap &icon) { for(int i=0; i < names.size(); i++) { insertCustomItem(names[i], (i < tooltips.size() ? tooltips[i] : QString()), icon); } } void CodeCompletionWidget::insertCustomItems(const QStringList &names, const QString &tooltip, ObjectType obj_type) { for(auto &name : names) insertCustomItem(name, tooltip, QPixmap(PgModelerUiNs::getIconPath(obj_type))); } void CodeCompletionWidget::clearCustomItems(void) { custom_items.clear(); } void CodeCompletionWidget::populateNameList(vector &objects, QString filter) { QListWidgetItem *item=nullptr; QString obj_name; ObjectType obj_type; QRegExp regexp(filter.remove('"') + QString("*"), Qt::CaseInsensitive, QRegExp::Wildcard); name_list->clear(); for(unsigned i=0; i < objects.size(); i++) { obj_type=objects[i]->getObjectType(); obj_name.clear(); //Formatting the object name according to the object type if(obj_type==ObjectType::Function) { dynamic_cast(objects[i])->createSignature(false); obj_name=dynamic_cast(objects[i])->getSignature(); } else if(obj_type==ObjectType::Operator) obj_name=dynamic_cast(objects[i])->getSignature(false); else obj_name+=objects[i]->getName(false, false); //The object will be inserted if its name matches the filter or there is no filter set if(filter.isEmpty() || regexp.exactMatch(obj_name)) { item=new QListWidgetItem(QPixmap(PgModelerUiNs::getIconPath(objects[i]->getSchemaName())), obj_name); item->setToolTip(QString("%1 (%2)").arg(objects[i]->getName(true)).arg(objects[i]->getTypeName())); item->setData(Qt::UserRole, QVariant::fromValue(objects[i])); item->setToolTip(BaseObject::getTypeName(obj_type)); name_list->addItem(item); } } name_list->sortItems(); } void CodeCompletionWidget::show(void) { prev_txt_cur=code_field_txt->textCursor(); this->updateList(); completion_wgt->show(); this->showItemTooltip(); popup_timer.stop(); } void CodeCompletionWidget::setQualifyingLevel(BaseObject *obj) { if(!obj) qualifying_level=-1; else if(obj->getObjectType()==ObjectType::Schema) qualifying_level=0; else if(BaseTable::isBaseTable(obj->getObjectType())) qualifying_level=1; else qualifying_level=2; if(qualifying_level < 0) { sel_objects={ nullptr, nullptr, nullptr }; } else { sel_objects[qualifying_level]=obj; lvl_cur=code_field_txt->textCursor(); } } void CodeCompletionWidget::updateList(void) { QListWidgetItem *item=nullptr; QString pattern; QStringList list; vector objects; vector types=BaseObject::getObjectTypes(false, { ObjectType::Textbox, ObjectType::Relationship, ObjectType::BaseRelationship }); QTextCursor tc; name_list->clear(); word.clear(); new_txt_cur=tc=code_field_txt->textCursor(); /* Try to move the cursor to the previous char in order to check if the user is calling the completion without an attached word */ tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); if(!tc.selectedText().trimmed().isEmpty() && new_txt_cur.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor)) { //Move the cursor right before the trigger char in order to get the complete word code_field_txt->setTextCursor(new_txt_cur); word=code_field_txt->textCursor().selectedText(); word.remove('"'); //Case the completion was triggered using the trigger char if(db_model && (auto_triggered || completion_trigger==word)) { /* The completion will try to find a schema, table or view that matches the word, if the serach returns one item the completion will start/continue an qualifying level */ new_txt_cur.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor); code_field_txt->setTextCursor(new_txt_cur); word=code_field_txt->textCursor().selectedText(); word.remove(completion_trigger); word.remove('"'); objects=db_model->findObjects(word, { ObjectType::Schema, ObjectType::Table, ObjectType::ForeignTable, ObjectType::View }, false, false, true); if(objects.size()==1) setQualifyingLevel(objects[0]); } code_field_txt->setTextCursor(prev_txt_cur); } if(!word.isEmpty() && !auto_triggered) pattern=QString("(^") + word.simplified() + QString(")"); else if(auto_triggered) pattern=word; if(db_model) { //Negative qualifying level means that user called the completion before a space (empty word) if(qualifying_level < 0) //The default behavior for this is to search all the objects on the model objects=db_model->findObjects(pattern, types, false, !auto_triggered, auto_triggered); else { QString left_word; //Searching objects according to qualifying level. tc=code_field_txt->textCursor(); tc.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor); /* Retrieving the word at the left in order to compare it to the object's name at the current qualifying level, if the word does not matches the object then children objects will not be retrieved */ if(tc.selectedText().contains('\"')) { tc.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor); left_word=tc.selectedText(); left_word.remove('"'); } else left_word=tc.selectedText(); //Level 0 indicates that user selected a schema, so all objects of the schema are retrieved if(qualifying_level==0 /*&& left_word==sel_objects[qualifying_level]->getName()*/) objects=db_model->getObjects(sel_objects[qualifying_level]); /* Level 1 indicates that user selected a table or view, so all child objects are retrieved. If the current level is 1 and the table/view name isn't present then the children will not be listed */ else if(qualifying_level==1 /*&& left_word==sel_objects[qualifying_level]->getName()*/) objects=dynamic_cast(sel_objects[qualifying_level])->getObjects(); /* If the current qualifying level and current word does retrieve any object as a fallback we try to find any object in the model and reset the qualifying level */ else { objects=db_model->findObjects(pattern, types, false, !auto_triggered, auto_triggered); setQualifyingLevel(nullptr); } /* If the typed word is equal to the current level object's name clear the order in order to avoid listing the same object */ if(qualifying_level >=0 && word==sel_objects[qualifying_level]->getName()) word.clear(); } populateNameList(objects, word); } /* List the keywords if the qualifying level is negative or the completion wasn't triggered using the special char */ if(qualifying_level < 0 && !auto_triggered) { QRegExp regexp(pattern, Qt::CaseInsensitive); list=keywords.filter(regexp); for(int i=0; i < list.size(); i++) { item=new QListWidgetItem(QPixmap(PgModelerUiNs::getIconPath("keyword")), list[i]); item->setToolTip(trUtf8("SQL Keyword")); name_list->addItem(item); } name_list->sortItems(); //If there are custom items, they wiill be placed at the very beggining of the list if(!custom_items.empty()) { QStringList list; int row=0; QListWidgetItem *item=nullptr; for(auto &itr : custom_items) { if(itr.first.contains(regexp)) list.push_back(itr.first); } list.sort(); for(auto &item_name : list) { item=new QListWidgetItem(custom_items[item_name], item_name); item->setToolTip(custom_items_tips[item_name]); name_list->insertItem(row++, item); } } } if(name_list->count()==0) { name_list->addItem(trUtf8("(no items found.)")); name_list->item(0)->setFlags(Qt::NoItemFlags); QToolTip::hideText(); } else name_list->setItemSelected(name_list->item(0), true); //Sets the list position right below of text cursor completion_wgt->move(code_field_txt->mapToGlobal(code_field_txt->cursorRect().topLeft() + QPoint(0,20))); name_list->setFocus(); } void CodeCompletionWidget::selectItem(void) { if(!name_list->selectedItems().isEmpty()) { QListWidgetItem *item=name_list->selectedItems().at(0); BaseObject *object=nullptr; QTextCursor tc; if(qualifying_level < 0) code_field_txt->setTextCursor(new_txt_cur); //If the selected item is a object (data not null) if(!item->data(Qt::UserRole).isNull()) { //Retrieve the object object=reinterpret_cast(item->data(Qt::UserRole).value()); /* Move the cursor to the start of the word because all the chars will be replaced with the object name */ prev_txt_cur.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); tc=prev_txt_cur; tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); /* An small workaround to correctly write the object name in the current qualifying level without remove the parent's name. This happens only when the completion is marked as persistent */ if(persistent_chk->isChecked()) { if(tc.selectedText().startsWith('.')) { prev_txt_cur.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); if(!tc.selectedText().endsWith('.')) prev_txt_cur.insertText(completion_trigger); } else if(qualifying_level >= 0 && !tc.selectedText().endsWith('.')) { prev_txt_cur.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); prev_txt_cur.insertText(completion_trigger); } } else if(tc.selectedText().contains('"')) prev_txt_cur=tc; code_field_txt->setTextCursor(prev_txt_cur); insertObjectName(object); setQualifyingLevel(object); } else { code_field_txt->insertPlainText(item->text() + QString(" ")); setQualifyingLevel(nullptr); } emit s_wordSelected(item->text()); } else setQualifyingLevel(nullptr); name_list->clearSelection(); auto_triggered=false; if(!persistent_chk->isChecked()) this->close(); } void CodeCompletionWidget::showItemTooltip(void) { QListWidgetItem *item=name_list->currentItem(); if(item) { QPoint pos=name_list->mapToGlobal(QPoint(name_list->width(), name_list->geometry().top())); QToolTip::showText(pos, item->toolTip()); } } void CodeCompletionWidget::close(void) { name_list->clearSelection(); completion_wgt->close(); auto_triggered=false; } void CodeCompletionWidget::insertObjectName(BaseObject *obj) { bool sch_qualified=!sel_objects[0], modify_name=QApplication::keyboardModifiers()==Qt::AltModifier; QString name=obj->getName(true, sch_qualified); ObjectType obj_type=obj->getObjectType(); int move_cnt=0; if(modify_name && (PhysicalTable::isPhysicalTable(obj_type) || TableObject::isTableObject(obj_type))) { if(PhysicalTable::isPhysicalTable(obj_type)) { PhysicalTable *tab=dynamic_cast(obj); name+=QString("("); for(unsigned i=0; i < tab->getColumnCount(); i++) name+=tab->getColumn(i)->getName(true) + QString(","); name.remove(name.size()-1, 1); name+=QString(")"); } else { if(sel_objects[0]) move_cnt=2; else move_cnt=3; lvl_cur.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor, move_cnt); code_field_txt->setTextCursor(lvl_cur); } } else if(obj_type==ObjectType::Function) { Function *func=dynamic_cast(obj); func->createSignature(true, sch_qualified); name=func->getSignature(); } else if(obj_type==ObjectType::Cast) { name.replace(',', QLatin1String(" AS ")); } else if(obj_type==ObjectType::Aggregate) { Aggregate *agg; agg=dynamic_cast(obj); name+=QString("("); if(agg->getDataTypeCount()==0) name+='*'; else { for(unsigned i=0; i < agg->getDataTypeCount(); i++) name+=~agg->getDataType(i) + ','; name.remove(name.size()-1, 1); } name+=')'; } code_field_txt->insertPlainText(name); } pgmodeler-0.9.2/libpgmodeler_ui/src/codecompletionwidget.h000066400000000000000000000130201360462764600240240ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class CodeCompletionWidget \brief Widget that handles the code completion (keywords and model object names) on a field that has the syntax highlighter installed on it. */ #ifndef CODE_COMPLETION_WIDGET_H #define CODE_COMPLETION_WIDGET_H #include #include "syntaxhighlighter.h" #include "databasemodel.h" class CodeCompletionWidget: public QWidget { private: Q_OBJECT //! \brief A timer that controls the completion popup QTimer popup_timer; QWidget *completion_wgt; //! \brief Marks the completion widget as persistent (available only when there is no a database model assinged) QCheckBox *persistent_chk; //! \brief Input field that is associated with the code completion QPlainTextEdit *code_field_txt; //! \brief This widget stores the list of completion items QListWidget *name_list; /*! \brief Stores the keywords retrieved from the syntax highlighter. These key words are listed whenever the user call the completion */ QStringList keywords; /*! \brief This cursor object is configured to use as a replacer when the user selects an item on the completion list */ QTextCursor new_txt_cur, //! \brief Stores the current text cursor position on the code field prev_txt_cur, lvl_cur; //! \brief Current typed word QString word; /*! \brief Stores the char used to trigger the completion widget. If the completion was instantiated using a SyntaxHighlighter object this char is retrieved from this last or the default (.) is used */ QChar completion_trigger; //! \brief Stores the database model used to search for objects and list them on completion DatabaseModel *db_model; /*! \brief This is used to simulate an history of selected object whenever the user types the completion trigger char. An example of qualifying is access a column of a table by typing the full path to it: public[0].table[1].column[2]. The numbers between brace are the qualifying level. */ int qualifying_level; //! \brief Indicates if the completion was triggered by typing the completion char bool auto_triggered, enable_snippets; //! \brief Store the objects selected for each qualifying level vector sel_objects; map custom_items; attribs_map custom_items_tips; //! \brief Puts the selected object name on the current cursor position. void insertObjectName(BaseObject *obj); //! \brief Filters the necessary events to trigger the completion as well to control/select items bool eventFilter(QObject *object, QEvent *event); /*! \brief Insert the objects of the vector into the name listing. The filter parameter is used to insert only the object which names matches the filter */ void populateNameList(vector &objects, QString filter=QString()); //! \brief Configures the current qualifying level according to the passed object void setQualifyingLevel(BaseObject *obj); public: CodeCompletionWidget(QPlainTextEdit *code_field_txt, bool enable_snippets = false); /*! \brief Configures the completion. If an syntax highlighter is specified, the completion widget will retrive the keywords and the trigger char from it. The keyword group name can be also specified in case the highlighter uses an different configuration */ void configureCompletion(DatabaseModel *db_model, SyntaxHighlighter *syntax_hl=nullptr, const QString &keywords_grp=QString("keywords")); //! \brief Inserts a custom named item on the list with a custom icon. Custom item will always appear at the beggining of the list void insertCustomItem(const QString &name, const QString &tooltip, const QPixmap &icon); //! \brief Inserts several custom named item on the list with a custom icon. Custom item will always appear at the beggining of the list void insertCustomItems(const QStringList &names, const QStringList &tooltips, const QPixmap &icon); //! \brief Inserts several custom named items on the list with an icon related to the obj_type. Custom item will always appear at the beggining of the list void insertCustomItems(const QStringList &names, const QString &tooltip, ObjectType obj_type); //! \brief Clear the custom added items void clearCustomItems(void); public slots: //! \brief Updates the completion list based upon the typed word void updateList(void); //! \brief Shows the configured completion list void show(void); //! \brief Close without select any item on completion list void close(void); //! \brief Selects an item and closes the completion list void selectItem(void); void showItemTooltip(void); signals: //! \brief This signal is emitted whenever a word is placed into the parent textbox through the completion popup. void s_wordSelected(QString); private slots: void handleSelectedWord(QString word); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/collationwidget.cpp000066400000000000000000000133671360462764600233550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "collationwidget.h" CollationWidget::CollationWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Collation) { try { QStringList loc_list, encodings; QFrame *frame=nullptr; Ui_CollationWidget::setupUi(this); frame=generateInformationFrame(trUtf8("The fields Collation, Locale, LC_COLLATE & LC_CTYPE are mutually exclusive, so you have to set only one of them in order to properly handle a collation.")); collation_grid->addItem(new QSpacerItem(10,10, QSizePolicy::Minimum,QSizePolicy::Expanding), collation_grid->count()+1, 0, 1, 0); collation_grid->addWidget(frame, collation_grid->count()+1, 0, 1, 0); frame->setParent(this); configureFormLayout(collation_grid, ObjectType::Collation); //Configures the encoding combobox EncodingType::getTypes(encodings); encodings.push_front(trUtf8("Not defined")); encoding_cmb->addItems(encodings); //Configures the localizations combobox for(int i=QLocale::C; i <= QLocale::Chewa; i++) { for(int i1=QLocale::Afghanistan; i1 <= QLocale::Zimbabwe; i1++) loc_list.append(QLocale(static_cast(i),static_cast(i1)).name()); } loc_list.removeDuplicates(); loc_list.sort(); loc_list.push_front(trUtf8("Not defined")); lccollate_cmb->addItems(loc_list); lcctype_cmb->addItems(loc_list); locale_cmb->addItems(loc_list); connect(collation_sel, SIGNAL(s_objectSelected(void)), this, SLOT(resetFields(void))); connect(collation_sel, SIGNAL(s_selectorCleared(void)), this, SLOT(resetFields(void))); connect(locale_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(resetFields(void))); connect(lcctype_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(resetFields(void))); connect(lccollate_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(resetFields(void))); configureTabOrder({ locale_cmb, encoding_cmb, lccollate_cmb, lcctype_cmb }); setMinimumSize(520, 420); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void CollationWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Collation *collation) { BaseObjectWidget::setAttributes(model, op_list, collation, schema); if(collation) { int idx=-1; idx=encoding_cmb->findText(~collation->getEncoding()); encoding_cmb->setCurrentIndex(idx < 0 ? 0 : idx); if(!collation_sel->getSelectedObject()) { idx=locale_cmb->findText(collation->getLocale()); locale_cmb->setCurrentIndex(idx < 0 ? 0 : idx); if(locale_cmb->currentIndex()==0) { idx=lcctype_cmb->findText(collation->getLocalization(Collation::LcCtype)); lcctype_cmb->setCurrentIndex(idx < 0 ? 0 : idx); idx=lccollate_cmb->findText(collation->getLocalization(Collation::LcCollate)); lccollate_cmb->setCurrentIndex(idx < 0 ? 0 : idx); } } } } void CollationWidget::resetFields(void) { //Block object's signals to evict an infinite call to this method collation_sel->blockSignals(true); locale_cmb->blockSignals(true); lccollate_cmb->blockSignals(true); lcctype_cmb->blockSignals(true); //If there is no sender reset all fields if(!sender()) { collation_sel->clearSelector(); locale_cmb->setCurrentIndex(0); lccollate_cmb->setCurrentIndex(0); lcctype_cmb->setCurrentIndex(0); } //Resetting the collation selector and locale combo else if((sender()==lccollate_cmb || sender()==lcctype_cmb) && (lccollate_cmb->currentIndex() > 0 || lcctype_cmb->currentIndex() > 0)) { collation_sel->clearSelector(); locale_cmb->setCurrentIndex(0); } //Resetting the lc_??? combos else if((sender()==collation_sel || sender()==locale_cmb) && (collation_sel->getSelectedObject()!=nullptr || locale_cmb->currentIndex() > 0)) { lccollate_cmb->setCurrentIndex(0); lcctype_cmb->setCurrentIndex(0); //Additionally resets the collation selector or locale combo depending on sender() if(sender()==collation_sel && collation_sel->getSelectedObject()!=nullptr) locale_cmb->setCurrentIndex(0); else collation_sel->clearSelector(); } collation_sel->blockSignals(false); locale_cmb->blockSignals(false); lccollate_cmb->blockSignals(false); lcctype_cmb->blockSignals(false); } void CollationWidget::applyConfiguration(void) { try { Collation *collation=nullptr; startConfiguration(); collation=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); if(encoding_cmb->currentIndex() > 0) collation->setEncoding(EncodingType(encoding_cmb->currentText())); if(locale_cmb->currentIndex() > 0) collation->setLocale(locale_cmb->currentText()); if(lccollate_cmb->currentIndex() > 0) collation->setLocalization(Collation::LcCollate, lccollate_cmb->currentText()); if(lcctype_cmb->currentIndex() > 0) collation->setLocalization(Collation::LcCtype, lcctype_cmb->currentText()); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/collationwidget.h000066400000000000000000000024741360462764600230170ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class CollationWidget \brief Implements the operations to create/edit collations via form. */ #ifndef COLLATION_WIDGET_H #define COLLATION_WIDGET_H #include "baseobjectwidget.h" #include "ui_collationwidget.h" class CollationWidget: public BaseObjectWidget, public Ui::CollationWidget { private: Q_OBJECT public: CollationWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Collation *collation); public slots: void applyConfiguration(void); private slots: void resetFields(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/colorpickerwidget.cpp000066400000000000000000000113011360462764600236670ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "colorpickerwidget.h" #include ColorPickerWidget::ColorPickerWidget(int color_count, QWidget * parent) : QWidget(parent) { random_device rand_seed; rand_num_engine.seed(rand_seed()); QToolButton *btn=nullptr; QHBoxLayout *hbox=nullptr; QSpacerItem *spacer=new QSpacerItem(10,10, QSizePolicy::Expanding, QSizePolicy::Fixed); setupUi(this); if(color_count==0) color_count=1; else if(color_count > MaxColorButtons) color_count=MaxColorButtons; hbox=new QHBoxLayout(this); hbox->setContentsMargins(0,0,0,0); for(int i=0; i < color_count; i++) { btn=new QToolButton(this); btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); btn->setMinimumHeight(25); btn->setMaximumHeight(random_color_tb->height() - 10); btn->setMinimumWidth(55); btn->installEventFilter(this); disable_color=btn->palette().color(QPalette::Button); buttons.push_back(btn); colors.push_back(disable_color); hbox->addWidget(btn); connect(btn, SIGNAL(clicked()), this, SLOT(selectColor())); } hbox->addWidget(random_color_tb); hbox->addSpacerItem(spacer); this->adjustSize(); connect(random_color_tb, SIGNAL(clicked()), this, SLOT(generateRandomColors())); } bool ColorPickerWidget::eventFilter(QObject *object, QEvent *event) { QToolButton *button=qobject_cast(object); if(event->type()==QEvent::ToolTip && button && button!=random_color_tb) { QToolTip::showText(QCursor::pos(), button->toolTip()); return(true); } return(QWidget::eventFilter(object, event)); } void ColorPickerWidget::setColor(int color_idx, const QColor &color) { QString cl_name; if(color_idx < 0 || color_idx >= colors.size()) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(this->isEnabled()) cl_name=color.name(); else cl_name=disable_color.name(); buttons[color_idx]->setStyleSheet(QString("background-color: %1").arg(cl_name)); colors[color_idx]=color; } QColor ColorPickerWidget::getColor(int color_idx) { if(color_idx < 0 || color_idx >= colors.size()) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(colors[color_idx]); } unsigned ColorPickerWidget::getColorCount(void) { return(colors.size()); } bool ColorPickerWidget::isButtonVisible(unsigned idx) { if(idx >= static_cast(buttons.size())) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(buttons[idx]->isVisible()); } void ColorPickerWidget::setButtonToolTip(unsigned button_idx, const QString &tooltip) { if(button_idx >= static_cast(buttons.size())) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); buttons[button_idx]->setToolTip(tooltip); } void ColorPickerWidget::setEnabled(bool value) { int i=0; for(auto &btn : buttons) btn->setStyleSheet(QString("background-color: %1") .arg(value ? colors[i++].name() : disable_color.name())); QWidget::setEnabled(value); } void ColorPickerWidget::setButtonVisible(unsigned idx, bool value) { if(idx >= static_cast(buttons.size())) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); buttons[idx]->setVisible(value); } void ColorPickerWidget::selectColor(void) { QColorDialog color_dlg; QToolButton *btn=qobject_cast(sender()); int btn_idx=buttons.indexOf(btn); color_dlg.setWindowTitle(trUtf8("Select color")); color_dlg.setCurrentColor(colors[btn_idx]); color_dlg.exec(); if(color_dlg.result()==QDialog::Accepted) { setColor(btn_idx, color_dlg.selectedColor()); emit s_colorChanged(static_cast(buttons.indexOf(btn)), color_dlg.selectedColor()); } } void ColorPickerWidget::generateRandomColors(void) { QColor color; uniform_int_distribution dist(0,255); int i=0; for(i=0; i < buttons.size(); i++) { color=QColor(dist(rand_num_engine), dist(rand_num_engine), dist(rand_num_engine)); setColor(i, color); } emit s_colorsChanged(); } pgmodeler-0.9.2/libpgmodeler_ui/src/colorpickerwidget.h000066400000000000000000000043161360462764600233440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ColorPìckerWidget \brief Implements a basic widget to handle color selection. */ #ifndef COLOR_PICKER_WIDGET_H #define COLOR_PICKER_WIDGET_H #include #include #include #include "ui_colorpickerwidget.h" #include "exception.h" #include #include class ColorPickerWidget: public QWidget, public Ui::ColorPickerWidget { private: Q_OBJECT //! \brief Random number generator engine used to generate random colors for buttons default_random_engine rand_num_engine; //! \brief List of buttons used to configure each color QList buttons; //! \brief List of colors assinged for each button QList colors; //! \brief Palette assinged to buttons when the color picker is disabled QColor disable_color; protected: bool eventFilter(QObject *object, QEvent *event); public: static constexpr int MaxColorButtons=20; explicit ColorPickerWidget(int color_count, QWidget * parent = nullptr); void setColor(int color_idx, const QColor &color); QColor getColor(int color_idx); unsigned getColorCount(void); bool isButtonVisible(unsigned idx); void setButtonToolTip(unsigned button_idx, const QString &tooltip); public slots: void setEnabled(bool value); void setButtonVisible(unsigned idx, bool value); void selectColor(void); void generateRandomColors(void); signals: void s_colorChanged(unsigned, QColor); void s_colorsChanged(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/columnwidget.cpp000066400000000000000000000160331360462764600226570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "columnwidget.h" #include "sequencewidget.h" #include "baseform.h" #include "generalconfigwidget.h" ColumnWidget::ColumnWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Column) { try { QSpacerItem *spacer=new QSpacerItem(10,10,QSizePolicy::Fixed,QSizePolicy::Expanding); QStringList list; Ui_ColumnWidget::setupUi(this); edit_seq_btn->setVisible(false); IdentityType::getTypes(list); identity_type_cmb->addItems(list); data_type=nullptr; data_type=new PgSQLTypeWidget(this); hl_default_value=nullptr; hl_default_value=new SyntaxHighlighter(def_value_txt, true); hl_default_value->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); sequence_sel=new ObjectSelectorWidget(ObjectType::Sequence, true, this); sequence_sel->setEnabled(false); column_grid->addWidget(data_type,0,0,1,0); column_grid->addWidget(default_value_grp,1,0,1,1); column_grid->addItem(spacer,column_grid->count(),0); dynamic_cast(default_value_grp->layout())->addWidget(sequence_sel, 1, 1, 1, 6); configureFormLayout(column_grid, ObjectType::Column); configureTabOrder({ data_type }); map > fields_map; fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion100)].push_back(identity_rb); highlightVersionSpecificFields(fields_map); connect(sequence_rb, &QRadioButton::clicked, [&](){ sequence_sel->setEnabled(true); def_value_txt->setEnabled(false); identity_type_cmb->setEnabled(false); notnull_chk->setEnabled(true); edit_seq_btn->setVisible(false); }); connect(expression_rb, &QRadioButton::clicked, [&](){ sequence_sel->setEnabled(false); def_value_txt->setEnabled(true); identity_type_cmb->setEnabled(false); notnull_chk->setEnabled(true); edit_seq_btn->setVisible(false); }); connect(identity_rb, &QRadioButton::clicked, [&](){ sequence_sel->setEnabled(false); def_value_txt->setEnabled(false); identity_type_cmb->setEnabled(true); notnull_chk->setChecked(true); notnull_chk->setEnabled(false); edit_seq_btn->setVisible(true); }); connect(edit_seq_btn, SIGNAL(clicked(bool)), this, SLOT(editSequenceAttributes())); setMinimumSize(540, 480); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ColumnWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *parent_obj, Column *column) { PgSqlType type; if(!parent_obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, column, parent_obj); sequence_sel->setModel(model); ident_col_seq.setValues(QString(), QString(), QString(), QString(), QString()); ident_col_seq.setCycle(false); if(column) { type=column->getType(); notnull_chk->setChecked(column->isNotNull()); def_value_txt->setPlainText(column->getDefaultValue()); if(column->getSequence()) { sequence_rb->click(); sequence_sel->setEnabled(true); sequence_sel->setSelectedObject(column->getSequence()); } else if(column->getIdentityType() != BaseType::Null) { identity_rb->click(); identity_type_cmb->setEnabled(true); identity_type_cmb->setCurrentText(~column->getIdentityType()); notnull_chk->setEnabled(false); } } data_type->setAttributes(type, model, UserTypeConfig::BaseType | UserTypeConfig::TableType | UserTypeConfig::ViewType | UserTypeConfig::ForeignTableType | UserTypeConfig::DomainType | UserTypeConfig::ExtensionType, true,false); } void ColumnWidget::editSequenceAttributes(void) { Column *col = dynamic_cast(this->object); Schema *schema = nullptr; BaseForm editing_form(this); SequenceWidget *seq_wgt=new SequenceWidget; BaseTable *table = col ? col->getParentTable() : nullptr; if(table) schema = dynamic_cast(table->getSchema()); else schema = this->model->getSchema("public"); ident_col_seq.setName(QString("%1_%2_seq").arg(table ? table->getName() : QString()).arg(col ? col->getName() : QString("new_column"))); ident_col_seq.setName(PgModelerNs::generateUniqueName(&ident_col_seq, *model->getObjectList(ObjectType::Sequence), false)); ident_col_seq.setSchema(schema); if(col) { ident_col_seq.setDefaultValues(col->getType()); ident_col_seq.setValues(col->getIdSeqMinValue(), col->getIdSeqMaxValue(), col->getIdSeqIncrement(), col->getIdSeqStart(), col->getIdSeqCache()); ident_col_seq.setCycle(col->isIdSeqCycle()); } seq_wgt->setAttributesReadonly(this->model, nullptr, nullptr, &ident_col_seq, col); editing_form.setMainWidget(seq_wgt); GeneralConfigWidget::restoreWidgetGeometry(&editing_form, seq_wgt->metaObject()->className()); editing_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&editing_form, seq_wgt->metaObject()->className()); } void ColumnWidget::applyConfiguration(void) { try { Column *column=nullptr; Constraint *pk = nullptr; startConfiguration(); column=dynamic_cast(this->object); column->setNotNull(notnull_chk->isChecked()); column->setType(data_type->getPgSQLType()); if(expression_rb->isChecked()) column->setDefaultValue(def_value_txt->toPlainText()); else if(sequence_rb->isChecked()) column->setSequence(sequence_sel->getSelectedObject()); else column->setIdentityType(IdentityType(identity_type_cmb->currentText())); column->setIdSeqAttributes(ident_col_seq.getMinValue(), ident_col_seq.getMaxValue(), ident_col_seq.getIncrement(), ident_col_seq.getStart(), ident_col_seq.getCache(), ident_col_seq.isCycle()); if(table) { pk = dynamic_cast(table)->getPrimaryKey(); if(pk && pk->isColumnReferenced(column) && !notnull_chk->isChecked()) throw Exception(Exception::getErrorMessage(ErrorCode::NullPrimaryKeyColumn) .arg(column->getName()) .arg(pk->getParentTable()->getSignature(true)), ErrorCode::NullPrimaryKeyColumn,__PRETTY_FUNCTION__,__FILE__,__LINE__); } BaseObjectWidget::applyConfiguration(); model->updateViewsReferencingTable(dynamic_cast(table)); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/columnwidget.h000066400000000000000000000027241360462764600223260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ColumnWidget \brief Implements the operations to create/edit columns via form. */ #ifndef COLUMN_WIDGET_H #define COLUMN_WIDGET_H #include "baseobjectwidget.h" #include "ui_columnwidget.h" #include "pgsqltypewidget.h" class ColumnWidget: public BaseObjectWidget, public Ui::ColumnWidget { private: Q_OBJECT SyntaxHighlighter *hl_default_value; PgSQLTypeWidget *data_type; ObjectSelectorWidget *sequence_sel; Sequence ident_col_seq; public: ColumnWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *parent_obj, Column *column); private slots: void editSequenceAttributes(void); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/configurationform.cpp000066400000000000000000000111731360462764600237110ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "configurationform.h" ConfigurationForm::ConfigurationForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); general_conf=new GeneralConfigWidget(this); appearance_conf=new AppearanceConfigWidget(this); connections_conf=new ConnectionsConfigWidget(this); relationships_conf=new RelationshipConfigWidget(this); snippets_conf=new SnippetsConfigWidget(this); plugins_conf=new PluginsConfigWidget(this); QWidgetList wgt_list={ general_conf, relationships_conf, appearance_conf, connections_conf, snippets_conf, plugins_conf}; for(int i=GeneralConfWgt; i <= PluginsConfWgt; i++) confs_stw->addWidget(wgt_list[i]); connect(icons_lst, SIGNAL(currentRowChanged(int)), confs_stw, SLOT(setCurrentIndex(int))); connect(cancel_btn, SIGNAL(clicked(void)), this, SLOT(reject(void))); connect(apply_btn, SIGNAL(clicked(void)), this, SLOT(applyConfiguration(void))); connect(defaults_btn, SIGNAL(clicked(void)), this, SLOT(restoreDefaults(void))); icons_lst->setCurrentRow(GeneralConfWgt); setMinimumSize(890, 740); } ConfigurationForm::~ConfigurationForm(void) { connections_conf->destroyConnections(); } void ConfigurationForm::hideEvent(QHideEvent *) { icons_lst->setCurrentRow(GeneralConfWgt); } void ConfigurationForm::showEvent(QShowEvent *) { snippets_conf->snippet_txt->updateLineNumbers(); } void ConfigurationForm::reject(void) { try { if(sender()==cancel_btn) { QWidgetList wgt_list={ appearance_conf, connections_conf, snippets_conf }; BaseConfigWidget *conf_wgt=nullptr; for(QWidget *wgt : wgt_list) { conf_wgt=qobject_cast(wgt); if(conf_wgt->isConfigurationChanged()) conf_wgt->loadConfiguration(); } } } catch(Exception &) {} QDialog::reject(); } void ConfigurationForm::applyConfiguration(void) { BaseConfigWidget *conf_wgt=nullptr; bool curr_escape_comments = BaseObject::isEscapeComments(); for(int i=GeneralConfWgt; i <= SnippetsConfWgt; i++) { conf_wgt=qobject_cast(confs_stw->widget(i)); if(conf_wgt->isConfigurationChanged()) conf_wgt->saveConfiguration(); } general_conf->applyConfiguration(); relationships_conf->applyConfiguration(); if(curr_escape_comments != BaseObject::isEscapeComments()) emit s_invalidateModelsRequested(); QDialog::accept(); } void ConfigurationForm::loadConfiguration(void) { BaseConfigWidget *config_wgt = nullptr; for(int i=GeneralConfWgt; i <= PluginsConfWgt; i++) { try { config_wgt = qobject_cast(confs_stw->widget(i)); config_wgt->loadConfiguration(); } catch(Exception &e) { Messagebox msg_box; if(e.getErrorCode()==ErrorCode::PluginsNotLoaded) { msg_box.show(e); } else { Exception ex = Exception(Exception::getErrorMessage(ErrorCode::ConfigurationNotLoaded).arg(e.getExtraInfo()),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); msg_box.show(ex, QString("%1 %2").arg(ex.getErrorMessage()).arg(trUtf8("In some cases restore the default settings related to it may solve the problem. Would like to do that?")), Messagebox::AlertIcon, Messagebox::YesNoButtons, trUtf8("Restore"), QString(), QString(), PgModelerUiNs::getIconPath("atualizar")); if(msg_box.result() == QDialog::Accepted) config_wgt->restoreDefaults(); } } } } void ConfigurationForm::restoreDefaults(void) { Messagebox msg_box; msg_box.show(trUtf8("Any modification made until now in the current section will be lost! Do you really want to restore default settings?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) qobject_cast(confs_stw->currentWidget())->restoreDefaults(); } BaseConfigWidget *ConfigurationForm::getConfigurationWidget(unsigned idx) { if(idx >= static_cast(confs_stw->count())) return(nullptr); else return(qobject_cast(confs_stw->widget(static_cast(idx)))); } pgmodeler-0.9.2/libpgmodeler_ui/src/configurationform.h000066400000000000000000000041211360462764600233510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ConfigurationForm \brief Reunites in a single form all available configuration widgets. */ #ifndef CONFIGURATION_FORM_H #define CONFIGURATION_FORM_H #include "ui_configurationform.h" #include "appearanceconfigwidget.h" #include "generalconfigwidget.h" #include "connectionsconfigwidget.h" #include "pluginsconfigwidget.h" #include "relationshipconfigwidget.h" #include "snippetsconfigwidget.h" class ConfigurationForm: public QDialog, public Ui::ConfigurationForm { private: Q_OBJECT GeneralConfigWidget *general_conf; AppearanceConfigWidget *appearance_conf; ConnectionsConfigWidget *connections_conf; RelationshipConfigWidget *relationships_conf; SnippetsConfigWidget *snippets_conf; PluginsConfigWidget *plugins_conf; void hideEvent(QHideEvent *); void showEvent(QShowEvent *); public: static constexpr int GeneralConfWgt=0, RelationshipsConfWgt=1, AppearanceConfWgt=2, ConnectionsConfWgt=3, SnippetsConfWgt=4, PluginsConfWgt=5; ConfigurationForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); ~ConfigurationForm(void); BaseConfigWidget *getConfigurationWidget(unsigned idx); public slots: void applyConfiguration(void); void loadConfiguration(void); void reject(void); private slots: void restoreDefaults(void); signals: void s_invalidateModelsRequested(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/connectionsconfigwidget.cpp000066400000000000000000000540301360462764600250710ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "connectionsconfigwidget.h" #include "pgmodeleruins.h" #include "baseform.h" vector ConnectionsConfigWidget::connections; map ConnectionsConfigWidget::config_params; const QString ConnectionsConfigWidget::DefaultFor=QString("default-for-%1"); ConnectionsConfigWidget::ConnectionsConfigWidget(QWidget * parent) : BaseConfigWidget(parent) { Ui_ConnectionsConfigWidget::setupUi(this); auto_browse_ht=new HintTextWidget(auto_browse_hint, this); auto_browse_ht->setText(auto_browse_chk->statusTip()); other_params_ht=new HintTextWidget(other_params_hint, this); other_params_ht->setText(other_params_edt->statusTip()); default_for_ops_ht=new HintTextWidget(default_for_ops_hint, this); default_for_ops_ht->setText(trUtf8("Indicates in which operations (diff, export, import or validation) the connection is used if none is explicitly specified by the user.")); connect(ssl_mode_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(enableCertificates(void))); connect(new_tb, SIGNAL(clicked(bool)), this, SLOT(newConnection(void))); connect(cancel_tb, SIGNAL(clicked(bool)), this, SLOT(newConnection(void))); connect(duplicate_tb, SIGNAL(clicked(bool)), this, SLOT(duplicateConnection(void))); connect(test_tb, SIGNAL(clicked(bool)), this, SLOT(testConnection(void))); connect(add_tb, SIGNAL(clicked(bool)), this, SLOT(handleConnection(void))); connect(update_tb, SIGNAL(clicked(bool)), this, SLOT(handleConnection(void))); connect(edit_tb, SIGNAL(clicked(bool)), this, SLOT(editConnection(void))); connect(remove_tb, SIGNAL(clicked(bool)), this, SLOT(removeConnection(void))); connect(alias_edt, SIGNAL(textChanged(QString)), this, SLOT(enableConnectionTest(void))); connect(host_edt, SIGNAL(textChanged(QString)), this, SLOT(enableConnectionTest(void))); connect(user_edt, SIGNAL(textChanged(QString)), this, SLOT(enableConnectionTest(void))); connect(passwd_edt, SIGNAL(textChanged(QString)), this, SLOT(enableConnectionTest(void))); connect(conn_db_edt, SIGNAL(textChanged(QString)), this, SLOT(enableConnectionTest(void))); update_tb->setVisible(false); cancel_tb->setVisible(false); } ConnectionsConfigWidget::~ConnectionsConfigWidget(void) { } void ConnectionsConfigWidget::hideEvent(QHideEvent *) { this->newConnection(); } void ConnectionsConfigWidget::showEvent(QShowEvent *) { updateConnectionsCombo(); newConnection(); conn_attribs_tbw->setCurrentIndex(0); } void ConnectionsConfigWidget::updateConnectionsCombo(void) { connections_cmb->clear(); for(auto &conn : connections) connections_cmb->addItem(QIcon(PgModelerUiNs::getIconPath("server")), conn->getConnectionId()); } void ConnectionsConfigWidget::destroyConnections(void) { Connection *conn=nullptr; while(!connections.empty()) { conn=connections.back(); connections.pop_back(); connections_cmb->removeItem(0); delete(conn); } } map ConnectionsConfigWidget::getConfigurationParams(void) { return(config_params); } void ConnectionsConfigWidget::loadConfiguration(void) { try { vector key_attribs; map::iterator itr, itr_end; Connection *conn=nullptr; destroyConnections(); key_attribs.push_back(Attributes::Alias); BaseConfigWidget::loadConfiguration(GlobalAttributes::ConnectionsConf, config_params, key_attribs); itr=config_params.begin(); itr_end=config_params.end(); while(itr!=itr_end) { conn=new Connection; conn->setConnectionParam(Connection::ParamAlias, itr->second[Attributes::Alias]); conn->setConnectionParam(Connection::ParamServerFqdn, itr->second[Connection::ParamServerFqdn]); conn->setConnectionParam(Connection::ParamPort, itr->second[Connection::ParamPort]); conn->setConnectionParam(Connection::ParamUser, itr->second[Connection::ParamUser]); conn->setConnectionParam(Connection::ParamPassword,itr->second[Connection::ParamPassword]); conn->setConnectionParam(Connection::ParamDbName, itr->second[Connection::ParamDbName]); conn->setConnectionParam(Connection::ParamConnTimeout, itr->second[Attributes::ConnectionTimeout]); conn->setConnectionParam(Connection::ParamSslMode, itr->second[Connection::ParamSslMode]); conn->setConnectionParam(Connection::ParamSslRootCert, itr->second[Connection::ParamSslRootCert]); conn->setConnectionParam(Connection::ParamSslCert, itr->second[Connection::ParamSslCert]); conn->setConnectionParam(Connection::ParamSslKey, itr->second[Connection::ParamSslKey]); conn->setConnectionParam(Connection::ParamSslCrl, itr->second[Connection::ParamSslCrl]); conn->setConnectionParam(Connection::ParamLibGssapi, itr->second[Connection::ParamLibGssapi]); conn->setConnectionParam(Connection::ParamKerberosServer, itr->second[Connection::ParamKerberosServer]); conn->setConnectionParam(Connection::ParamOthers, itr->second[Connection::ParamOthers]); conn->setAutoBrowseDB(itr->second[Attributes::AutoBrowseDb]==Attributes::True); conn->setDefaultForOperation(Connection::OpDiff, itr->second[DefaultFor.arg(Attributes::Diff)]==Attributes::True); conn->setDefaultForOperation(Connection::OpExport, itr->second[DefaultFor.arg(Attributes::Export)]==Attributes::True); conn->setDefaultForOperation(Connection::OpImport, itr->second[DefaultFor.arg(Attributes::Import)]==Attributes::True); conn->setDefaultForOperation(Connection::OpValidation, itr->second[DefaultFor.arg(Attributes::Validation)]==Attributes::True); connections.push_back(conn); itr++; } edit_tb->setEnabled(!connections.empty()); remove_tb->setEnabled(!connections.empty()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo()); } } void ConnectionsConfigWidget::enableCertificates(void) { client_cert_lbl->setEnabled(ssl_mode_cmb->currentIndex()!=0); client_cert_edt->setEnabled(ssl_mode_cmb->currentIndex()!=0); root_cert_lbl->setEnabled(ssl_mode_cmb->currentIndex()!=0); root_cert_edt->setEnabled(ssl_mode_cmb->currentIndex()!=0); crl_edt->setEnabled(ssl_mode_cmb->currentIndex()!=0); crl_lbl->setEnabled(ssl_mode_cmb->currentIndex()!=0); client_key_lbl->setEnabled(ssl_mode_cmb->currentIndex()!=0); client_key_edt->setEnabled(ssl_mode_cmb->currentIndex()!=0); } void ConnectionsConfigWidget::enableConnectionTest(void) { test_tb->setEnabled(!alias_edt->text().isEmpty() && !host_edt->text().isEmpty() && !user_edt->text().isEmpty() && !conn_db_edt->text().isEmpty()); add_tb->setEnabled(test_tb->isEnabled()); update_tb->setEnabled(test_tb->isEnabled()); if(!isConfigurationChanged()) setConfigurationChanged(true); } void ConnectionsConfigWidget::newConnection(void) { conn_db_edt->clear(); alias_edt->clear(); user_edt->clear(); host_edt->clear(); port_sbp->setValue(5432); passwd_edt->clear(); other_params_edt->clear(); auto_browse_chk->setChecked(false); diff_chk->setChecked(false); export_chk->setChecked(false); import_chk->setChecked(false); validation_chk->setChecked(false); ssl_mode_cmb->setCurrentIndex(0); client_cert_edt->setText(QString("~/.postgresql/postgresql.crt")); root_cert_edt->setText(QString("~/.postgresql/root.crt")); crl_edt->setText(QString("~/.postgresql/root.crl")); client_key_edt->setText(QString("~/.postgresql/postgresql.key")); gssapi_auth_chk->setChecked(false); krb_server_edt->clear(); timeout_sbp->setValue(2); add_tb->setVisible(true); update_tb->setVisible(false); connections_cmb->setEnabled(true); new_tb->setVisible(true); cancel_tb->setVisible(false); edit_tb->setEnabled(connections_cmb->count() > 0); remove_tb->setEnabled(connections_cmb->count() > 0); duplicate_tb->setEnabled(connections_cmb->count() > 0); } void ConnectionsConfigWidget::duplicateConnection(void) { Connection *conn=nullptr, *new_conn=nullptr; try { conn=connections.at(connections_cmb->currentIndex()); new_conn=new Connection; (*new_conn)=(*conn); connections.push_back(new_conn); new_conn->setConnectionParam(Connection::ParamAlias, QString("cp_%1").arg(conn->getConnectionParam(Connection::ParamAlias))); connections_cmb->addItem(QIcon(QString(":icones/icones/server.png")), new_conn->getConnectionId()); connections_cmb->setCurrentIndex(connections_cmb->count()-1); setConfigurationChanged(true); } catch(Exception &e) { if(new_conn) delete(new_conn); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConnectionsConfigWidget::handleConnection(void) { Connection *conn=nullptr; try { if(!update_tb->isVisible()) { conn=new Connection; this->configureConnection(conn); connections_cmb->addItem(QIcon(QString(":icones/icones/server.png")), conn->getConnectionId()); connections.push_back(conn); } else { conn=connections.at(connections_cmb->currentIndex()); this->configureConnection(conn); connections_cmb->setItemText(connections_cmb->currentIndex(), conn->getConnectionId()); } this->newConnection(); edit_tb->setEnabled(connections_cmb->count() > 0); remove_tb->setEnabled(connections_cmb->count() > 0); setConfigurationChanged(true); } catch(Exception &e) { if(add_tb->isVisible()) delete(conn); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConnectionsConfigWidget::removeConnection(void) { if(connections_cmb->currentIndex() >= 0) { Connection *conn=nullptr; conn=connections.at(connections_cmb->currentIndex()); connections.erase(connections.begin() + connections_cmb->currentIndex()); connections_cmb->removeItem(connections_cmb->currentIndex()); delete(conn); this->newConnection(); setConfigurationChanged(true); } } void ConnectionsConfigWidget::editConnection(void) { if(connections_cmb->count() > 0) { Connection *conn=nullptr; conn=connections.at(connections_cmb->currentIndex()); alias_edt->setText(conn->getConnectionParam(Connection::ParamAlias)); auto_browse_chk->setChecked(conn->isAutoBrowseDB()); diff_chk->setChecked(conn->isDefaultForOperation(Connection::OpDiff)); export_chk->setChecked(conn->isDefaultForOperation(Connection::OpExport)); import_chk->setChecked(conn->isDefaultForOperation(Connection::OpImport)); validation_chk->setChecked(conn->isDefaultForOperation(Connection::OpValidation)); if(!conn->getConnectionParam(Connection::ParamServerFqdn).isEmpty()) host_edt->setText(conn->getConnectionParam(Connection::ParamServerFqdn)); else host_edt->setText(conn->getConnectionParam(Connection::ParamServerIp)); conn_db_edt->setText(conn->getConnectionParam(Connection::ParamDbName)); user_edt->setText(conn->getConnectionParam(Connection::ParamUser)); passwd_edt->setText(conn->getConnectionParam(Connection::ParamPassword)); port_sbp->setValue(conn->getConnectionParam(Connection::ParamPort).toInt()); timeout_sbp->setValue(conn->getConnectionParam(Connection::ParamConnTimeout).toInt()); krb_server_edt->setText(conn->getConnectionParam(Connection::ParamKerberosServer)); gssapi_auth_chk->setChecked(conn->getConnectionParam(Connection::ParamLibGssapi)==QString("gssapi")); other_params_edt->setText(conn->getConnectionParam(Connection::ParamOthers)); if(conn->getConnectionParam(Connection::ParamSslMode)==Connection::SslDisable) ssl_mode_cmb->setCurrentIndex(0); else if(conn->getConnectionParam(Connection::ParamSslMode)==Connection::SslAllow) ssl_mode_cmb->setCurrentIndex(1); else if(conn->getConnectionParam(Connection::ParamSslMode)==Connection::SslRequire) ssl_mode_cmb->setCurrentIndex(2); else if(conn->getConnectionParam(Connection::ParamSslMode)==Connection::SslCaVerify) ssl_mode_cmb->setCurrentIndex(3); else ssl_mode_cmb->setCurrentIndex(4); if(ssl_mode_cmb->currentIndex() > 0) { client_cert_edt->setText(conn->getConnectionParam(Connection::ParamSslCert)); root_cert_edt->setText(conn->getConnectionParam(Connection::ParamSslRootCert)); client_key_edt->setText(conn->getConnectionParam(Connection::ParamSslKey)); crl_edt->setText(conn->getConnectionParam(Connection::ParamSslCrl)); } update_tb->setVisible(true); add_tb->setVisible(false); connections_cmb->setEnabled(false); new_tb->setVisible(false); duplicate_tb->setEnabled(false); cancel_tb->setVisible(true); edit_tb->setEnabled(false); } } void ConnectionsConfigWidget::configureConnection(Connection *conn) { if(conn) { conn->setAutoBrowseDB(auto_browse_chk->isChecked()); conn->setConnectionParam(Connection::ParamAlias, alias_edt->text()); conn->setConnectionParam(Connection::ParamServerIp, QString()); conn->setConnectionParam(Connection::ParamServerFqdn, host_edt->text()); conn->setConnectionParam(Connection::ParamPort, QString("%1").arg(port_sbp->value())); conn->setConnectionParam(Connection::ParamUser, user_edt->text()); conn->setConnectionParam(Connection::ParamPassword, passwd_edt->text()); conn->setConnectionParam(Connection::ParamDbName, conn_db_edt->text()); conn->setConnectionParam(Connection::ParamConnTimeout, QString("%1").arg(timeout_sbp->value())); conn->setDefaultForOperation(Connection::OpDiff, diff_chk->isChecked()); conn->setDefaultForOperation(Connection::OpExport, export_chk->isChecked()); conn->setDefaultForOperation(Connection::OpImport, import_chk->isChecked()); conn->setDefaultForOperation(Connection::OpValidation, validation_chk->isChecked()); switch(ssl_mode_cmb->currentIndex()) { case 1: conn->setConnectionParam(Connection::ParamSslMode, Connection::SslAllow); break; case 2: conn->setConnectionParam(Connection::ParamSslMode, Connection::SslRequire); break; case 3: conn->setConnectionParam(Connection::ParamSslMode, Connection::SslCaVerify); break; case 4: conn->setConnectionParam(Connection::ParamSslMode, Connection::SslFullVerify); break; default: case 0: conn->setConnectionParam(Connection::ParamSslMode, Connection::SslDisable); break; } if(ssl_mode_cmb->currentIndex()!=0) { conn->setConnectionParam(Connection::ParamSslRootCert, root_cert_edt->text()); conn->setConnectionParam(Connection::ParamSslCert, client_cert_edt->text()); conn->setConnectionParam(Connection::ParamSslKey, client_key_edt->text()); conn->setConnectionParam(Connection::ParamSslCrl, crl_edt->text()); } if(gssapi_auth_chk->isChecked()) conn->setConnectionParam(Connection::ParamLibGssapi, QString("gssapi")); if(!krb_server_edt->text().isEmpty()) conn->setConnectionParam(Connection::ParamKerberosServer, krb_server_edt->text()); if(!other_params_edt->text().isEmpty()) conn->setConnectionParam(Connection::ParamOthers, other_params_edt->text()); } } void ConnectionsConfigWidget::testConnection(void) { Connection conn; Messagebox msg_box; attribs_map srv_info; try { this->configureConnection(&conn); conn.connect(); srv_info=conn.getServerInfo(); msg_box.show(trUtf8("Success"), PgModelerUiNs::formatMessage(trUtf8("Connection successfully established!\n\nServer details:\n\nPID: `%1'\nProtocol: `%2'\nVersion: `%3'")) .arg(srv_info[Connection::ServerPid]) .arg(srv_info[Connection::ServerProtocol]) .arg(srv_info[Connection::ServerVersion]), Messagebox::InfoIcon); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConnectionsConfigWidget::restoreDefaults(void) { try { //Restore the default connection config file BaseConfigWidget::restoreDefaults(GlobalAttributes::ConnectionsConf, false); //Remove all connections while(connections_cmb->count() > 0) this->removeConnection(); //Reloads the configuration this->loadConfiguration(); updateConnectionsCombo(); this->setConfigurationChanged(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConnectionsConfigWidget::saveConfiguration(void) { try { attribs_map attribs; /* If add or update buttons are enabled when saving the configs indicates that user forgot to click on these buttons and register the connection, so in order to do not lost the data pgModeler will ask to save the connection. */ if(add_tb->isEnabled() || update_tb->isEnabled()) { Messagebox msg_box; msg_box.show(trUtf8("There is a connection being created or edited! Do you want to save it?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) handleConnection(); } config_params[GlobalAttributes::ConnectionsConf].clear(); /* Workaround: When there is no connection, to prevent saving an empty file, is necessary to fill the attribute CONNECTIONS with white spaces */ if(connections.empty()) config_params[GlobalAttributes::ConnectionsConf][Attributes::Connections]=QString(" "); else { for(Connection *conn : connections) { attribs=conn->getConnectionParams(); if(attribs[Connection::ParamServerFqdn].isEmpty()) attribs[Connection::ParamServerFqdn]=attribs[Connection::ParamServerIp]; attribs[Attributes::Alias]=attribs[Connection::ParamAlias]; attribs[Attributes::AutoBrowseDb]=(conn->isAutoBrowseDB() ? Attributes::True : QString()); attribs[Attributes::ConnectionTimeout]=attribs[Connection::ParamConnTimeout]; attribs[DefaultFor.arg(Attributes::Export)]=(conn->isDefaultForOperation(Connection::OpExport) ? Attributes::True : QString()); attribs[DefaultFor.arg(Attributes::Import)]=(conn->isDefaultForOperation(Connection::OpImport) ? Attributes::True : QString()); attribs[DefaultFor.arg(Attributes::Diff)]=(conn->isDefaultForOperation(Connection::OpDiff) ? Attributes::True : QString()); attribs[DefaultFor.arg(Attributes::Validation)]=(conn->isDefaultForOperation(Connection::OpValidation) ? Attributes::True : QString()); schparser.ignoreUnkownAttributes(true); config_params[GlobalAttributes::ConnectionsConf][Attributes::Connections]+= schparser.getCodeDefinition(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + GlobalAttributes::ConnectionsConf + GlobalAttributes::SchemaExt, attribs); schparser.ignoreUnkownAttributes(false); } } schparser.ignoreUnkownAttributes(true); BaseConfigWidget::saveConfiguration(GlobalAttributes::ConnectionsConf, config_params); schparser.ignoreUnkownAttributes(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConnectionsConfigWidget::getConnections(map &conns, bool inc_hosts) { QString alias; conns.clear(); for(Connection *conn : connections) { alias=conn->getConnectionId(); if(!inc_hosts) alias.remove(QRegExp(QString(" \\((.)*\\)"))); conns[alias]=conn; } } Connection *ConnectionsConfigWidget::getConnection(const QString &conn_id) { for(Connection *conn : connections) { if(conn->getConnectionId() == conn_id) return(conn); } return(nullptr); } void ConnectionsConfigWidget::fillConnectionsComboBox(QComboBox *combo, bool incl_placeholder, unsigned check_def_for) { map connections; Connection *def_conn=nullptr; if(!combo) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); getConnections(connections); combo->blockSignals(true); combo->clear(); if(incl_placeholder) { if(!connections.empty()) combo->addItem(trUtf8("Found %1 connection(s)").arg(connections.size())); else combo->addItem(trUtf8("No connections found")); } for(auto &itr : connections) { combo->addItem(QIcon(PgModelerUiNs::getIconPath("server")), itr.first, QVariant::fromValue(itr.second)); if(!def_conn && itr.second->isDefaultForOperation(check_def_for)) def_conn=itr.second; } if(incl_placeholder) combo->addItem(QIcon(QString(":icones/icones/conexaobd.png")), trUtf8("Edit connections")); if(def_conn) combo->setCurrentText(def_conn->getConnectionId()); combo->blockSignals(false); } bool ConnectionsConfigWidget::openConnectionsConfiguration(QComboBox *combo, bool incl_placeholder) { if(combo) { BaseForm parent_form; ConnectionsConfigWidget conn_cfg_wgt; bool conn_saved = false; parent_form.setWindowTitle(trUtf8("Edit database connections")); parent_form.setWindowFlags(Qt::Dialog | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint); connect(parent_form.cancel_btn, SIGNAL(clicked(bool)), &parent_form, SLOT(reject())); connect(parent_form.apply_ok_btn, SIGNAL(clicked(bool)), &parent_form, SLOT(accept())); try { conn_cfg_wgt.loadConfiguration(); conn_cfg_wgt.frame->setFrameShape(QFrame::NoFrame); conn_cfg_wgt.frame->layout()->setContentsMargins(2,2,2,2); parent_form.setMainWidget(&conn_cfg_wgt); parent_form.setButtonConfiguration(Messagebox::OkCancelButtons); parent_form.exec(); if(parent_form.result()==QDialog::Accepted) { conn_cfg_wgt.saveConfiguration(); conn_saved=true; } conn_cfg_wgt.fillConnectionsComboBox(combo, incl_placeholder); } catch(Exception &e) { combo->setCurrentIndex(0); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } return(conn_saved); } return(false); } Connection *ConnectionsConfigWidget::getDefaultConnection(unsigned operation) { Connection *conn=nullptr; for(Connection *aux_conn : connections) { if(aux_conn->isDefaultForOperation(operation)) { conn=aux_conn; break; } } return(conn); } pgmodeler-0.9.2/libpgmodeler_ui/src/connectionsconfigwidget.h000066400000000000000000000066051360462764600245430ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ConnectionsConfigWidget \brief Implements the operations to manage database connections. */ #ifndef CONNECTIONS_CONFIG_WIDGET_H #define CONNECTIONS_CONFIG_WIDGET_H #include "ui_connectionsconfigwidget.h" #include "baseconfigwidget.h" #include "connection.h" #include "messagebox.h" #include "hinttextwidget.h" class ConnectionsConfigWidget: public BaseConfigWidget, public Ui::ConnectionsConfigWidget { private: Q_OBJECT HintTextWidget *auto_browse_ht, *default_for_ops_ht, *other_params_ht; static const QString DefaultFor; //! \brief Stores the connections created by the user static vector connections; /*! \brief Stores the connections attributes. This map is used to write the connections.conf file as well to create the connections stored by the 'connections' vector */ static map config_params; //! \brief Configures the passed connection setting it's attributes using the values from the form void configureConnection(Connection *conn); void hideEvent(QHideEvent *); void showEvent(QShowEvent *); void updateConnectionsCombo(void); public: ConnectionsConfigWidget(QWidget * parent = nullptr); ~ConnectionsConfigWidget(void); void saveConfiguration(void); void loadConfiguration(void); static map getConfigurationParams(void); //! \brief Fills the passed map with all the loaded connections. static void getConnections(map &conns, bool inc_hosts=true); //! \brief Return a connection with the provided ID. If no connection is found the method returns nullptr static Connection *getConnection(const QString &conn_id); //! \brief Fills the passed combobox with all the loaded connections static void fillConnectionsComboBox(QComboBox *combo, bool incl_placeholder, unsigned check_def_for=Connection::OpNone); //! \brief Opens a local instance of connection config dialog to permit user configures connections on-the-fly static bool openConnectionsConfiguration(QComboBox *combo, bool incl_placeholder); //! \brief Returns the first connection found which is defined as the default for the specified operation static Connection *getDefaultConnection(unsigned operation); protected: void destroyConnections(void); public slots: void restoreDefaults(void); private slots: void newConnection(void); void duplicateConnection(void); void handleConnection(void); void editConnection(void); void testConnection(void); void removeConnection(void); void enableCertificates(void); void enableConnectionTest(void); void applyConfiguration(void){} friend class ConfigurationForm; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/constraintwidget.cpp000066400000000000000000000436731360462764600235600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "constraintwidget.h" ConstraintWidget::ConstraintWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Constraint) { try { QStringList list; map > fields_map; map > values_map; QGridLayout *grid=nullptr; Ui_ConstraintWidget::setupUi(this); excl_elems_tab=new ElementsTableWidget(this); grid=new QGridLayout; grid->setContentsMargins(4,4,4,4); grid->addWidget(excl_elems_tab,0,0); excl_elems_grp->setLayout(grid); expression_hl=new SyntaxHighlighter(expression_txt, false, true); expression_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); columns_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton | ObjectsTableWidget::DuplicateButton), true, this); ref_columns_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton | ObjectsTableWidget::DuplicateButton), true, this); ref_table_sel=new ObjectSelectorWidget(ObjectType::Table, true, this); columns_tab->setColumnCount(2); columns_tab->setHeaderLabel(trUtf8("Column"), 0); columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); columns_tab->setHeaderLabel(trUtf8("Type"), 1); columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); ref_columns_tab->setEnabled(false); ref_columns_tab->setColumnCount(2); ref_columns_tab->setHeaderLabel(trUtf8("Column"), 0); ref_columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); ref_columns_tab->setHeaderLabel(trUtf8("Type"), 1); ref_columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); dynamic_cast(columns_tbw->widget(0)->layout())->addWidget(columns_tab, 1,0,1,3); dynamic_cast(columns_tbw->widget(1)->layout())->addWidget(ref_table_sel, 0,1,1,2); dynamic_cast(columns_tbw->widget(1)->layout())->addWidget(ref_columns_tab, 3,0,1,3); configureFormLayout(constraint_grid, ObjectType::Constraint); ConstraintType::getTypes(list); constr_type_cmb->addItems(list); MatchType::getTypes(list); match_cmb->addItems(list); DeferralType::getTypes(list); deferral_cmb->addItems(list); ActionType::getTypes(list); on_delete_cmb->addItems(list); on_update_cmb->addItems(list); IndexingType::getTypes(list); indexing_cmb->addItems(list); info_frm=generateInformationFrame(trUtf8("Columns which were included by relationship can not be added / removed manually from the primary key. If done such changes they can raise errors. To create primary key using columns included by relationship use the following options: identifier field, attributes & constraints tab or primary key tab on the relationship form.")); constraint_grid->addWidget(info_frm, constraint_grid->count()+1, 0, 1, 0); info_frm->setParent(this); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion92)].push_back(no_inherit_lbl); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(indexing_chk); values_map[indexing_chk].push_back(~IndexingType(IndexingType::Brin)); warn_frm=generateVersionWarningFrame(fields_map, &values_map); constraint_grid->addWidget(warn_frm, constraint_grid->count()+1, 0, 1, 0); warn_frm->setParent(this); //connect(parent_form->apply_ok_btn,SIGNAL(clicked(bool)), this, SLOT(applyConfiguration(void))); connect(constr_type_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(selectConstraintType(void))); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_cmb, SLOT(setEnabled(bool))); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_lbl, SLOT(setEnabled(bool))); connect(indexing_chk, SIGNAL(toggled(bool)), indexing_cmb, SLOT(setEnabled(bool))); connect(columns_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addColumn(int))); connect(columns_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removeColumn(int))); connect(columns_tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removeColumns(void))); connect(ref_columns_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addColumn(int))); connect(ref_columns_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removeColumn(int))); connect(ref_columns_tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removeColumns(void))); connect(ref_table_sel, SIGNAL(s_selectorCleared(void)), this, SLOT(selectReferencedTable(void))); connect(ref_table_sel, SIGNAL(s_objectSelected(void)), this, SLOT(selectReferencedTable(void))); connect(fill_factor_chk, SIGNAL(toggled(bool)), fill_factor_sb, SLOT(setEnabled(bool))); selectConstraintType(); configureTabOrder(); setMinimumSize(540, 600); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConstraintWidget::addColumn(int row) { QObject *sender_obj=sender(); ObjectsTableWidget *aux_col_tab=nullptr; QComboBox *combo=nullptr; Column *column=nullptr; unsigned col_id; try { if(sender_obj==columns_tab) { aux_col_tab=columns_tab; combo=column_cmb; col_id=Constraint::SourceCols; } else { aux_col_tab=ref_columns_tab; combo=ref_column_cmb; col_id=Constraint::ReferencedCols; } //Gets the reference to the selected column column=reinterpret_cast(combo->itemData(combo->currentIndex(),Qt::UserRole).value()); //When the column is selected it will be removed from combo combo->removeItem(combo->currentIndex()); //Adds the column into table addColumn(column, col_id, row); //When there is no items con the combo the insert button of the table is disabled aux_col_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (combo->count()!=0)); } catch(Exception &e) { aux_col_tab->removeRow(row); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConstraintWidget::removeColumn(int) { if(sender()==columns_tab) updateColumnsCombo(Constraint::SourceCols); else updateColumnsCombo(Constraint::ReferencedCols); } void ConstraintWidget::removeColumns(void) { if(sender()==columns_tab) updateColumnsCombo(Constraint::SourceCols); else updateColumnsCombo(Constraint::ReferencedCols); } void ConstraintWidget::addColumn(Column *column, unsigned col_id, int row) { ObjectsTableWidget *table_wgt=nullptr; if(column && row >= 0) { if(col_id==Constraint::SourceCols) table_wgt=columns_tab; else table_wgt=ref_columns_tab; table_wgt->setCellText(column->getName(),row,0); table_wgt->setCellText(~column->getType(),row,1); table_wgt->setRowData(QVariant::fromValue(column), row); //Change the table row background color if the column is protected or added by relationship if(column->isAddedByRelationship() || column->isProtected()) { QFont fonte; fonte=table_wgt->font(); fonte.setItalic(true); if(column->isProtected()) table_wgt->setRowFont(row, fonte, ProtRowFgColor, ProtRowBgColor); else table_wgt->setRowFont(row, fonte, RelAddedRowFgColor, RelAddedRowBgColor); } } } void ConstraintWidget::updateColumnsCombo(unsigned col_id) { ObjectsTableWidget *aux_col_tab=nullptr; Column *column=nullptr; PhysicalTable *table=nullptr; QComboBox *combo=nullptr; Relationship *rel=nullptr; unsigned i, count=0; try { if(col_id==Constraint::SourceCols) { combo=column_cmb; aux_col_tab=columns_tab; /* If the column to be edited does not belongs to a relationship means that the column is from a table */ if(!this->relationship) { table=dynamic_cast(this->table); count=table->getColumnCount(); } else { rel=this->relationship; count=rel->getAttributeCount(); } } else { combo=ref_column_cmb; aux_col_tab=ref_columns_tab; table=dynamic_cast(ref_table_sel->getSelectedObject()); if(table) count=table->getColumnCount(); } combo->clear(); for(i=0; i < count; i++) { if(rel) column=rel->getAttribute(i); else column=table->getColumn(i); //If the column does not exists on the column's table, adds it if(aux_col_tab->getRowIndex(QVariant::fromValue(column)) < 0) combo->addItem(column->getName() + QString(" (") + ~column->getType() + QString(")"), QVariant::fromValue(column)); } aux_col_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (combo->count()!=0)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConstraintWidget::selectReferencedTable(void) { Table *table=dynamic_cast

(ref_table_sel->getSelectedObject()); if(!table || (this->object && dynamic_cast(this->object)->getReferencedTable() != table)) { ref_columns_tab->blockSignals(true); ref_columns_tab->removeRows(); ref_columns_tab->setEnabled(false); ref_columns_tab->blockSignals(false); } if(!table) ref_column_cmb->clear(); else { ref_columns_tab->setEnabled(true); updateColumnsCombo(Constraint::ReferencedCols); } } void ConstraintWidget::selectConstraintType(void) { ConstraintType constr_type=ConstraintType(constr_type_cmb->currentText()); tablespace_lbl->setVisible(constr_type==ConstraintType::PrimaryKey || constr_type==ConstraintType::Unique); tablespace_sel->setVisible(constr_type==ConstraintType::PrimaryKey || constr_type==ConstraintType::Unique); if(!tablespace_sel->isVisible()) tablespace_sel->clearSelector(); expression_lbl->setVisible(constr_type==ConstraintType::Check || constr_type==ConstraintType::Exclude); expression_txt->setVisible(constr_type==ConstraintType::Check || constr_type==ConstraintType::Exclude); no_inherit_chk->setVisible(constr_type==ConstraintType::Check); no_inherit_lbl->setVisible(constr_type==ConstraintType::Check); warn_frm->setVisible(constr_type==ConstraintType::Check); fill_factor_chk->setVisible(constr_type==ConstraintType::Unique || constr_type==ConstraintType::PrimaryKey || constr_type==ConstraintType::Exclude); fill_factor_sb->setVisible(constr_type==ConstraintType::Unique || constr_type==ConstraintType::PrimaryKey || constr_type==ConstraintType::Exclude); info_frm->setVisible(constr_type==ConstraintType::PrimaryKey); deferrable_lbl->setVisible(constr_type!=ConstraintType::Check); deferrable_chk->setVisible(constr_type!=ConstraintType::Check); deferral_cmb->setVisible(constr_type!=ConstraintType::Check); deferral_lbl->setVisible(constr_type!=ConstraintType::Check); match_lbl->setVisible(constr_type==ConstraintType::ForeignKey); match_cmb->setVisible(constr_type==ConstraintType::ForeignKey); on_delete_cmb->setVisible(constr_type==ConstraintType::ForeignKey); on_delete_lbl->setVisible(constr_type==ConstraintType::ForeignKey); on_update_cmb->setVisible(constr_type==ConstraintType::ForeignKey); on_update_lbl->setVisible(constr_type==ConstraintType::ForeignKey); columns_tbw->setVisible(constr_type!=ConstraintType::Check && constr_type!=ConstraintType::Exclude); indexing_chk->setVisible(constr_type==ConstraintType::Exclude); indexing_cmb->setVisible(constr_type==ConstraintType::Exclude); if(constr_type!=ConstraintType::ForeignKey) { columns_tbw->setTabEnabled(1, false); columns_tbw->setCurrentIndex(0); ref_table_sel->clearSelector(); } else columns_tbw->setTabEnabled(1, true); excl_elems_grp->setVisible(constr_type==ConstraintType::Exclude); } void ConstraintWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *parent_obj, Constraint *constr) { ObjectType obj_type; unsigned row = 0; Table *ref_table=nullptr; vector excl_elems; if(!parent_obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); obj_type = parent_obj->getObjectType(); if(!PhysicalTable::isPhysicalTable(obj_type) && obj_type!=ObjectType::Relationship) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, constr, parent_obj); info_frm->setVisible(this->table!=nullptr); ref_table_sel->setModel(model); columns_tab->blockSignals(true); if(constr) { row = 0; for(auto column : constr->getColumns(Constraint::SourceCols)) { columns_tab->addRow(); addColumn(column, Constraint::SourceCols, row); row++; } } updateColumnsCombo(Constraint::SourceCols); columns_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (column_cmb->count()!=0)); columns_tab->blockSignals(false); if(constr) { excl_elems = constr->getExcludeElements(); indexing_chk->setChecked(constr->getIndexType()!=BaseType::Null); indexing_cmb->setCurrentIndex(indexing_cmb->findText(~constr->getIndexType())); constr_type_cmb->setCurrentIndex(constr_type_cmb->findText(~constr->getConstraintType())); constr_type_cmb->setEnabled(false); constr_type_lbl->setEnabled(false); expression_txt->setPlainText(constr->getExpression()); no_inherit_chk->setChecked(constr->isNoInherit()); deferrable_chk->setChecked(constr->isDeferrable()); deferral_cmb->setCurrentIndex(deferral_cmb->findText(~constr->getDeferralType())); match_cmb->setCurrentIndex(match_cmb->findText(~constr->getMatchType())); on_delete_cmb->setCurrentIndex(on_delete_cmb->findText(~constr->getActionType(Constraint::DeleteAction))); on_update_cmb->setCurrentIndex(on_update_cmb->findText(~constr->getActionType(Constraint::UpdateAction))); fill_factor_chk->setChecked(constr->getFillFactor()!=0); if(fill_factor_chk->isChecked()) fill_factor_sb->setValue(constr->getFillFactor()); ref_table=dynamic_cast
(constr->getReferencedTable()); if(ref_table) { ref_columns_tab->blockSignals(true); ref_table_sel->setSelectedObject(ref_table); row = 0; for(auto column : constr->getColumns(Constraint::ReferencedCols)) { ref_columns_tab->addRow(); addColumn(column, Constraint::ReferencedCols, row); row++; } updateColumnsCombo(Constraint::ReferencedCols); ref_columns_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (column_cmb->count()!=0)); ref_columns_tab->blockSignals(false); } } excl_elems_tab->setAttributes(model, parent_obj); excl_elems_tab->setElements(excl_elems); } void ConstraintWidget::applyConfiguration(void) { try { Constraint *constr=nullptr; unsigned i, col_id, count; Column *column=nullptr; ObjectsTableWidget *aux_col_tab=nullptr; vector excl_elems; startConfiguration(); constr=dynamic_cast(this->object); constr->setConstraintType(ConstraintType(constr_type_cmb->currentText())); constr->setExpression(expression_txt->toPlainText().toUtf8()); if(fill_factor_chk->isChecked()) constr->setFillFactor(fill_factor_sb->value()); else constr->setFillFactor(0); constr->setMatchType(MatchType(match_cmb->currentText())); constr->setDeferrable(deferrable_chk->isChecked()); constr->setDeferralType(DeferralType(deferral_cmb->currentText())); constr->setActionType(ActionType(on_delete_cmb->currentText()),Constraint::DeleteAction); constr->setActionType(ActionType(on_update_cmb->currentText()),Constraint::UpdateAction); constr->setNoInherit(no_inherit_chk->isChecked()); if(indexing_chk->isChecked()) constr->setIndexType(IndexingType(indexing_cmb->currentText())); else constr->setIndexType(BaseType::Null); if(constr->getConstraintType()==ConstraintType::ForeignKey) constr->setReferencedTable(dynamic_cast(ref_table_sel->getSelectedObject())); constr->removeColumns(); for(col_id=Constraint::SourceCols; col_id <= Constraint::ReferencedCols; col_id++) { aux_col_tab=(col_id==Constraint::SourceCols ? columns_tab : ref_columns_tab); count=aux_col_tab->getRowCount(); for(i=0; i < count; i++) { column=reinterpret_cast(aux_col_tab->getRowData(i).value()); constr->addColumn(column, col_id); } } excl_elems_tab->getElements(excl_elems); constr->addExcludeElements(excl_elems); //Raises an error if the user try to create a primary key that has columns added by relationship (not supported) if(constr->getConstraintType()==ConstraintType::PrimaryKey && constr->isReferRelationshipAddedColumn()) throw Exception(ErrorCode::UnsupportedPKColsAddedByRel,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::applyConfiguration(); /* Raises an error if the constraint type requires at least one column to be assinged and there is no columns configured on the form */ if(((constr->getConstraintType()==ConstraintType::ForeignKey || constr->getConstraintType()==ConstraintType::PrimaryKey) && constr->getColumnCount(Constraint::SourceCols)==0) || (constr->getConstraintType()==ConstraintType::ForeignKey && constr->getColumnCount(Constraint::ReferencedCols)==0)) throw Exception(ErrorCode::InvConstratintNoColumns,__PRETTY_FUNCTION__,__FILE__,__LINE__); finishConfiguration(); //For the foreign keys, updates the fk relationships on the model if(constr->getConstraintType()==ConstraintType::ForeignKey) this->model->updateTableFKRelationships(dynamic_cast
(this->table)); } catch(Exception &e) { Messagebox msg_box; cancelConfiguration(); msg_box.show(e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/constraintwidget.h000066400000000000000000000046151360462764600232160ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ConstraintWidget \brief Implements the operations to create/edit constraints via form. */ #ifndef CONSTRAINT_WIDGET_H #define CONSTRAINT_WIDGET_H #include "baseobjectwidget.h" #include "ui_constraintwidget.h" #include "objectstablewidget.h" #include "messagebox.h" #include "elementstablewidget.h" class ConstraintWidget: public BaseObjectWidget, public Ui::ConstraintWidget { private: Q_OBJECT QFrame *info_frm, *warn_frm; SyntaxHighlighter *expression_hl; ElementsTableWidget *excl_elems_tab; /*! \brief Table widgets used to store the columns that forms the constraint as well the referenced columns (only for foreign keys) */ ObjectsTableWidget *columns_tab, *ref_columns_tab; //! \brief Referenced table selector ObjectSelectorWidget *ref_table_sel; //! \brief Updates the column combo according to the column id. (Constraint::[SOURCE_COLS | REFERENCED_COLS]) void updateColumnsCombo(unsigned col_id); //! \brief Adds the column to the column's table at the specified row void addColumn(Column *column, unsigned col_id, int row); public: ConstraintWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *parent_obj, Constraint *constr); private slots: //! \brief Shows only the fields related to the selected constraint type void selectConstraintType(void); //! \brief Selects the referenced table as well updates the combo containing the referenced table columns void selectReferencedTable(void); void addColumn(int row); void removeColumn(int); void removeColumns(void); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/conversionwidget.cpp000066400000000000000000000064651360462764600235570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "conversionwidget.h" ConversionWidget::ConversionWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Conversion) { try { QFrame *frame=nullptr; QStringList encodings; Ui_ConversionWidget::setupUi(this); conv_func_sel=nullptr; conv_func_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); convcod_grid->addWidget(conv_func_sel,1,1,1,3); setRequiredField(src_encoding_lbl); setRequiredField(trg_encoding_lbl); setRequiredField(conv_func_lbl); setRequiredField(conv_func_sel); configureFormLayout(convcod_grid, ObjectType::Conversion); frame=generateInformationFrame(trUtf8("The function to be assigned to an encoding conversion must have the following signature: void function(integer, integer, cstring, internal, integer).")); convcod_grid->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding), convcod_grid->count()+1, 0, 1, 0); convcod_grid->addWidget(frame, convcod_grid->count()+1, 0, 1, 0); frame->setParent(this); EncodingType::getTypes(encodings); src_encoding_cmb->addItems(encodings); trg_encoding_cmb->addItems(encodings); configureTabOrder({ src_encoding_cmb, trg_encoding_cmb, conv_func_sel }); setMinimumSize(500, 300); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ConversionWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Conversion *conv) { BaseObjectWidget::setAttributes(model, op_list, conv, schema); conv_func_sel->setModel(model); if(conv) { conv_func_sel->setSelectedObject(conv->getConversionFunction()); default_conv_chk->setChecked(conv->isDefault()); src_encoding_cmb->setCurrentIndex(trg_encoding_cmb->findText(~(conv->getEncoding(Conversion::SrcEncoding)))); trg_encoding_cmb->setCurrentIndex(trg_encoding_cmb->findText(~(conv->getEncoding(Conversion::DstEncoding)))); } } void ConversionWidget::applyConfiguration(void) { try { Conversion *conv=nullptr; startConfiguration(); conv=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); conv->setEncoding(Conversion::SrcEncoding, src_encoding_cmb->currentText()); conv->setEncoding(Conversion::DstEncoding, trg_encoding_cmb->currentText()); conv->setDefault(default_conv_chk->isChecked()); conv->setConversionFunction(dynamic_cast(conv_func_sel->getSelectedObject())); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/conversionwidget.h000066400000000000000000000025261360462764600232160ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ConversionWidget \brief Implements the operations to create/edit encoding conversions via form. */ #ifndef CONVERSION_WIDGET_H #define CONVERSION_WIDGET_H #include "baseobjectwidget.h" #include "ui_conversionwidget.h" class ConversionWidget: public BaseObjectWidget, public Ui::ConversionWidget { private: Q_OBJECT ObjectSelectorWidget *conv_func_sel; public: ConversionWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Conversion *conv); private slots: public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/csvloadwidget.cpp000066400000000000000000000162071360462764600230200ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "csvloadwidget.h" #include #include "exception.h" #include CsvLoadWidget::CsvLoadWidget(QWidget * parent, bool cols_in_first_row) : QWidget(parent) { setupUi(this); separator_edt->setVisible(false); if(!cols_in_first_row) { col_names_ht=new HintTextWidget(col_names_hint, this); col_names_ht->setText(col_names_chk->statusTip()); } else { col_names_ht=nullptr; col_names_chk->setVisible(false); col_names_chk->setChecked(true); } connect(select_file_tb, SIGNAL(clicked(bool)), this, SLOT(selectCsvFile())); connect(txt_delim_chk, SIGNAL(toggled(bool)), txt_delim_edt, SLOT(setEnabled(bool))); connect(load_btn, SIGNAL(clicked(bool)), this, SLOT(loadCsvFile())); connect(separator_cmb, &QComboBox::currentTextChanged, [&](){ separator_edt->setVisible(separator_cmb->currentIndex() == separator_cmb->count()-1); }); connect(file_edt, &QLineEdit::textChanged, [&](){ load_btn->setEnabled(!file_edt->text().isEmpty()); }); } QStringList CsvLoadWidget::getCsvColumns(void) { return(csv_columns); } QList CsvLoadWidget::getCsvRows(void) { return(csv_rows); } void CsvLoadWidget::selectCsvFile(void) { QFileDialog file_dlg; file_dlg.setWindowTitle(trUtf8("Load CSV file")); file_dlg.setModal(true); file_dlg.setNameFilter(trUtf8("Comma-separted values (*.csv);;All files (*.*)")); if(file_dlg.exec()==QFileDialog::Accepted) { QString file; if(!file_dlg.selectedFiles().isEmpty()) file = file_dlg.selectedFiles().at(0); file_edt->setText(file); } } QList CsvLoadWidget::loadCsvFromBuffer(const QString &csv_buffer, const QString &separator, const QString &text_delim, bool cols_in_first_row, QStringList &csv_cols) { QList csv_rows; if(!csv_buffer.isEmpty()) { QString double_quote=QString("%1%1").arg(text_delim), placeholder = QString(QChar::ReplacementCharacter), escaped_delim = QString("\u2020"), //Unicode char to be used as a placeholder for escaped text delimiter, e.g., \" escaped_sep = QString("\u2052"), //Unicode char to be used as a placeholder for escaped value separator, e.g., \; aux_buffer = csv_buffer, win_line_break = QString("%1%2").arg(QChar(QChar::CarriageReturn)).arg(QChar(QChar::LineFeed)), mac_line_break = QString("%1").arg(QChar(QChar::CarriageReturn)); QStringList values, rows; QRegExp empty_val; if(aux_buffer.contains(win_line_break)) aux_buffer.replace(win_line_break, QString(QChar::LineFeed)); else if(aux_buffer.contains(mac_line_break)) aux_buffer.replace(mac_line_break, QString(QChar::LineFeed)); /* In order to avoid wrong replacement of escapade both text delimiter and value separator * we replace them by their respective placeholders in order to revert them back to their * original representation on the final (formated) string */ aux_buffer.replace(QString("\\%1").arg(text_delim), escaped_delim); aux_buffer.replace(QString("\\%1").arg(separator), escaped_sep); if(cols_in_first_row) { int lf_idx = aux_buffer.indexOf(QChar::LineFeed); if(lf_idx < 0) lf_idx = aux_buffer.size(); csv_cols=aux_buffer.mid(0, lf_idx).split(separator); csv_cols.replaceInStrings(text_delim, QString()); //Replace the escaped separator and delimiter by their original form in the col names csv_cols.replaceInStrings(escaped_sep, separator); csv_cols.replaceInStrings(escaped_delim, text_delim); aux_buffer.replace(0, lf_idx + 1, QString()); } aux_buffer.replace(QString("%1%2").arg(QChar(QChar::LineFeed)).arg(text_delim), placeholder); rows = aux_buffer.split(placeholder, QString::SkipEmptyParts); //Configuring an regexp to remove empty quoted values, e.g, "", if(!text_delim.isEmpty()) empty_val = QRegExp(QString("(\\%1\\%1)(\\%2)").arg(text_delim).arg(separator)); for(QString row : rows) { if(!empty_val.pattern().isEmpty()) row.replace(empty_val, separator); /* In order to preserve double quotes (double delimiters) inside the values, * we first replace them by a placeholder, erase the delimiters and restore the previous value */ row.replace(double_quote, placeholder); row.replace(text_delim, QString()); row.replace(placeholder, double_quote); values = row.split(separator); for(int i =0; i < values.count(); i++) { //Replace the escaped separator and delimiter by their original form in the final value values[i].replace(escaped_sep, separator); values[i].replace(escaped_delim, text_delim); values[i] = values[i].trimmed(); } csv_rows.append(values); } } return (csv_rows); } void CsvLoadWidget::loadCsvFile(void) { QFile file; QString csv_buffer; file.setFileName(file_edt->text()); if(!file.open(QFile::ReadOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(file_edt->text()), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); csv_columns.clear(); csv_rows.clear(); csv_buffer.append(file.readAll()); if(!csv_buffer.isEmpty()) { csv_rows = loadCsvFromBuffer(csv_buffer, getSeparator(), txt_delim_chk->isChecked() ? txt_delim_edt->text() : QString(), col_names_chk->isChecked(), csv_columns); } file_edt->clear(); emit s_csvFileLoaded(); } QString CsvLoadWidget::getSeparator(void) { QStringList separators={ QString(";"), QString(","), QString(" "), QString("\t") }; separators += (separator_edt->text().isEmpty() ? QString(";") : separator_edt->text()); return(separators[separator_cmb->currentIndex()]); } QString CsvLoadWidget::getCsvBuffer(QString separator, QString line_break) { QString buffer; QStringList rows; if(separator.isEmpty()) separator = QString(";"); if(line_break.isEmpty()) line_break = QString("\n"); buffer+=csv_columns.join(separator) + line_break; for(QStringList row : csv_rows) rows+=row.join(separator); buffer+=rows.join(line_break); return(buffer); } bool CsvLoadWidget::isColumnsInFirstRow(void) { return(col_names_chk->isChecked()); } void CsvLoadWidget::loadCsvBuffer(const QString csv_buffer, const QString &separator, const QString &text_delim, bool cols_in_first_row) { csv_columns.clear(); csv_rows.clear(); csv_rows = loadCsvFromBuffer(csv_buffer, separator, text_delim, cols_in_first_row, csv_columns); } void CsvLoadWidget::loadCsvBuffer(const QString csv_buffer) { loadCsvBuffer(csv_buffer, getSeparator(), txt_delim_chk->isChecked() ? txt_delim_edt->text() : QString(), col_names_chk->isChecked()); } pgmodeler-0.9.2/libpgmodeler_ui/src/csvloadwidget.h000066400000000000000000000055241360462764600224650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class CsvLoadWidget \brief Implements basic features to load csv files and return the loaded buffer to the application */ #ifndef CSV_LOAD_WIDGET_H #define CSV_LOAD_WIDGET_H #include "ui_csvloadwidget.h" #include "hinttextwidget.h" #include class CsvLoadWidget : public QWidget, Ui::CsvLoadWidget { private: Q_OBJECT HintTextWidget *col_names_ht; //! \brief Holds the names of columns extracted from the csv file QStringList csv_columns; //! \brief Holds the rows extracted from the csv file QList csv_rows; public: CsvLoadWidget(QWidget * parent = nullptr, bool cols_in_first_row = true); //! \brief Returns the extracted columns QStringList getCsvColumns(void); //! \brief Returns the extracted rows QList getCsvRows(void); //! \brief Returns a formatted CSV buffer by specifying a custom separator and line break QString getCsvBuffer(QString separator, QString line_break); bool isColumnsInFirstRow(void); /*! \brief Loads a csv document from a buffer and stores the result in the internal csv_columns and csv_rows attributes for later usage. * The separator and text delimiter chars can be specified overriding the ones configured in the widget */ void loadCsvBuffer(const QString csv_buffer, const QString &separator, const QString &text_delim, bool cols_in_first_row); //! \brief Loads a csv document from a buffer and stores the result in the internal csv_columns and csv_rows attributes for later usage. void loadCsvBuffer(const QString csv_buffer); QString getSeparator(void); /*! \brief Loads a csv document from a buffer. The user can specify the value separator, text delimiter and an object which will store the column names. * In that case, the column names are only extracted from the first row if the cols_in_first_row is true */ static QList loadCsvFromBuffer(const QString &csv_buffer, const QString &separator, const QString &text_delim, bool cols_in_first_row, QStringList &csv_cols); private slots: void selectCsvFile(void); void loadCsvFile(void); signals: void s_csvFileLoaded(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/customsqlwidget.cpp000066400000000000000000000224441360462764600234170ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "customsqlwidget.h" #include "pgmodeleruins.h" CustomSQLWidget::CustomSQLWidget(QWidget *parent) : BaseObjectWidget(parent) { try { QFont font; Ui_CustomSQLWidget::setupUi(this); configureFormLayout(sqlappend_grid, ObjectType::BaseObject); append_sql_txt=PgModelerUiNs::createNumberedTextEditor(append_sql_wgt, true); prepend_sql_txt=PgModelerUiNs::createNumberedTextEditor(prepend_sql_wgt, true); append_sql_hl=new SyntaxHighlighter(append_sql_txt); append_sql_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); append_sql_cp=new CodeCompletionWidget(append_sql_txt, true); prepend_sql_hl=new SyntaxHighlighter(prepend_sql_txt); prepend_sql_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); prepend_sql_cp=new CodeCompletionWidget(prepend_sql_txt, true); name_edt->setReadOnly(true); comment_edt->setVisible(false); comment_lbl->setVisible(false); PgModelerUiNs::configureWidgetFont(message_lbl, PgModelerUiNs::MediumFontFactor); action_gen_insert=new QAction(trUtf8("Generic INSERT"), this); action_gen_insert->setObjectName(QString("action_gen_insert")); action_inc_serials=new QAction(trUtf8("Include serial columns"), this); action_inc_serials->setObjectName(QString("action_inc_serials")); action_exc_serials=new QAction(trUtf8("Exclude serial columns"), this); action_exc_serials->setObjectName(QString("action_exc_serials")); action_gen_select=new QAction(trUtf8("Generic SELECT"), this); action_gen_select->setObjectName(QString("action_gen_select")); action_tab_select=new QAction(trUtf8("Table SELECT"), this); action_tab_select->setObjectName(QString("action_tab_select")); action_gen_update=new QAction(trUtf8("Generic UPDATE"), this); action_gen_update->setObjectName(QString("action_gen_update")); action_tab_update=new QAction(trUtf8("Table UPDATE"), this); action_tab_update->setObjectName(QString("action_tab_update")); action_gen_delete=new QAction(trUtf8("Generic DELETE"), this); action_gen_delete->setObjectName(QString("action_gen_delete")); action_tab_delete=new QAction(trUtf8("Table DELETE"), this); action_tab_delete->setObjectName(QString("action_tab_delete")); insert_menu.addAction(action_inc_serials); insert_menu.addAction(action_exc_serials); insert_menu.addAction(action_gen_insert); select_menu.addAction(action_tab_select); select_menu.addAction(action_gen_select); update_menu.addAction(action_tab_update); update_menu.addAction(action_gen_update); delete_menu.addAction(action_tab_delete); delete_menu.addAction(action_gen_delete); connect(clear_tb, SIGNAL(clicked(bool)), this, SLOT(clearCode(void))); connect(insert_tb, SIGNAL(clicked(bool)), this, SLOT(addCommand(void))); connect(select_tb, SIGNAL(clicked(bool)), this, SLOT(addCommand(void))); connect(update_tb, SIGNAL(clicked(bool)), this, SLOT(addCommand(void))); connect(delete_tb, SIGNAL(clicked(bool)), this, SLOT(addCommand(void))); connect(action_gen_insert, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_inc_serials, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_exc_serials, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_gen_select, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_tab_select, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_gen_update, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_tab_update, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_gen_delete, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); connect(action_tab_delete, SIGNAL(triggered(void)), this, SLOT(addCommand(void))); setMinimumSize(640, 480); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void CustomSQLWidget::configureMenus(void) { ObjectType obj_type=this->object->getObjectType(); QToolButton *btns[]={ insert_tb, select_tb , delete_tb, update_tb }; int count=sizeof(btns)/sizeof(QToolButton *); for(int i=0; i < count; i++) btns[i]->setMenu(nullptr); if(BaseTable::isBaseTable(obj_type)) { if(PhysicalTable::isPhysicalTable(obj_type)) { insert_tb->setMenu(&insert_menu); delete_tb->setMenu(&delete_menu); update_tb->setMenu(&update_menu); } select_tb->setMenu(&select_menu); } } void CustomSQLWidget::setAttributes(DatabaseModel *model, BaseObject *object) { if(!object) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!BaseObject::acceptsCustomSQL(object->getObjectType())) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { BaseObjectWidget::setAttributes(model, object, nullptr); name_edt->setText(QString("%1 (%2)").arg(object->getSignature()).arg(object->getTypeName())); if(object->getObjectType()==ObjectType::Database) { end_of_model_chk->setChecked(dynamic_cast(object)->isAppendAtEOD()); begin_of_model_chk->setChecked(dynamic_cast(object)->isPrependedAtBOD()); } append_sql_txt->setFocus(); append_sql_txt->setPlainText(object->getAppendedSQL()); append_sql_cp->configureCompletion(model, append_sql_hl); append_sql_txt->moveCursor(QTextCursor::End); append_sql_txt->setFocus(); prepend_sql_txt->setPlainText(object->getPrependedSQL()); prepend_sql_cp->configureCompletion(model, prepend_sql_hl); prepend_sql_txt->moveCursor(QTextCursor::End); end_of_model_chk->setVisible(object->getObjectType()==ObjectType::Database); begin_of_model_chk->setVisible(object->getObjectType()==ObjectType::Database); protected_obj_frm->setVisible(false); obj_id_lbl->setVisible(false); obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(object->getObjectType()))); configureMenus(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void CustomSQLWidget::applyConfiguration(void) { if(this->object->getObjectType()==ObjectType::Database) { dynamic_cast(this->object)->setAppendAtEOD(end_of_model_chk->isChecked()); dynamic_cast(this->object)->setPrependAtBOD(begin_of_model_chk->isChecked()); } this->object->setAppendedSQL(append_sql_txt->toPlainText()); this->object->setPrependedSQL(prepend_sql_txt->toPlainText()); this->sqlcodes_twg->setCurrentIndex(0); emit s_closeRequested(); } void CustomSQLWidget::addCommand(void) { PhysicalTable *table=dynamic_cast(this->object); BaseTable *base_table=dynamic_cast(this->object); QString cmd, ins_cmd=QString("INSERT INTO %1 (%2) VALUES (%3);"), sel_cmd=QString("SELECT * FROM %1;"), del_cmd=QString("DELETE * FROM %1;"), upd_cmd=QString("UPDATE %1 SET ;"); QPlainTextEdit *sqlcode_txt=(sqlcodes_twg->currentIndex()==0 ? append_sql_txt : prepend_sql_txt); if(sender()->objectName().contains(QString("insert")) || sender()->objectName().contains(QString("serial"))) { if(!table || sender()==action_gen_insert) cmd=ins_cmd.arg("table").arg("cols").arg("values"); else if(table) { bool inc_serials=(sender()==action_inc_serials); QString cols, vals; unsigned val_id=1; for(unsigned i=0; i < table->getColumnCount(); i++) { if(inc_serials || (!inc_serials && !table->getColumn(i)->getType().isSerialType())) { cols+=table->getColumn(i)->getName(true) + ','; vals+=QString("val%1,").arg(val_id++); } } cols.remove(cols.size()-1, 1); vals.remove(vals.size()-1, 1); cmd=ins_cmd.arg(table->getName(true)).arg(cols).arg(vals); } } else if(sender()->objectName().contains(QString("select"))) { if(!base_table || sender()==action_gen_select) cmd=sel_cmd.arg("object"); else if(base_table) cmd=sel_cmd.arg(base_table->getName(true)); } else if(sender()->objectName().contains(QString("delete"))) { if(!table || sender()==action_gen_delete) cmd=del_cmd.arg("object"); else if(table) cmd=del_cmd.arg(table->getName(true)); } else { if(!table || sender()==action_gen_update) cmd=upd_cmd.arg("object"); else if(table) cmd=upd_cmd.arg(table->getName(true)); } if(!sqlcode_txt->toPlainText().isEmpty()) sqlcode_txt->insertPlainText(QString("\n")); sqlcode_txt->insertPlainText(cmd); } void CustomSQLWidget::clearCode(void) { QPlainTextEdit *sqlcode_txt=(sqlcodes_twg->currentIndex()==0 ? append_sql_txt : prepend_sql_txt); QTextCursor tc=sqlcode_txt->textCursor(); tc.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); tc.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); tc.removeSelectedText(); } pgmodeler-0.9.2/libpgmodeler_ui/src/customsqlwidget.h000066400000000000000000000036201360462764600230570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class CustomSQLWidget \brief Widget that handles insertion of free SQL commands into object's definition */ #ifndef CUSTOM_SQL_WIDGET_H #define CUSTOM_SQL_WIDGET_H #include "baseobjectwidget.h" #include "codecompletionwidget.h" #include "ui_customsqlwidget.h" class CustomSQLWidget: public BaseObjectWidget, public Ui::CustomSQLWidget { private: Q_OBJECT NumberedTextEditor *append_sql_txt, *prepend_sql_txt; SyntaxHighlighter *append_sql_hl, *prepend_sql_hl; CodeCompletionWidget *append_sql_cp, *prepend_sql_cp; QMenu insert_menu, delete_menu, update_menu, select_menu; QAction *action_gen_insert, *action_gen_select, *action_inc_serials, *action_exc_serials, *action_tab_select, *action_tab_update, *action_gen_update, *action_gen_delete, *action_tab_delete; //! \brief Configures the code template menus according to the loaded object void configureMenus(void); public: CustomSQLWidget(QWidget *parent = nullptr); void setAttributes(DatabaseModel *model, BaseObject *object); public slots: void applyConfiguration(void); private slots: void addCommand(void); void clearCode(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/databaseexplorerwidget.cpp000066400000000000000000002422511360462764600247120ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "databaseexplorerwidget.h" #include "databaseimportform.h" #include "sqltoolwidget.h" #include "sqlexecutionwidget.h" #include "snippetsconfigwidget.h" #include "plaintextitemdelegate.h" #include "pgmodeleruins.h" #include "generalconfigwidget.h" const QString DatabaseExplorerWidget::DepNotDefined=QString(); const QString DatabaseExplorerWidget::DepNotFound=QT_TR_NOOP("(not found, OID: %1)"); const QString DatabaseExplorerWidget::ElemSeparator=QString("•"); const QString DatabaseExplorerWidget::DefaultSourceCode=QString("-- %1 --").arg(QT_TR_NOOP("Source code not generated! Hit F7 or middle-click the item to load it.")); const attribs_map DatabaseExplorerWidget::attribs_i18n { {Attributes::AdminRoles, QT_TR_NOOP("Admin. roles")}, {Attributes::Alignment, QT_TR_NOOP("Alignment")}, {Attributes::AnalyzeFunc, QT_TR_NOOP("Analyze func.")}, {Attributes::ArgCount, QT_TR_NOOP("Arg. count")}, {Attributes::ArgDefCount, QT_TR_NOOP("Arg. default count")}, {Attributes::ArgDefaults, QT_TR_NOOP("Arg. defaults")}, {Attributes::ArgModes, QT_TR_NOOP("Arg. modes")}, {Attributes::ArgNames, QT_TR_NOOP("Arg. names")}, {Attributes::ArgTypes, QT_TR_NOOP("Arg. types")}, {Attributes::Attribute, QT_TR_NOOP("Attribute")}, {Attributes::BehaviorType, QT_TR_NOOP("Behavior type")}, {Attributes::ByValue, QT_TR_NOOP("By value")}, {Attributes::CastType, QT_TR_NOOP("Cast type")}, {Attributes::Category, QT_TR_NOOP("Category")}, {Attributes::Collatable, QT_TR_NOOP("Collatable")}, {Attributes::Collation, QT_TR_NOOP("Collation")}, {Attributes::Comment, QT_TR_NOOP("Comment")}, {Attributes::CommutatorOp, QT_TR_NOOP("Commutator Op.")}, {Attributes::Configuration, QT_TR_NOOP("Configuration")}, {Attributes::ConnLimit, QT_TR_NOOP("Conn. limit")}, {Attributes::Constraint, QT_TR_NOOP("Constraint")}, {Attributes::CreateDb, QT_TR_NOOP("Create DB")}, {Attributes::CreateRole, QT_TR_NOOP("Create role")}, {Attributes::CurVersion, QT_TR_NOOP("Curr. version")}, {Attributes::Default, QT_TR_NOOP("Default")}, {Attributes::DefaultValue, QT_TR_NOOP("Default value")}, {Attributes::Definition, QT_TR_NOOP("Definition")}, {Attributes::Delimiter, QT_TR_NOOP("Delimiter")}, {Attributes::DestType, QT_TR_NOOP("Dest. type")}, {Attributes::Dimension, QT_TR_NOOP("Dimension")}, {Attributes::Directory, QT_TR_NOOP("Directory")}, {Attributes::DstEncoding, QT_TR_NOOP("Dest. encoding")}, {Attributes::Element, QT_TR_NOOP("Element")}, {Attributes::Encoding, QT_TR_NOOP("Encoding")}, {Attributes::Encrypted, QT_TR_NOOP("Encrypted")}, {Attributes::Enumerations, QT_TR_NOOP("Enumerations")}, {Attributes::ExecutionCost, QT_TR_NOOP("Exec. cost")}, {Attributes::Expression, QT_TR_NOOP("Expression")}, {Attributes::Family, QT_TR_NOOP("Op. family")}, {Attributes::FinalFunc, QT_TR_NOOP("Final func.")}, {Attributes::Function, QT_TR_NOOP("Function")}, {Attributes::FunctionType, QT_TR_NOOP("Func. type")}, {Attributes::HandlerFunc, QT_TR_NOOP("Handler func.")}, {Attributes::HandlesType, QT_TR_NOOP("Handles type")}, {Attributes::Hashes, QT_TR_NOOP("Hashes")}, {Attributes::IndexType, QT_TR_NOOP("Index type")}, {Attributes::Inherit, QT_TR_NOOP("Inherit")}, {Attributes::InitialCond, QT_TR_NOOP("Ini. condition")}, {Attributes::InlineFunc, QT_TR_NOOP("Inline func.")}, {Attributes::InputFunc, QT_TR_NOOP("Input func.")}, {Attributes::InternalLength, QT_TR_NOOP("Internal length")}, {Attributes::IntervalType, QT_TR_NOOP("Interval type")}, {Attributes::IoCast, QT_TR_NOOP("I/O cast")}, {Attributes::JoinFunc, QT_TR_NOOP("Join func.")}, {Attributes::Language, QT_TR_NOOP("Language")}, {Attributes::LcCollate, QT_TR_NOOP("LC COLLATE")}, {Attributes::LcCtype, QT_TR_NOOP("LC CTYPE")}, {Attributes::LeakProof, QT_TR_NOOP("Leak proof")}, {Attributes::LeftType, QT_TR_NOOP("Left type")}, {Attributes::Length, QT_TR_NOOP("Length")}, {Attributes::Library, QT_TR_NOOP("Library")}, {Attributes::Login, QT_TR_NOOP("Can login")}, {Attributes::Materialized, QT_TR_NOOP("Materialized")}, {Attributes::MemberRoles, QT_TR_NOOP("Member roles")}, {Attributes::Merges, QT_TR_NOOP("Merges")}, {Attributes::Name, QT_TR_NOOP("Name")}, {Attributes::NegatorOp, QT_TR_NOOP("Negator op.")}, {Attributes::NotNull, QT_TR_NOOP("Not null")}, {Attributes::ObjectType, QT_TR_NOOP("Object type")}, {Attributes::Oid, QT_TR_NOOP("OID")}, {Attributes::Oids, QT_TR_NOOP("With OIDs")}, {Attributes::OldVersion, QT_TR_NOOP("Old version")}, {Attributes::Operator, QT_TR_NOOP("Operator")}, {Attributes::OperatorFunc, QT_TR_NOOP("Operator func.")}, {Attributes::OutputFunc, QT_TR_NOOP("Output func.")}, {Attributes::Owner, QT_TR_NOOP("Owner")}, {Attributes::OwnerColumn, QT_TR_NOOP("Owner column")}, {Attributes::Parents, QT_TR_NOOP("Parents")}, {Attributes::Password, QT_TR_NOOP("Password")}, {Attributes::Permission, QT_TR_NOOP("Permissions")}, {Attributes::Precision, QT_TR_NOOP("Precision")}, {Attributes::Preferred, QT_TR_NOOP("Preferred")}, {Attributes::RangeAttribs, QT_TR_NOOP("Range attributes")}, {Attributes::RecvFunc, QT_TR_NOOP("Receive func.")}, {Attributes::RefRoles, QT_TR_NOOP("Ref. roles")}, {Attributes::Replication, QT_TR_NOOP("Replication")}, {Attributes::RestrictionFunc, QT_TR_NOOP("Restriction func.")}, {Attributes::ReturnType, QT_TR_NOOP("Return type")}, {Attributes::ReturnsSetOf, QT_TR_NOOP("Returns SETOF")}, {Attributes::RightType, QT_TR_NOOP("Right type")}, {Attributes::RowAmount, QT_TR_NOOP("Rows amount")}, {Attributes::Schema, QT_TR_NOOP("Schema")}, {Attributes::SecurityType, QT_TR_NOOP("Security type")}, {Attributes::SendFunc, QT_TR_NOOP("Send func.")}, {Attributes::SortOp, QT_TR_NOOP("Sort op.")}, {Attributes::SourceType, QT_TR_NOOP("Source type")}, {Attributes::SrcEncoding, QT_TR_NOOP("Src. encoding")}, {Attributes::StateType, QT_TR_NOOP("State type")}, {Attributes::Storage, QT_TR_NOOP("Storage")}, {Attributes::Superuser, QT_TR_NOOP("Superuser")}, {Attributes::Tablespace, QT_TR_NOOP("Tablespace")}, {Attributes::TpmodInFunc, QT_TR_NOOP("Type mod. in func.")}, {Attributes::TpmodOutFunc, QT_TR_NOOP("Type mod. out func.")}, {Attributes::TransitionFunc, QT_TR_NOOP("Transition func.")}, {Attributes::Trusted, QT_TR_NOOP("Trusted")}, {Attributes::Type, QT_TR_NOOP("Type")}, {Attributes::TypeAttribute, QT_TR_NOOP("Type attribute")}, {Attributes::Types, QT_TR_NOOP("Types")}, {Attributes::Unlogged, QT_TR_NOOP("Unlogged")}, {Attributes::Validator, QT_TR_NOOP("Validator func.")}, {Attributes::Validity, QT_TR_NOOP("Validity")}, {Attributes::WindowFunc, QT_TR_NOOP("Windows func.")}, {Attributes::False, QT_TR_NOOP("false")}, {Attributes::True, QT_TR_NOOP("true")}, {Attributes::Cache, QT_TR_NOOP("Cache value")}, {Attributes::Cycle, QT_TR_NOOP("Cycle")}, {Attributes::Increment, QT_TR_NOOP("Increment")}, {Attributes::MaxValue, QT_TR_NOOP("Max. value")}, {Attributes::MinValue, QT_TR_NOOP("Min. value")}, {Attributes::Start, QT_TR_NOOP("Start value")}, {Attributes::LastValue, QT_TR_NOOP("Last value")}, {Attributes::Subtype, QT_TR_NOOP("Subtype")}, {Attributes::OpClass, QT_TR_NOOP("Op. class")}, {Attributes::CanonicalFunc, QT_TR_NOOP("Canonical func.")}, {Attributes::SubtypeDiffFunc, QT_TR_NOOP("Subtype diff func.")}, {Attributes::Deferrable, QT_TR_NOOP("Deferrable")}, {Attributes::PerRow, QT_TR_NOOP("For each row")}, {Attributes::FiringType, QT_TR_NOOP("Firing")}, {Attributes::InsEvent, QT_TR_NOOP("On insert")}, {Attributes::DelEvent, QT_TR_NOOP("On delete")}, {Attributes::UpdEvent, QT_TR_NOOP("On update")}, {Attributes::TruncEvent, QT_TR_NOOP("On truncate")}, {Attributes::Arguments, QT_TR_NOOP("Arguments")}, {Attributes::Table, QT_TR_NOOP("Table")}, {Attributes::TriggerFunc, QT_TR_NOOP("Trigger func.")}, {Attributes::Columns, QT_TR_NOOP("Columns")}, {Attributes::Condition, QT_TR_NOOP("Condition")}, {Attributes::DeferType, QT_TR_NOOP("Deferment")}, {Attributes::EventType, QT_TR_NOOP("Event")}, {Attributes::ExecType, QT_TR_NOOP("Execution mode")}, {Attributes::Commands, QT_TR_NOOP("Commands")}, {Attributes::Position, QT_TR_NOOP("Position")}, {Attributes::ComparisonType, QT_TR_NOOP("Comparison type")}, {Attributes::DelAction, QT_TR_NOOP("On delete")}, {Attributes::DstColumns, QT_TR_NOOP("Ref. columns")}, {Attributes::Expressions, QT_TR_NOOP("Expressions")}, {Attributes::Factor, QT_TR_NOOP("Fill factor")}, {Attributes::NoInherit, QT_TR_NOOP("No inherit")}, {Attributes::OpClasses, QT_TR_NOOP("Op. classes")}, {Attributes::Operators, QT_TR_NOOP("Operators")}, {Attributes::RefTable, QT_TR_NOOP("Ref. table")}, {Attributes::Columns, QT_TR_NOOP("Columns")}, {Attributes::UpdAction, QT_TR_NOOP("On update")}, {Attributes::SrcColumns, QT_TR_NOOP("Columns")}, {Attributes::Unique, QT_TR_NOOP("Unique")}, {Attributes::Predicate, QT_TR_NOOP("Predicate")}, {Attributes::Collations, QT_TR_NOOP("Collations")}, {Attributes::Inherited, QT_TR_NOOP("Inherited")}, {Attributes::ClientEncoding, QT_TR_NOOP("Client encoding")}, {Attributes::ConfigFile, QT_TR_NOOP("Configuration file")}, {Attributes::DataDirectory, QT_TR_NOOP("Data directory")}, {Attributes::DynamicLibraryPath, QT_TR_NOOP("Dynamic library path")}, {Attributes::DynamicSharedMemory, QT_TR_NOOP("Dynamic shared memory")}, {Attributes::HbaFile, QT_TR_NOOP("Hba file")}, {Attributes::ListenAddresses, QT_TR_NOOP("Listen addresses")}, {Attributes::MaxConnections, QT_TR_NOOP("Max. connections")}, {Attributes::Port, QT_TR_NOOP("Listen port")}, {Attributes::ServerEncoding, QT_TR_NOOP("Server encoding")}, {Attributes::Ssl, QT_TR_NOOP("SSL")}, {Attributes::SslCaFile, QT_TR_NOOP("SSL ca file")}, {Attributes::SslCertFile, QT_TR_NOOP("SSL cert file")}, {Attributes::SslCrlFile, QT_TR_NOOP("SSL crl file")}, {Attributes::SslKeyFile, QT_TR_NOOP("SSL key file")}, {Attributes::ServerVersion, QT_TR_NOOP("Server version")}, {Attributes::IdentFile, QT_TR_NOOP("Ident file")}, {Attributes::PasswordEncryption, QT_TR_NOOP("Password encryption")}, {Attributes::Connection, QT_TR_NOOP("Connection ID")}, {Attributes::ServerPid, QT_TR_NOOP("Server PID")}, {Attributes::ServerProtocol, QT_TR_NOOP("Server protocol")}, {Attributes::Referrers, QT_TR_NOOP("Referrers")}, {Attributes::IdentityType, QT_TR_NOOP("Identity")}, {Attributes::Command, QT_TR_NOOP("Command")}, {Attributes::UsingExp, QT_TR_NOOP("USING expr.")}, {Attributes::CheckExp, QT_TR_NOOP("CHECK expr.")}, {Attributes::Roles, QT_TR_NOOP("Roles")}, {Attributes::RlsEnabled, QT_TR_NOOP("RLS enabled")}, {Attributes::RlsForced, QT_TR_NOOP("RLS forced")}, {Attributes::LastAnalyze, QT_TR_NOOP("Last analyze")}, {Attributes::LastAutovacuum, QT_TR_NOOP("Last autovacuum")}, {Attributes::LastVacuum, QT_TR_NOOP("Last vacuum")}, {Attributes::TuplesDel, QT_TR_NOOP("Tuples deleted")}, {Attributes::TyplesUpd, QT_TR_NOOP("Tuples updated")}, {Attributes::TuplesIns, QT_TR_NOOP("Tuples inserted")}, {Attributes::IsPartitioned, QT_TR_NOOP("Partitioned")}, {Attributes::PartitionedTable, QT_TR_NOOP("Partition of")}, {Attributes::PartitionBoundExpr, QT_TR_NOOP("Partition bound expr.")}, {Attributes::DeadRowsAmount, QT_TR_NOOP("Dead rows amount")}, {Attributes::PartitionKey, QT_TR_NOOP("Partition keys")}, {Attributes::Partitioning, QT_TR_NOOP("Partitioning")}, {Attributes::Options, QT_TR_NOOP("Options")}, {Attributes::Fdw, QT_TR_NOOP("Foreign data wrapper")}, {Attributes::Server, QT_TR_NOOP("Server")}, {Attributes::BypassRls, QT_TR_NOOP("Bypass RLS")} }; DatabaseExplorerWidget::DatabaseExplorerWidget(QWidget *parent): QWidget(parent) { setupUi(this); filter_parent->setVisible(false); sort_column = 0; splitter->setSizes({ 80, 20 }); properties_tbw->setItemDelegate(new PlainTextItemDelegate(this, true)); rename_item=nullptr; data_grid_tb->setToolTip(data_grid_tb->toolTip() + QString(" (%1)").arg(data_grid_tb->shortcut().toString())); runsql_tb->setToolTip(runsql_tb->toolTip() + QString(" (%1)").arg(runsql_tb->shortcut().toString())); QAction *act = nullptr; act = toggle_disp_menu.addAction(trUtf8("Show objects filter")); act->setCheckable(true); connect(act, SIGNAL(toggled(bool)), filter_parent, SLOT(setVisible(bool))); toggle_disp_menu.addSeparator(); show_sys_objs = toggle_disp_menu.addAction(trUtf8("Show system objects")); show_sys_objs->setCheckable(true); connect(show_sys_objs, SIGNAL(toggled(bool)), this, SLOT(listObjects(void))); show_ext_objs = toggle_disp_menu.addAction(trUtf8("Show extension objects")); show_ext_objs->setCheckable(true); connect(show_ext_objs, SIGNAL(toggled(bool)), this, SLOT(listObjects(void))); toggle_display_tb->setMenu(&toggle_disp_menu); snippets_menu.setTitle(trUtf8("Snippets")); snippets_menu.setIcon(QIcon(QString(":icones/icones/codesnippet.png"))); drop_action=new QAction(QIcon(QString(":icones/icones/excluir.png")), trUtf8("Drop object"), &handle_menu); drop_action->setShortcut(QKeySequence(Qt::Key_Delete)); drop_cascade_action=new QAction(QIcon(QString(":icones/icones/delcascade.png")), trUtf8("Drop cascade"), &handle_menu); drop_cascade_action->setShortcut(QKeySequence("Shift+Del")); truncate_action=new QAction(QIcon(QString(":icones/icones/truncate.png")), trUtf8("Truncate"), &handle_menu); trunc_cascade_action=new QAction(QIcon(QString(":icones/icones/trunccascade.png")), trUtf8("Trunc. cascade"), &handle_menu); show_data_action=new QAction(QIcon(QString(":icones/icones/result.png")), trUtf8("Show data"), &handle_menu); show_data_action->setShortcut(QKeySequence(Qt::Key_Space)); properties_action=new QAction(QIcon(QString(":icones/icones/editar.png")), trUtf8("Reload properties"), &handle_menu); refresh_action=new QAction(QIcon(QString(":icones/icones/atualizar.png")), trUtf8("Update"), &handle_menu); refresh_action->setShortcut(QKeySequence(Qt::Key_F6)); rename_action=new QAction(QIcon(QString(":icones/icones/rename.png")), trUtf8("Rename"), &handle_menu); rename_action->setShortcut(QKeySequence(Qt::Key_F2)); source_action=new QAction(QIcon(QString(":icones/icones/codigosql.png")), trUtf8("Source code"), &handle_menu); source_action->setShortcut(QKeySequence(Qt::Key_F7)); objects_trw->installEventFilter(this); connect(refresh_tb, SIGNAL(clicked(void)), this, SLOT(listObjects(void))); connect(objects_trw, SIGNAL(itemPressed(QTreeWidgetItem*,int)), this, SLOT(handleObject(QTreeWidgetItem *,int))); connect(objects_trw, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(showObjectProperties())); connect(raw_attrib_names_chk, SIGNAL(toggled(bool)), this, SLOT(showObjectProperties())); connect(objects_trw, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(cancelObjectRename())); connect(objects_trw, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(cancelObjectRename())); connect(objects_trw, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(cancelObjectRename())); connect(data_grid_tb, SIGNAL(clicked(bool)), this, SLOT(openDataGrid())); connect(drop_db_tb, SIGNAL(clicked(bool)), this, SLOT(dropDatabase())); connect(collapse_all_tb, SIGNAL(clicked(bool)), objects_trw, SLOT(collapseAll(void))); connect(by_oid_chk, SIGNAL(toggled(bool)), this, SLOT(filterObjects(void))); connect(filter_edt, SIGNAL(textChanged(QString)), this, SLOT(filterObjects(void))); connect(runsql_tb, &QToolButton::clicked, [&]() { emit s_sqlExecutionRequested(); }); connect(properties_tbw, &QTableWidget::itemPressed, [&]() { SQLExecutionWidget::copySelection(properties_tbw, true); }); connect(expand_all_tb, &QToolButton::clicked, [&](){ objects_trw->blockSignals(true); objects_trw->expandAll(); objects_trw->blockSignals(false); }); connect(objects_trw, &QTreeWidget::itemExpanded, [&](QTreeWidgetItem *item){ ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); unsigned oid=item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(); if((obj_type==ObjectType::Schema || BaseTable::isBaseTable(obj_type)) && oid > 0 && item->childCount() <= 1) { updateItem(item); } }); connect(sort_by_name_tb, &QToolButton::clicked, [&]() { sort_column = sort_by_name_tb->isChecked() ? 0 : DatabaseImportForm::ObjectId; objects_trw->sortByColumn(sort_column); }); QMenu *refresh_menu=new QMenu(refresh_tb); act=refresh_menu->addAction(trUtf8("Quick refresh"), this, SLOT(listObjects()), QKeySequence("Alt+F5")); act->setData(QVariant::fromValue(true)); act=refresh_menu->addAction(trUtf8("Full refresh"), this, SLOT(listObjects()), QKeySequence("Ctrl+F5")); act->setData(QVariant::fromValue(false)); refresh_tb->setPopupMode(QToolButton::InstantPopup); refresh_tb->setMenu(refresh_menu); filter_ht=new HintTextWidget(filter_hint, this); filter_ht->setText(filter_lbl->statusTip()); } bool DatabaseExplorerWidget::eventFilter(QObject *object, QEvent *event) { if(object==objects_trw && event->type()==QEvent::KeyPress) { QKeyEvent *k_event=dynamic_cast(event); if(k_event->key()==Qt::Key_Delete || k_event->key()==Qt::Key_F6 || k_event->key()==Qt::Key_Space || k_event->key()==Qt::Key_F2 || k_event->key()==Qt::Key_Escape || k_event->key()==Qt::Key_Return || k_event->key()==Qt::Key_Enter || k_event->key()==Qt::Key_F7) { if(k_event->key()==Qt::Key_Space) { QTreeWidgetItem *item=objects_trw->currentItem(); ObjectType obj_type=ObjectType::BaseObject; if(item) { unsigned oid=item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(); obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); if(oid!=0 && BaseTable::isBaseTable(obj_type)) { openDataGrid(item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString(), item->text(0), obj_type!=ObjectType::View); } } } else if(k_event->key()==Qt::Key_F6) updateItem(objects_trw->currentItem()); else if(k_event->key()==Qt::Key_F2) startObjectRename(objects_trw->currentItem()); else if(k_event->key()==Qt::Key_F7) loadObjectSource(); else if(k_event->key()==Qt::Key_Escape) cancelObjectRename(); else if(k_event->key()==Qt::Key_Enter || k_event->key()==Qt::Key_Return) finishObjectRename(); else dropObject(objects_trw->currentItem(), k_event->modifiers()==Qt::ShiftModifier); return(true); } else return(false); } return(QWidget::eventFilter(object, event)); } attribs_map DatabaseExplorerWidget::formatObjectAttribs(attribs_map &attribs) { ObjectType obj_type=ObjectType::BaseObject; attribs_map fmt_attribs; QString attr_name, attr_value; QRegExp oid_regexp=QRegExp(QString("^[0-9]+")); map dep_types={{Attributes::Owner, ObjectType::Role}, {Attributes::Schema, ObjectType::Schema}, {Attributes::Tablespace, ObjectType::Tablespace}, {Attributes::Collation, ObjectType::Collation}, {Attributes::Table, ObjectType::Table}}; if(attribs.count(Attributes::ObjectType)!=0) obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); try { switch(obj_type) { case ObjectType::Cast: formatCastAttribs(attribs); break; case ObjectType::EventTrigger: formatEventTriggerAttribs(attribs); break; case ObjectType::Language: formatLanguageAttribs(attribs); break; case ObjectType::Role: formatRoleAttribs(attribs); break; case ObjectType::Aggregate: formatAggregateAttribs(attribs); break; case ObjectType::Conversion: formatConversionAttribs(attribs); break; case ObjectType::Domain: formatDomainAttribs(attribs); break; case ObjectType::Extension: formatExtensionAttribs(attribs); break; case ObjectType::Function: formatFunctionAttribs(attribs); break; case ObjectType::Operator: formatOperatorAttribs(attribs); break; case ObjectType::OpClass: formatOperatorClassAttribs(attribs); break; case ObjectType::Table: formatTableAttribs(attribs); break; case ObjectType::Sequence: formatSequenceAttribs(attribs); break; case ObjectType::Type: formatTypeAttribs(attribs); break; case ObjectType::View: formatViewAttribs(attribs); break; case ObjectType::Trigger: formatTriggerAttribs(attribs); break; case ObjectType::Rule: formatRuleAttribs(attribs); break; case ObjectType::Column: formatColumnAttribs(attribs); break; case ObjectType::Constraint: formatConstraintAttribs(attribs); break; case ObjectType::Index: formatIndexAttribs(attribs); break; case ObjectType::Policy: formatPolicyAttribs(attribs); break; case ObjectType::ForeignDataWrapper: formatForeignDataWrapperAttribs(attribs); break; case ObjectType::ForeignServer: formatServerAttribs(attribs); break; case ObjectType::UserMapping: formatUserMappingAttribs(attribs); break; default: break; } } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } if(attribs.count(Attributes::Permission)!=0) attribs[Attributes::Permission]=Catalog::parseArrayValues(attribs[Attributes::Permission]).join(ElemSeparator); //Removing system schemas from object's name if(attribs.count(Attributes::Name)!=0 && (attribs[Attributes::Name].startsWith(QString("pg_catalog.")) || attribs[Attributes::Name].startsWith(QString("information_schema.")))) attribs[Attributes::Name]=attribs[Attributes::Name].split('.').at(1); for(auto &attrib : attribs) { attr_name=attrib.first; attr_value=attrib.second; if(attr_name==Attributes::ObjectType) attr_value=BaseObject::getTypeName(static_cast(attr_value.toUInt())); //If the current attribute is related to a dependency object, retreive its real name else if(dep_types.count(attr_name)!=0 && oid_regexp.exactMatch(attr_value)) attr_value=getObjectName(dep_types[attr_name], attr_value); attribs[attr_name]=attr_value; //Applying translation on the attribute if(attribs_i18n.count(attr_name)!=0) attr_name=attribs_i18n.at(attr_name); fmt_attribs[attr_name]=attr_value; } if(attribs[Attributes::Oid].toUInt() > 0) { attribs[Attributes::SqlObject]=BaseObject::getSQLName(obj_type); attribs[Attributes::ObjectType]=BaseObject::getSchemaName(obj_type); if(attribs.count(Attributes::Signature)==0) attribs[Attributes::Signature]=BaseObject::formatName(attribs[Attributes::Name]); if(attribs.count(Attributes::Schema)!=0) attribs[Attributes::Signature]=QString("%1.%2") .arg(BaseObject::formatName(attribs[Attributes::Schema])) .arg(attribs[Attributes::Signature]); } return(fmt_attribs); } void DatabaseExplorerWidget::formatBooleanAttribs(attribs_map &attribs, QStringList bool_attrs) { for(QString attr : bool_attrs) attribs[attr]=(attribs[attr].isEmpty() ? attribs_i18n.at(Attributes::False) : attribs_i18n.at(Attributes::True)); } void DatabaseExplorerWidget::formatOidAttribs(attribs_map &attribs, QStringList oid_attrs, ObjectType obj_type, bool is_oid_array) { try { if(!is_oid_array) { for(QString attr : oid_attrs) attribs[attr]=getObjectName(obj_type, attribs[attr]); } else { QStringList names; for(QString attr : oid_attrs) { names=getObjectsNames(obj_type, Catalog::parseArrayValues(attribs[attr])); attribs[attr]=names.join(ElemSeparator); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseExplorerWidget::formatCastAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::IoCast }); formatOidAttribs(attribs, { Attributes::DestType, Attributes::SourceType }, ObjectType::Type, false); attribs[Attributes::Function]=getObjectName(ObjectType::Function, attribs[Attributes::Function]); } void DatabaseExplorerWidget::formatEventTriggerAttribs(attribs_map &attribs) { attribs[Attributes::Values]=Catalog::parseArrayValues(attribs[Attributes::Values]).join(ElemSeparator); attribs[Attributes::Function]=getObjectName(ObjectType::Function, attribs[Attributes::Function]); } void DatabaseExplorerWidget::formatAggregateAttribs(attribs_map &attribs) { formatOidAttribs(attribs, { Attributes::FinalFunc, Attributes::TransitionFunc }, ObjectType::Function, false); formatOidAttribs(attribs, { Attributes::Types }, ObjectType::Type, true); attribs[Attributes::Signature]=(QString("%1(%2)") .arg(BaseObject::formatName(attribs[Attributes::Name])) .arg(attribs[Attributes::Types])).replace(ElemSeparator, QString(",")); attribs[Attributes::StateType]=getObjectName(ObjectType::Type, attribs[Attributes::StateType]); attribs[Attributes::SortOp]=getObjectName(ObjectType::Operator, attribs[Attributes::SortOp]); attribs[Attributes::InitialCond]=Catalog::parseArrayValues(attribs[Attributes::InitialCond]).join(ElemSeparator); } void DatabaseExplorerWidget::formatLanguageAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::Trusted }); formatOidAttribs(attribs, { Attributes::ValidatorFunc, Attributes::HandlerFunc, Attributes::InlineFunc }, ObjectType::Function, false); } void DatabaseExplorerWidget::formatRoleAttribs(attribs_map &attribs) { formatOidAttribs(attribs, { Attributes::AdminRoles, Attributes::MemberRoles, Attributes::RefRoles }, ObjectType::Role, true); formatBooleanAttribs(attribs, { Attributes::Superuser, Attributes::Inherit, Attributes::CreateRole, Attributes::CreateDb, Attributes::Login, Attributes::Encrypted, Attributes::Replication }); } void DatabaseExplorerWidget::formatConversionAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::Default }); attribs[Attributes::Function]=getObjectName(ObjectType::Function, attribs[Attributes::Function]); } void DatabaseExplorerWidget::formatDomainAttribs(attribs_map &attribs) { QStringList contrs = Catalog::parseArrayValues(attribs[Attributes::Constraints]); contrs.replaceInStrings(Table::DataSeparator, QChar(':')); attribs[Attributes::Constraints] = contrs.join(Table::DataSeparator); formatBooleanAttribs(attribs, { Attributes::NotNull }); attribs[Attributes::Type]=getObjectName(ObjectType::Type, attribs[Attributes::Type]); } void DatabaseExplorerWidget::formatExtensionAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::HandlesType }); } void DatabaseExplorerWidget::formatFunctionAttribs(attribs_map &attribs) { attribs[Attributes::Language]=getObjectName(ObjectType::Language, attribs[Attributes::Language]); attribs[Attributes::ReturnType]=getObjectName(ObjectType::Type, attribs[Attributes::ReturnType]); attribs[Attributes::ArgNames]=Catalog::parseArrayValues(attribs[Attributes::ArgNames]).join(ElemSeparator); attribs[Attributes::ArgModes]=Catalog::parseArrayValues(attribs[Attributes::ArgModes]).join(ElemSeparator); attribs[Attributes::ArgDefaults]=Catalog::parseArrayValues(attribs[Attributes::ArgDefaults]).join(ElemSeparator); formatOidAttribs(attribs, { Attributes::ArgTypes }, ObjectType::Type, true); attribs[Attributes::Signature]=(QString("%1(%2)") .arg(BaseObject::formatName(attribs[Attributes::Name])) .arg(attribs[Attributes::ArgTypes])).replace(ElemSeparator, QString(",")); formatBooleanAttribs(attribs, { Attributes::WindowFunc, Attributes::LeakProof, Attributes::ReturnsSetOf }); } void DatabaseExplorerWidget::formatOperatorAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::Hashes, Attributes::Merges }); formatOidAttribs(attribs, { Attributes::LeftType, Attributes::RightType}, ObjectType::Type, false); formatOidAttribs(attribs, { Attributes::CommutatorOp, Attributes::NegatorOp}, ObjectType::Operator, false); formatOidAttribs(attribs, { Attributes::OperatorFunc, Attributes::RestrictionFunc, Attributes::JoinFunc }, ObjectType::Function, false); attribs[Attributes::Signature]=(QString("%1(%2,%3)") .arg(BaseObject::formatName(attribs[Attributes::Name], true)) .arg(attribs[Attributes::LeftType]) .arg(attribs[Attributes::RightType])).replace(ElemSeparator, QString(",")); } void DatabaseExplorerWidget::formatTableAttribs(attribs_map &attribs) { QStringList part_keys; formatBooleanAttribs(attribs, { Attributes::Oids, Attributes::Unlogged, Attributes::RlsEnabled, Attributes::RlsForced}); formatOidAttribs(attribs, { Attributes::Parents }, ObjectType::Table, true); formatOidAttribs(attribs, { Attributes::PartitionedTable }, ObjectType::Table, false); part_keys.push_back(getObjectsNames(ObjectType::Column, Catalog::parseArrayValues(attribs[Attributes::PartKeyCols]), getObjectName(ObjectType::Schema, attribs[Attributes::Schema]), attribs[Attributes::Name]).join(ElemSeparator)); part_keys.push_back(Catalog::parseArrayValues(attribs[Attributes::Expressions]).join(ElemSeparator)); part_keys.removeAll(QString()); attribs[Attributes::PartitionKey] = part_keys.join(ElemSeparator); attribs.erase(Attributes::PartKeyColls); attribs.erase(Attributes::PartKeyOpCls); attribs.erase(Attributes::PartKeyExprs); attribs.erase(Attributes::PartKeyCols); } void DatabaseExplorerWidget::formatSequenceAttribs(attribs_map &attribs) { QStringList owner_col, seq_values=Catalog::parseArrayValues(attribs[Attributes::Attribute]), seq_attrs={ Attributes::Start, Attributes::MinValue, Attributes::MaxValue, Attributes::Increment, Attributes::Cache, Attributes::Cycle }; QString sch_name=getObjectName(ObjectType::Schema, attribs[Attributes::Schema]); attribs.erase(Attributes::Attribute); for(int i=0; i < seq_values.size(); i++) attribs[seq_attrs[i]]=seq_values[i]; formatBooleanAttribs(attribs, { Attributes::Cycle }); owner_col=attribs[Attributes::OwnerColumn].split(':'); if(owner_col.size()==2) { QStringList names=getObjectName(ObjectType::Table, owner_col[0]).split('.'); vector col_attribs=catalog.getObjectsAttributes(ObjectType::Column, names[0], names[1], { owner_col[1].toUInt() }); if(!col_attribs.empty()) attribs[Attributes::OwnerColumn]=QString("%1.%2.%3").arg(names[0], names[1], col_attribs[0].at(Attributes::Name)); } //Retrieving the current value of the sequence by querying the database try { Connection conn=connection; ResultSet res; conn.connect(); conn.executeDMLCommand(QString("SELECT last_value FROM \"%1\".\"%2\"").arg(sch_name).arg(BaseObject::formatName(attribs[Attributes::Name])), res); if(res.accessTuple(ResultSet::FirstTuple)) attribs[Attributes::LastValue]=res.getColumnValue(QString("last_value")); conn.close(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseExplorerWidget::formatViewAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::Materialized }); } void DatabaseExplorerWidget::formatTypeAttribs(attribs_map &attribs) { QStringList range_attr=Catalog::parseArrayValues(attribs[Attributes::RangeAttribs]), type_attr=Catalog::parseArrayValues(attribs[Attributes::TypeAttribute]); formatBooleanAttribs(attribs, { Attributes::ByValue, Attributes::Collatable, Attributes::Preferred }); formatOidAttribs(attribs, { Attributes::AnalyzeFunc, Attributes::InputFunc, Attributes::OutputFunc, Attributes::RecvFunc, Attributes::SendFunc, Attributes::TpmodInFunc, Attributes::TpmodOutFunc }, ObjectType::Function, false); attribs[Attributes::Element]=getObjectName(ObjectType::Type, attribs[Attributes::Element]); if(attribs[Attributes::Enumerations].isEmpty()) attribs.erase(Attributes::Enumerations); else attribs[Attributes::Enumerations]=Catalog::parseArrayValues(attribs[Attributes::Enumerations]).join(ElemSeparator); attribs.erase(Attributes::RangeAttribs); if(!range_attr.isEmpty()) { attribs[Attributes::Subtype]=getObjectName(ObjectType::Type, range_attr[0]); attribs[Attributes::Collation]=getObjectName(ObjectType::Collation, range_attr[1]); attribs[Attributes::OpClass]=getObjectName(ObjectType::OpClass, range_attr[2]); attribs[Attributes::CanonicalFunc]=getObjectName(ObjectType::Function, range_attr[3]); attribs[Attributes::SubtypeDiffFunc]=getObjectName(ObjectType::Function, range_attr[4]); } if(!type_attr.isEmpty()) { QStringList list, fmt_attribs; for(QString attr : type_attr) { list=attr.split(':'); list.removeAt(2); fmt_attribs.push_back(list.join(QLatin1String(" "))); } attribs[Attributes::TypeAttribute]=fmt_attribs.join(ElemSeparator); } else attribs.erase(Attributes::TypeAttribute); } void DatabaseExplorerWidget::formatOperatorClassAttribs(attribs_map &attribs) { QStringList list, array_vals, elems; attribs[Attributes::Family]=getObjectName(ObjectType::OpFamily, attribs[Attributes::Family]); formatBooleanAttribs(attribs, { Attributes::Default }); formatOidAttribs(attribs, { Attributes::Storage, Attributes::Type }, ObjectType::Type, false); array_vals=Catalog::parseArrayValues(attribs[Attributes::Function]); if(!array_vals.isEmpty()) { for(int i=0; i < array_vals.size(); i++) { list=array_vals[i].split(':'); elems.push_back(QString("[%1] %2").arg(list[0], getObjectName(ObjectType::Function, list[1]))); } attribs[Attributes::Function]=elems.join(ElemSeparator); elems.clear(); } array_vals=Catalog::parseArrayValues(attribs[Attributes::Operator]); if(!array_vals.isEmpty()) { for(int i=0; i < array_vals.size(); i++) { list=array_vals[i].split(':'); elems.push_back(QString("[%1] [%2] [%3]") .arg(list[0], getObjectName(ObjectType::Operator, list[1]), getObjectName(ObjectType::Operator, list[2]))); } attribs[Attributes::Operator]=elems.join(ElemSeparator); elems.clear(); } } void DatabaseExplorerWidget::formatTriggerAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::Constraint, Attributes::Deferrable, Attributes::PerRow, Attributes::InsEvent, Attributes::DelEvent, Attributes::UpdEvent, Attributes::TruncEvent }); attribs[Attributes::TriggerFunc]=getObjectName(ObjectType::Function, attribs[Attributes::TriggerFunc]); attribs[Attributes::Arguments]=Catalog::parseArrayValues(attribs[Attributes::Arguments]).join(ElemSeparator); attribs[Attributes::Columns]=Catalog::parseArrayValues(attribs[Attributes::Columns]).join(ElemSeparator); } void DatabaseExplorerWidget::formatRuleAttribs(attribs_map &attribs) { attribs[Attributes::Commands]=Catalog::parseRuleCommands(attribs[Attributes::Commands]).join(';'); } void DatabaseExplorerWidget::formatColumnAttribs(attribs_map &attribs) { formatBooleanAttribs(attribs, { Attributes::NotNull, Attributes::Inherited }); attribs[Attributes::Position]=attribs[Attributes::Oid]; attribs.erase(Attributes::Oid); attribs.erase(Attributes::TypeOid); } void DatabaseExplorerWidget::formatConstraintAttribs(attribs_map &attribs) { map types={{Attributes::PkConstr, ConstraintType(ConstraintType::PrimaryKey)}, {Attributes::FkConstr, ConstraintType(ConstraintType::ForeignKey)}, {Attributes::UqConstr, ConstraintType(ConstraintType::Unique)}, {Attributes::CkConstr, ConstraintType(ConstraintType::Check)}, {Attributes::ExConstr, ConstraintType(ConstraintType::Exclude)}}; ConstraintType constr_type=types[attribs[Attributes::Type]]; QStringList names=getObjectName(ObjectType::Table, attribs[Attributes::Table]).split('.'); formatBooleanAttribs(attribs, { Attributes::Deferrable, Attributes::NoInherit }); attribs[Attributes::Type]=~types[attribs[Attributes::Type]]; attribs[Attributes::OpClasses]=getObjectsNames(ObjectType::OpClass, Catalog::parseArrayValues(attribs[Attributes::OpClasses])).join(ElemSeparator); attribs[Attributes::SrcColumns]=getObjectsNames(ObjectType::Column, Catalog::parseArrayValues(attribs[Attributes::SrcColumns]), names[0], names[1]).join(ElemSeparator); if(constr_type==ConstraintType::ForeignKey) { attribs[Attributes::RefTable]=getObjectName(ObjectType::Table, attribs[Attributes::RefTable]); names=attribs[Attributes::RefTable].split('.'); attribs[Attributes::DstColumns]=getObjectsNames(ObjectType::Column, Catalog::parseArrayValues(attribs[Attributes::DstColumns]), names[0], names[1]).join(ElemSeparator); } else { attribs.erase(Attributes::DstColumns); attribs.erase(Attributes::RefTable); attribs.erase(Attributes::UpdAction); attribs.erase(Attributes::DelAction); attribs.erase(Attributes::ComparisonType); } if(constr_type==ConstraintType::Check) { attribs.erase(Attributes::Deferrable); attribs.erase(Attributes::DeferType); } else attribs.erase(Attributes::Expression); if(constr_type==ConstraintType::Exclude) { attribs[Attributes::Expressions]=Catalog::parseArrayValues(attribs[Attributes::Expressions]).join(ElemSeparator); attribs[Attributes::Operators]=getObjectsNames(ObjectType::Operator, Catalog::parseArrayValues(attribs[Attributes::Operators])).join(ElemSeparator); } else { attribs.erase(Attributes::Condition); attribs.erase(Attributes::Expressions); attribs.erase(Attributes::Operators); } } void DatabaseExplorerWidget::formatIndexAttribs(attribs_map &attribs) { QStringList names=getObjectName(ObjectType::Table, attribs[Attributes::Table]).split('.'); if(names.isEmpty() || names.size() == 1) names=getObjectName(ObjectType::View, attribs[Attributes::Table]).split('.'); formatBooleanAttribs(attribs, { Attributes::Unique }); attribs[Attributes::Expressions]=Catalog::parseIndexExpressions(attribs[Attributes::Expressions]).join(ElemSeparator); attribs[Attributes::Collations]=getObjectsNames(ObjectType::Collation, Catalog::parseArrayValues(attribs[Attributes::Collations])).join(ElemSeparator); attribs[Attributes::OpClasses]=getObjectsNames(ObjectType::OpClass, Catalog::parseArrayValues(attribs[Attributes::OpClasses])).join(ElemSeparator); attribs[Attributes::Columns]=getObjectsNames(ObjectType::Column, Catalog::parseArrayValues(attribs[Attributes::Columns]), names[0], names[1]).join(ElemSeparator); } void DatabaseExplorerWidget::formatPolicyAttribs(attribs_map &attribs) { attribs[Attributes::Roles] = getObjectsNames(ObjectType::Role, Catalog::parseArrayValues(attribs[Attributes::Roles])).join(ElemSeparator); } void DatabaseExplorerWidget::formatForeignDataWrapperAttribs(attribs_map &attribs) { attribs[Attributes::Options]=Catalog::parseArrayValues(attribs[Attributes::Options]).join(ElemSeparator); formatOidAttribs(attribs, { Attributes::ValidatorFunc, Attributes::HandlerFunc }, ObjectType::Function, false); } void DatabaseExplorerWidget::formatServerAttribs(attribs_map &attribs) { attribs[Attributes::Options]=Catalog::parseArrayValues(attribs[Attributes::Options]).join(ElemSeparator); formatOidAttribs(attribs, { Attributes::Fdw }, ObjectType::ForeignDataWrapper, false); } void DatabaseExplorerWidget::formatUserMappingAttribs(attribs_map &attribs) { attribs[Attributes::Options]=Catalog::parseArrayValues(attribs[Attributes::Options]).join(ElemSeparator); formatOidAttribs(attribs, { Attributes::Owner }, ObjectType::Role, false); formatOidAttribs(attribs, { Attributes::Server }, ObjectType::ForeignServer, false); } QString DatabaseExplorerWidget::formatObjectName(attribs_map &attribs) { try { if(attribs.empty() || attribs[Attributes::Oid].isEmpty() || attribs[Attributes::Oid]==QString("0") || attribs[Attributes::Name].isEmpty()) return(DepNotDefined); else { ObjectType obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); attribs_map aux_attribs; QString oid=attribs[Attributes::Oid], obj_name=DepNotFound.arg(oid), sch_name; if(obj_type!=ObjectType::Type) obj_name=BaseObject::formatName(attribs[Attributes::Name], obj_type==ObjectType::Operator); else obj_name=attribs[Attributes::Name]; //Retrieving the schema name if(!attribs[Attributes::Schema].isEmpty() && attribs[Attributes::Schema]!=QString("0")) { aux_attribs=catalog.getObjectAttributes(ObjectType::Schema, attribs[Attributes::Schema].toUInt()); sch_name=BaseObject::formatName(aux_attribs[Attributes::Name], false); if(!sch_name.isEmpty()) obj_name=sch_name + QString(".") + obj_name; } //Formatting paramenter types for function if(obj_type==ObjectType::Function) { QStringList names, arg_types=Catalog::parseArrayValues(attribs[Attributes::ArgTypes]); for(int idx=0; idx < arg_types.size(); idx++) { names=getObjectName(ObjectType::Type, arg_types[idx]).split('.'); arg_types[idx]=names[names.size()-1]; } obj_name+=QString("(%1)").arg(arg_types.join(',')); } //Formatting paramenter types for operator else if(obj_type==ObjectType::Operator) { QStringList arg_types, names; QString type_name; vector attrib_ids={ Attributes::LeftType, Attributes::RightType }; for(QString attr : attrib_ids) { names=getObjectName(ObjectType::Type, attribs[attr]).split('.'); type_name=names[names.size()-1]; if(type_name.isEmpty()) type_name=QString("-"); arg_types.push_back(type_name); } obj_name+=QString("(%1)").arg(arg_types.join(',')); } return(obj_name); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QStringList DatabaseExplorerWidget::getObjectsNames(ObjectType obj_type, const QStringList &oids, const QString &sch_name, const QString tab_name) { try { if(oids.isEmpty()) return(QStringList{ DepNotDefined }); else { vector attribs_vect; vector oids_vect; map attrs_map; QStringList names; //Converting the oids to unsigned in order to filter them on Catalog for(QString oid : oids) oids_vect.push_back(oid.toUInt()); //Retrieve all the objects by their oids and put them on a auxiliary map in which key is their oids attribs_vect=catalog.getObjectsAttributes(obj_type, sch_name, tab_name, oids_vect); for(attribs_map attr : attribs_vect) attrs_map[attr[Attributes::Oid]]=attr; //Retreving the names from the auxiliary map using the provided oids for(QString oid : oids) names.push_back(formatObjectName(attrs_map[oid])); return(names); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString DatabaseExplorerWidget::getObjectName(ObjectType obj_type, const QString &oid, const QString &sch_name, const QString tab_name) { try { if(oid==QString("0") || oid.isEmpty()) return(DepNotDefined); else { attribs_map attribs=catalog.getObjectAttributes(obj_type, oid.toUInt(), sch_name, tab_name); return(formatObjectName(attribs)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseExplorerWidget::setConnection(Connection conn, const QString &default_db) { this->connection=conn; this->default_db=(default_db.isEmpty() ? QString("postgres") : default_db); } Connection DatabaseExplorerWidget::getConnection(void) { return(connection); } void DatabaseExplorerWidget::clearObjectProperties(void) { properties_tbw->clearContents(); properties_tbw->setRowCount(0); emit s_sourceCodeShowRequested(QString()); } void DatabaseExplorerWidget::listObjects(void) { try { QAction *act=qobject_cast(sender()); bool quick_refresh=(act ? act->data().toBool() : true); configureImportHelper(); objects_trw->blockSignals(true); clearObjectProperties(); if(quick_refresh) QApplication::setOverrideCursor(Qt::WaitCursor); DatabaseImportForm::listObjects(import_helper, objects_trw, false, false, true, quick_refresh, sort_column); QTreeWidgetItem *root = new QTreeWidgetItem, *curr_root = nullptr; //Changing the root item of the generated tree to be a special item containing info about the connected server curr_root = objects_trw->topLevelItem(0); objects_trw->takeTopLevelItem(0); root->setText(0, connection.getConnectionId(true)); root->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("server"))); root->setData(DatabaseImportForm::ObjectId, Qt::UserRole, -1); root->setData(DatabaseImportForm::ObjectTypeId, Qt::UserRole, enum_cast(ObjectType::BaseObject)); root->setData(DatabaseImportForm::ObjectSource, Qt::UserRole, trUtf8("-- Source code unavailable for this kind of object --")); root->addChild(curr_root); objects_trw->addTopLevelItem(root); root->setExpanded(true); root->setSelected(true); objects_trw->setCurrentItem(root); QApplication::restoreOverrideCursor(); objects_trw->blockSignals(false); import_helper.closeConnection(); catalog.closeConnection(); } catch(Exception &e) { QApplication::restoreOverrideCursor(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseExplorerWidget::configureImportHelper(void) { import_helper.setConnection(connection); import_helper.setCurrentDatabase(connection.getConnectionParam(Connection::ParamDbName)); import_helper.setImportOptions(show_sys_objs->isChecked(), show_ext_objs->isChecked(), false, false, false, false, false); catalog.closeConnection(); catalog.setFilter(Catalog::ListAllObjects); catalog.setConnection(connection); } void DatabaseExplorerWidget::handleObject(QTreeWidgetItem *item, int) { if(item->data(DatabaseImportForm::ObjectOtherData, Qt::UserRole).toInt() < 0) { updateItem(item->parent()); } else if(QApplication::mouseButtons()==Qt::MiddleButton && item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toInt() >= 0) { loadObjectSource(); } else if(QApplication::mouseButtons()==Qt::RightButton && item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toInt() >= 0) { ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); unsigned obj_id=item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(); SnippetsConfigWidget::configureSnippetsMenu(&snippets_menu, { obj_type, ObjectType::BaseObject }); for(auto &act : handle_menu.actions()) handle_menu.removeAction(act); handle_menu.addAction(refresh_action); if(obj_id > 0) { if(BaseTable::isBaseTable(obj_type)) handle_menu.addAction(show_data_action); handle_menu.addAction(properties_action); handle_menu.addAction(source_action); if(obj_type!=ObjectType::Cast && obj_type!=ObjectType::Database) handle_menu.addAction(rename_action); if(obj_type!=ObjectType::Database) { handle_menu.addSeparator(); handle_menu.addAction(drop_action); if(obj_type!=ObjectType::Role && obj_type!=ObjectType::ForeignTable && obj_type!=ObjectType::Tablespace) handle_menu.addAction(drop_cascade_action); if(obj_type==ObjectType::Table) { handle_menu.addAction(truncate_action); handle_menu.addAction(trunc_cascade_action); } } } handle_menu.addSeparator(); handle_menu.addMenu(&snippets_menu); QAction *exec_action=handle_menu.exec(QCursor::pos()); if(exec_action==drop_action || exec_action==drop_cascade_action) dropObject(item, exec_action==drop_cascade_action); else if(exec_action==truncate_action || exec_action==trunc_cascade_action) truncateTable(item, exec_action==trunc_cascade_action); else if(exec_action==refresh_action) updateItem(objects_trw->currentItem()); else if(exec_action==rename_action) startObjectRename(item); else if(exec_action==properties_action) showObjectProperties(true); else if(exec_action==source_action) loadObjectSource(); else if(exec_action==show_data_action) { openDataGrid(item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString(), item->text(0), item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt() != enum_cast(ObjectType::View)); } else if(exec_action) handleSelectedSnippet(exec_action->text()); } } void DatabaseExplorerWidget::handleSelectedSnippet(const QString &snip_id) { attribs_map attribs; QTreeWidgetItem *item=objects_trw->currentItem(); ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); loadObjectProperties(); attribs=item->data(DatabaseImportForm::ObjectOtherData, Qt::UserRole).value(); if(attribs.empty()) { QString sch_name=item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString(), tab_name=item->data(DatabaseImportForm::ObjectTable, Qt::UserRole).toString(); //Formatting a schema qualified "table" attribute for table children objects if(TableObject::isTableObject(obj_type) && !sch_name.isEmpty() && !tab_name.isEmpty()) attribs[Attributes::Table]=BaseObject::formatName(sch_name) + QString(".") + BaseObject::formatName(tab_name); } //Formatting the "name" attribute if it is not schema qualified else if(attribs.count(Attributes::Schema) && attribs.count(Attributes::Name) && !attribs[Attributes::Name].contains('.')) { QString obj_name; if(obj_type!=ObjectType::Operator) obj_name=BaseObject::formatName(attribs[Attributes::Name]); else obj_name=attribs[Attributes::Name]; attribs[Attributes::Name]=BaseObject::formatName(attribs[Attributes::Schema]) + QString(".") + obj_name; } if(attribs.count(Attributes::SqlObject)==0) { attribs[Attributes::SqlObject]=BaseObject::getSQLName(obj_type); attribs[Attributes::ObjectType]=BaseObject::getSchemaName(obj_type); } for(auto &attr : attribs) { if(attr.second.contains(ElemSeparator)) attribs[attr.first]=attr.second.replace(ElemSeparator,QString(",")); } emit s_snippetShowRequested(SnippetsConfigWidget::getParsedSnippet(snip_id, attribs)); } attribs_map DatabaseExplorerWidget::extractAttributesFromItem(QTreeWidgetItem *item) { if(!item) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); QString obj_name=item->text(0); int idx=0, idx1=0; attribs_map attribs; QStringList types; attribs[Attributes::SqlObject]=BaseObject::getSQLName(obj_type); attribs[Attributes::DeclInTable]=QString(); attribs[BaseObject::getSchemaName(obj_type)]=Attributes::True; //For cast, operator and function is needed to extract the name and the params types if(obj_type==ObjectType::Operator || obj_type==ObjectType::Function || obj_type==ObjectType::Cast) { idx=obj_name.indexOf('('); idx1=obj_name.indexOf(')'); types=obj_name.mid(idx+1, idx1-idx-1).split(','); types.removeAll(QString("-")); obj_name.remove(idx, obj_name.size()); } else if(obj_type==ObjectType::OpFamily || obj_type==ObjectType::OpClass) obj_name.remove(QRegExp("( )+(\\[)(.)+(\\])")); //Formatting the names attribs[Attributes::Name]=BaseObject::formatName(obj_name, obj_type==ObjectType::Operator); attribs[Attributes::Table]=BaseObject::formatName(item->data(DatabaseImportForm::ObjectTable, Qt::UserRole).toString()); attribs[Attributes::Schema]=BaseObject::formatName(item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString()); //For table objects the "table" attribute must be schema qualified if(obj_type!=ObjectType::Index && TableObject::isTableObject(obj_type)) { attribs[Attributes::Table]=attribs[Attributes::Schema] + QString(".") + attribs[Attributes::Table]; attribs[Attributes::Signature]=attribs[Attributes::Name] + QString(" ON %1").arg(attribs[Attributes::Table]); } //For operators and functions there must exist the signature attribute else if(obj_type==ObjectType::Operator || obj_type==ObjectType::Function) attribs[Attributes::Signature]=attribs[Attributes::Schema] + QString(".") + attribs[Attributes::Name] + QString("(%1)").arg(types.join(ElemSeparator)); else if(obj_type==ObjectType::Cast) attribs[Attributes::Signature]=QString("(%1 AS %2)").arg(types[0]).arg(types[1]); else if(obj_type==ObjectType::OpFamily || obj_type==ObjectType::OpClass) { attribs_map aux_attribs=item->data(DatabaseImportForm::ObjectOtherData, Qt::UserRole).value(); attribs[Attributes::Signature]=QString("%1 USING %2").arg(attribs[Attributes::Name]).arg(aux_attribs[Attributes::IndexType]); } else if(obj_type == ObjectType::UserMapping) { QStringList names = attribs[Attributes::Name].remove('"').split('@'); attribs[Attributes::Signature]=QString("FOR %1 SERVER %2") .arg(BaseObject::formatName(names[0])) .arg(BaseObject::formatName(names[1])); } else { /* If we are handling a view we need to append the MATERIALIZED keyword in the sql-object in order * to construct DDL commands correctly for this kind of object */ if(obj_type==ObjectType::View) { attribs_map aux_attribs=item->data(DatabaseImportForm::ObjectOtherData, Qt::UserRole).value(); if(aux_attribs[Attributes::Materialized] == Attributes::True) { attribs[Attributes::SqlObject] = QString("%1 %2").arg(Attributes::Materialized.toUpper()) .arg(BaseObject::getSQLName(ObjectType::View)); } } if(!attribs[Attributes::Schema].isEmpty() && attribs[Attributes::Name].indexOf(attribs[Attributes::Schema] + QString(".")) < 0) attribs[Attributes::Signature]=attribs[Attributes::Schema] + QString(".") + attribs[Attributes::Name]; else attribs[Attributes::Signature]=attribs[Attributes::Name]; } return(attribs); } void DatabaseExplorerWidget::dropObject(QTreeWidgetItem *item, bool cascade) { Messagebox msg_box; try { if(item && item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt() > 0) { ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); QString msg; QString obj_name=item->data(DatabaseImportForm::ObjectName, Qt::UserRole).toString(); //Roles, tablespaces and user mappings can't be removed in cascade mode if(cascade && (obj_type==ObjectType::Role || obj_type==ObjectType::Tablespace || obj_type == ObjectType::UserMapping)) return; if(!cascade) msg=trUtf8("Do you really want to drop the object %1 (%2)?") .arg(obj_name).arg(BaseObject::getTypeName(obj_type)); else msg=trUtf8("Do you really want to cascade drop the object %1 (%2)? This action will drop all the other objects that depends on it.") .arg(obj_name).arg(BaseObject::getTypeName(obj_type)); msg_box.show(msg, Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { QTreeWidgetItem *parent=nullptr; attribs_map attribs; QString drop_cmd; Connection conn; attribs=extractAttributesFromItem(item); if(obj_type==ObjectType::Operator || obj_type==ObjectType::Function) attribs[Attributes::Signature].replace(ElemSeparator, QChar(',')); //Generate the drop command schparser.ignoreEmptyAttributes(true); schparser.ignoreUnkownAttributes(true); drop_cmd=schparser.getCodeDefinition(Attributes::Drop, attribs, SchemaParser::SqlDefinition); if(cascade) drop_cmd.replace(';', QString(" CASCADE;")); //Executes the drop cmd conn=connection; conn.connect(); conn.executeDDLCommand(drop_cmd); //Updates the object count on the parent item parent=item->parent(); if(parent && parent->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt()==0) { unsigned cnt=parent->data(DatabaseImportForm::ObjectCount, Qt::UserRole).toUInt(); ObjectType parent_type=static_cast(parent->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); cnt--; parent->setText(0, BaseObject::getTypeName(parent_type) + QString(" (%1)").arg(cnt)); parent->setData(DatabaseImportForm::ObjectCount, Qt::UserRole, QVariant::fromValue(cnt)); } if(parent) parent->takeChild(parent->indexOfChild(item)); else objects_trw->takeTopLevelItem(objects_trw->indexOfTopLevelItem(item)); objects_trw->setCurrentItem(nullptr); } } } catch(Exception &e) { msg_box.show(e); } } bool DatabaseExplorerWidget::truncateTable(const QString &sch_name, const QString &obj_name, bool cascade, Connection connection) { try { Messagebox msg_box; QString msg; if(!cascade) msg=trUtf8("Do you really want to truncate the table %1.%2?").arg(sch_name).arg(obj_name); else msg=trUtf8("Do you really want to truncate in cascade mode the table %1.%2? This action will truncate all the tables that depends on it?").arg(sch_name).arg(obj_name); msg_box.setCustomOptionText(trUtf8("Also restart sequences")); msg_box.show(msg, Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { attribs_map attribs; QString truc_cmd; Connection conn; SchemaParser schparser; attribs[Attributes::SqlObject]=BaseObject::getSQLName(ObjectType::Table); attribs[Attributes::Signature]=QString("%1.%2").arg(BaseObject::formatName(sch_name)).arg(BaseObject::formatName(obj_name)); attribs[Attributes::Cascade]=(cascade ? Attributes::True : ""); attribs[Attributes::RestartSeq]=(msg_box.isCustomOptionChecked() ? Attributes::True : ""); //Generate the truncate command schparser.ignoreEmptyAttributes(true); schparser.ignoreUnkownAttributes(true); truc_cmd=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::AlterSchemaDir + GlobalAttributes::DirSeparator + Attributes::Truncate + GlobalAttributes::SchemaExt, attribs); //Executes the truncate cmd conn = connection; conn.connect(); conn.executeDDLCommand(truc_cmd); } return(msg_box.result()==QDialog::Accepted); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__); } } void DatabaseExplorerWidget::truncateTable(QTreeWidgetItem *item, bool cascade) { try { if(item && item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt() > 0) { QString obj_name, sch_name; obj_name=item->data(DatabaseImportForm::ObjectName, Qt::UserRole).toString(); sch_name=BaseObject::formatName(item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString()); truncateTable(sch_name, obj_name, cascade, connection); } } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } void DatabaseExplorerWidget::updateItem(QTreeWidgetItem *item) { if(item && item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toInt() >= 0) { QTreeWidgetItem *root=nullptr, *parent=nullptr, *aux_item=nullptr; ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); unsigned obj_id=item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(); QString sch_name, tab_name; vector gen_items; QApplication::setOverrideCursor(Qt::WaitCursor); if(obj_type==ObjectType::Database) listObjects(); else { clearObjectProperties(); parent=item->parent(); sch_name=item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString(); tab_name=item->data(DatabaseImportForm::ObjectTable, Qt::UserRole).toString(); if(parent) { if(obj_id==0) { root=parent; parent->takeChild(parent->indexOfChild(item)); } else { if(obj_type==ObjectType::Schema || BaseTable::isBaseTable(obj_type)) { root=item; root->takeChildren(); if(obj_type == ObjectType::Schema) sch_name=item->text(0); else tab_name=item->text(0); } else { root=parent->parent(); root->takeChild(root->indexOfChild(parent)); } } } configureImportHelper(); //Updates the group type only if(obj_id==0 || (!BaseTable::isBaseTable(obj_type) && obj_type!=ObjectType::Schema)) gen_items=DatabaseImportForm::updateObjectsTree(import_helper, objects_trw, { obj_type }, false, false, root, sch_name, tab_name, sort_column); else //Updates all child objcts when the selected object is a schema or table or view gen_items=DatabaseImportForm::updateObjectsTree(import_helper, objects_trw, BaseObject::getChildObjectTypes(obj_type), false, false, root, sch_name, tab_name, sort_column); //Creating dummy items for schemas and tables if(obj_type==ObjectType::Schema || BaseTable::isBaseTable(obj_type)) { for(auto &item : gen_items) { aux_item=new QTreeWidgetItem(item); aux_item->setText(0, QString("...")); aux_item->setData(DatabaseImportForm::ObjectOtherData, Qt::UserRole, QVariant::fromValue(-1)); } } import_helper.closeConnection(); objects_trw->sortItems(sort_column, Qt::AscendingOrder); objects_trw->setCurrentItem(nullptr); if(BaseTable::isBaseTable(obj_type)) { objects_trw->blockSignals(true); objects_trw->setCurrentItem(item); showObjectProperties(true); objects_trw->setCurrentItem(nullptr); objects_trw->blockSignals(false); } } QApplication::restoreOverrideCursor(); } } void DatabaseExplorerWidget::loadObjectProperties(bool force_reload) { try { QTreeWidgetItem *item=objects_trw->currentItem(); unsigned oid=item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(); if(oid != 0 || (item == objects_trw->topLevelItem(0))) { ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); attribs_map orig_attribs, fmt_attribs; //First, retrieve the attributes stored on the item as a result of a previous properties listing orig_attribs=item->data(DatabaseImportForm::ObjectAttribs, Qt::UserRole).value(); //In case of the cached attributes are empty if(orig_attribs.empty() || force_reload) { QApplication::setOverrideCursor(Qt::WaitCursor); catalog.setConnection(connection); //Loading the server properties if(item == objects_trw->topLevelItem(0)) orig_attribs=catalog.getServerAttributes(); //Retrieve them from the catalog else if(obj_type!=ObjectType::Column) { orig_attribs=catalog.getObjectAttributes(obj_type, oid); if(obj_type == ObjectType::Table) { vector ref_fks; attribs_map ref_table, ref_schema; QStringList tab_list; ref_fks = catalog.getObjectsAttributes(ObjectType::Constraint, QString(), QString(), {}, {{ Attributes::CustomFilter, QString("contype='f' AND cs.confrelid=%1").arg(orig_attribs[Attributes::Oid])}}); for(auto &fk : ref_fks) { ref_table = catalog.getObjectAttributes(ObjectType::Table, fk[Attributes::Table].toUInt()); ref_schema = catalog.getObjectAttributes(ObjectType::Schema, ref_table[Attributes::Schema].toUInt()); tab_list.push_back(QString("%1.%2").arg(ref_schema[Attributes::Name]).arg(ref_table[Attributes::Name])); } if(!tab_list.isEmpty()) orig_attribs[Attributes::Referrers] = tab_list.join(Table::DataSeparator); } } else { QString tab_name=item->data(DatabaseImportForm::ObjectTable, Qt::UserRole).toString(), sch_name=item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString(); vector vect_attribs=catalog.getObjectsAttributes(obj_type, sch_name, tab_name, { oid }); if(!vect_attribs.empty()) orig_attribs=vect_attribs[0]; } //Format values and translate the attribute names fmt_attribs=formatObjectAttribs(orig_attribs); fmt_attribs.erase(Attributes::Signature); //Store the original attributes on the item to permit value replacements when using code snippets item->setData(DatabaseImportForm::ObjectOtherData, Qt::UserRole, QVariant::fromValue(orig_attribs)); //Store the attributes on the item to avoid repeatedly query the database item->setData(DatabaseImportForm::ObjectAttribs, Qt::UserRole, QVariant::fromValue(fmt_attribs)); if(item != objects_trw->topLevelItem(0)) item->setData(DatabaseImportForm::ObjectSource, Qt::UserRole, DefaultSourceCode); catalog.closeConnection(); QApplication::restoreOverrideCursor(); } } } catch(Exception &e) { QApplication::restoreOverrideCursor(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseExplorerWidget::showObjectProperties(bool force_reload) { try { QTreeWidgetItem *item=objects_trw->currentItem(); clearObjectProperties(); if(item && ((item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toInt() >= 0) || (item == objects_trw->topLevelItem(0)))) { attribs_map cached_attribs; QTableWidgetItem *tab_item=nullptr; QStringList values; int row=0; QFont font; loadObjectProperties(force_reload); cached_attribs=item->data((raw_attrib_names_chk->isChecked() ? DatabaseImportForm::ObjectOtherData : DatabaseImportForm::ObjectAttribs), Qt::UserRole).value(); properties_tbw->setSortingEnabled(false); if(!cached_attribs.empty()) { for(auto &attrib : cached_attribs) { properties_tbw->insertRow(properties_tbw->rowCount()); row=properties_tbw->rowCount() - 1; //Creates the property name item tab_item=new QTableWidgetItem; font=tab_item->font(); font.setItalic(true); tab_item->setText(attrib.first); tab_item->setFont(font); tab_item->setIcon(QPixmap(PgModelerUiNs::getIconPath("attribute"))); properties_tbw->setItem(row, 0, tab_item); values=attrib.second.split(ElemSeparator); //Creating the value item if(values.size() >= 2) { //If the values contatins more the one item, the a combo box will be placed instead of the text QComboBox *combo=new QComboBox; combo->setStyleSheet(QString("border: 0px")); combo->addItems(values); properties_tbw->setCellWidget(row, 1, combo); } else { tab_item=new QTableWidgetItem; tab_item->setText(attrib.second); properties_tbw->setItem(row, 1, tab_item); //If the value contains multiple lines, configures the tooltip to expose the complete form of the value if(attrib.second.contains('\n') || attrib.second.length() > 30) tab_item->setToolTip(attrib.second); } } cached_attribs=item->data(DatabaseImportForm::ObjectOtherData,Qt::UserRole).value(); if(cached_attribs[Attributes::ObjectType]==BaseObject::getSchemaName(ObjectType::Constraint) && item->childCount()==0) { QTreeWidgetItem *fk_item=nullptr, *src_item=nullptr; if(cached_attribs[Attributes::Type]==~ConstraintType(ConstraintType::ForeignKey)) { /* Creates two items denoting the source columns and referenced tables. These items have a negative id indicating that no popup menu will be show if user right-click them. */ src_item=new QTreeWidgetItem(item); src_item->setData(DatabaseImportForm::ObjectId, Qt::UserRole, QVariant::fromValue(-1)); src_item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("column"))); src_item->setText(0, QString("%1(%2)") .arg(cached_attribs[Attributes::Table]) .arg(cached_attribs[Attributes::SrcColumns])); src_item->setToolTip(0, trUtf8("Src. table: %1\nSrc. column(s): %2") .arg(cached_attribs[Attributes::Table]) .arg(cached_attribs[Attributes::SrcColumns])); src_item->setFlags(Qt::ItemIsEnabled); fk_item=new QTreeWidgetItem(item); fk_item->setData(DatabaseImportForm::ObjectId, Qt::UserRole, QVariant::fromValue(-1)); fk_item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("referenced"))); fk_item->setText(0, QString("%1(%2)") .arg(cached_attribs[Attributes::RefTable]) .arg(cached_attribs[Attributes::DstColumns])); fk_item->setToolTip(0, trUtf8("Ref. table: %1\nRef. column(s): %2") .arg(cached_attribs[Attributes::RefTable]) .arg(cached_attribs[Attributes::DstColumns])); fk_item->setFlags(Qt::ItemIsEnabled); } else if(cached_attribs[Attributes::Type]==~ConstraintType(ConstraintType::Unique) || cached_attribs[Attributes::Type]==~ConstraintType(ConstraintType::PrimaryKey)) { QStringList columns=cached_attribs[Attributes::SrcColumns].split(ElemSeparator); for(auto &col : columns) { src_item=new QTreeWidgetItem(item); src_item->setData(DatabaseImportForm::ObjectId, Qt::UserRole, QVariant::fromValue(-1)); src_item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("column"))); src_item->setText(0, col); src_item->setFlags(Qt::ItemIsEnabled); } } } else if(cached_attribs[Attributes::ObjectType] == BaseObject::getSchemaName(ObjectType::Table) && !cached_attribs[Attributes::Referrers].isEmpty() && item->childCount() == 5) { QTreeWidgetItem *refs_item=nullptr, *tab_item=nullptr; QStringList ref_tab_names = cached_attribs[Attributes::Referrers].split(Table::DataSeparator); QFont font; refs_item=new QTreeWidgetItem(item); font = refs_item->font(0); font.setItalic(true); refs_item->setFont(0, font); refs_item->setData(DatabaseImportForm::ObjectId, Qt::UserRole, QVariant::fromValue(-1)); refs_item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("referrer"))); refs_item->setText(0, QString("%1 (%2)") .arg(attribs_i18n.at(Attributes::Referrers)) .arg(ref_tab_names.length())); for(QString tab_name : ref_tab_names) { tab_item=new QTreeWidgetItem(refs_item); tab_item->setData(DatabaseImportForm::ObjectId, Qt::UserRole, QVariant::fromValue(-1)); tab_item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("table"))); tab_item->setText(0, tab_name); tab_item->setFlags(Qt::ItemIsEnabled); } } } emit s_sourceCodeShowRequested(item->data(DatabaseImportForm::ObjectSource, Qt::UserRole).toString()); properties_tbw->setSortingEnabled(true); properties_tbw->sortByColumn(0, Qt::AscendingOrder); properties_tbw->resizeColumnToContents(0); } properties_tbw->horizontalHeader()->setVisible(properties_tbw->rowCount() > 0); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseExplorerWidget::startObjectRename(QTreeWidgetItem *item) { if(item && item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt() > 0) { ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); if(obj_type!=ObjectType::Cast && obj_type!=ObjectType::Database) { item->setFlags(item->flags() | Qt::ItemIsEditable); objects_trw->openPersistentEditor(item); rename_item=item; rename_item->setData(DatabaseImportForm::ObjectOtherData, Qt::UserRole, rename_item->text(0)); } } } void DatabaseExplorerWidget::finishObjectRename(void) { Messagebox msg_box; try { if(rename_item) { QString rename_cmd; Connection conn=connection; attribs_map attribs=extractAttributesFromItem(rename_item); ObjectType obj_type=static_cast(rename_item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); objects_trw->closePersistentEditor(rename_item); attribs[Attributes::NewName]=BaseObject::formatName(rename_item->text(0), obj_type==ObjectType::Operator); //Generate the drop command schparser.ignoreEmptyAttributes(true); schparser.ignoreUnkownAttributes(true); rename_cmd=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::AlterSchemaDir + GlobalAttributes::DirSeparator + Attributes::Rename + GlobalAttributes::SchemaExt, attribs); //Executes the rename cmd conn.connect(); conn.executeDDLCommand(rename_cmd); rename_item->setFlags(rename_item->flags() ^ Qt::ItemIsEditable); rename_item=nullptr; } } catch(Exception &e) { cancelObjectRename(); msg_box.show(e); } } void DatabaseExplorerWidget::cancelObjectRename(void) { if(rename_item) { objects_trw->closePersistentEditor(rename_item); rename_item->setFlags(rename_item->flags() ^ Qt::ItemIsEditable); rename_item->setText(0, rename_item->data(DatabaseImportForm::ObjectOtherData, Qt::UserRole).toString()); rename_item=nullptr; } } void DatabaseExplorerWidget::loadObjectSource(void) { QTreeWidgetItem *item=objects_trw->currentItem(); try { if(item == objects_trw->topLevelItem(0)) { QString n = item->text(0); emit s_sourceCodeShowRequested(item->data(DatabaseImportForm::ObjectSource, Qt::UserRole).toString()); } else if(item) { QString source=item->data(DatabaseImportForm::ObjectSource, Qt::UserRole).toString(); if(source!=DefaultSourceCode) { emit s_sourceCodeShowRequested(source); } else { DatabaseModel dbmodel; DatabaseImportHelper import_hlp; ObjectType obj_type=static_cast(item->data(DatabaseImportForm::ObjectTypeId, Qt::UserRole).toUInt()); QString sch_name, tab_name, name; QTreeWidgetItem *sch_item=nullptr; BaseObject *object=nullptr; BaseObject *schema=nullptr; attribs_map attribs=item->data(DatabaseImportForm::ObjectOtherData, Qt::UserRole).value(); bool is_column=false; unsigned oid=item->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(), db_oid=objects_trw->topLevelItem(0)->child(0)->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(), sys_oid=0; int sbar_value=(objects_trw->verticalScrollBar() ? objects_trw->verticalScrollBar()->value() : 0); QApplication::setOverrideCursor(Qt::WaitCursor); sch_name=item->data(DatabaseImportForm::ObjectSchema, Qt::UserRole).toString(); tab_name=item->data(DatabaseImportForm::ObjectTable, Qt::UserRole).toString(); name=item->data(DatabaseImportForm::ObjectName, Qt::UserRole).toString(); if(!sch_name.isEmpty() && obj_type!=ObjectType::Extension) { if(tab_name.isEmpty()) name.prepend(sch_name + QChar('.')); else tab_name.prepend(sch_name + QChar('.')); } //Special case for columns. We will retrieve the table from database and then generate the code for the column if(obj_type==ObjectType::Column) { oid=item->parent()->parent()->data(DatabaseImportForm::ObjectId, Qt::UserRole).toUInt(); is_column=true; obj_type=ObjectType::Table; } //Importing the object and its dependencies dbmodel.createSystemObjects(false); import_hlp.setConnection(connection); import_hlp.setCurrentDatabase(connection.getConnectionParam(Connection::ParamDbName)); import_hlp.setImportOptions(show_sys_objs->isChecked(), show_ext_objs->isChecked(), true, false, false, false, false); import_hlp.setSelectedOIDs(&dbmodel, {{ObjectType::Database, {db_oid}}, {obj_type,{oid}}}, {}); sys_oid=import_hlp.getLastSystemOID(); //Currently pgModeler does not support the visualization of base types and built-in ones if(obj_type==ObjectType::Type && (oid <= sys_oid || attribs[Attributes::Configuration]==Attributes::BaseType)) { source=QString("-- %1 --").arg(trUtf8("Source code genaration for built-in and base types currently unavailable.")); emit s_sourceCodeShowRequested(source); } else { import_hlp.importDatabase(); if(obj_type==ObjectType::Database) source=getObjectSource(&dbmodel, &dbmodel); else { /* Fixing the signature of opclasses and opfamilies. The name is in form "name [index type]", so we change it to "name USING [index type]" */ if(obj_type==ObjectType::OpClass || obj_type==ObjectType::OpFamily) { QString idx_type=item->text(0); idx_type.remove(0, idx_type.indexOf(QChar('[')) + 1); idx_type.remove(QChar(']')); name=QString("%1 USING %2").arg(name).arg(idx_type); } //Generating the code for table child object if(TableObject::isTableObject(obj_type) || is_column) { PhysicalTable *table=nullptr; table=dynamic_cast(dbmodel.getObject(tab_name, {ObjectType::Table, ObjectType::ForeignTable})); QTreeWidgetItem *table_item=nullptr; //If the table was imported then the source code of it will be placed on the respective item if(table) { table_item=item->parent()->parent(); objects_trw->setCurrentItem(item->parent()->parent()); table_item->setData(DatabaseImportForm::ObjectSource, Qt::UserRole, getObjectSource(table, &dbmodel)); sch_item=table_item->parent()->parent(); schema=table->getSchema(); //Generate the code of table children objects as ALTER commands table->setGenerateAlterCmds(true); object=table->getObject(name, (is_column ? ObjectType::Column : obj_type)); } } else { object=dbmodel.getObject(name, obj_type); schema=object->getSchema(); } if(object) source=getObjectSource(object, &dbmodel); else source=QString("-- %1 --").arg(trUtf8("Source code unavailable for the object %1 (%2).").arg(name).arg(BaseObject::getTypeName(obj_type))); } } //Generating the schema code and assigning it to the respective items if(schema) { if(!sch_item) sch_item=item->parent()->parent(); objects_trw->setCurrentItem(sch_item); sch_item->setData(DatabaseImportForm::ObjectSource, Qt::UserRole, getObjectSource(schema, &dbmodel)); } if(obj_type != ObjectType::Database) { //Generating the code for the database itself and storing it in the first child of the root item in the tree objects_trw->setCurrentItem(objects_trw->topLevelItem(0)); objects_trw->topLevelItem(0)->child(0)->setData(DatabaseImportForm::ObjectSource, Qt::UserRole, getObjectSource(&dbmodel, &dbmodel)); } item->setData(DatabaseImportForm::ObjectSource, Qt::UserRole, source); objects_trw->setCurrentItem(item); /* Restore the position of the scrollbar in the tree because the usage of setCurrentItem in previous lines may cause the scrollbar to change its original value */ if(objects_trw->verticalScrollBar()) objects_trw->verticalScrollBar()->setValue(sbar_value); QApplication::restoreOverrideCursor(); emit s_sourceCodeShowRequested(source); } } } catch (Exception &e) { QApplication::restoreOverrideCursor(); emit s_sourceCodeShowRequested(QString("/* Could not generate source code due to one or more errors! \n \n %1 */").arg(e.getExceptionsText())); } } void DatabaseExplorerWidget::filterObjects(void) { DatabaseImportForm::filterObjects(objects_trw, filter_edt->text(), (by_oid_chk->isChecked() ? DatabaseImportForm::ObjectId : 0), false); } QString DatabaseExplorerWidget::getObjectSource(BaseObject *object, DatabaseModel *dbmodel) { if(!object || !dbmodel) return QString(); vector perms; QString source; dbmodel->getPermissions(object, perms); object->setSystemObject(false); object->setSQLDisabled(false); object->setCodeInvalidated(true); if(object!=dbmodel) source=object->getCodeDefinition(SchemaParser::SqlDefinition); else source=dbmodel->__getCodeDefinition(SchemaParser::SqlDefinition); for(auto &perm : perms) source+=perm->getCodeDefinition(SchemaParser::SqlDefinition); return(source); } void DatabaseExplorerWidget::openDataGrid(const QString &schema, const QString &table, bool hide_views) { DataManipulationForm *data_manip=new DataManipulationForm; Connection conn=Connection(this->connection.getConnectionParams()); data_manip->setWindowModality(Qt::NonModal); data_manip->setAttribute(Qt::WA_DeleteOnClose, true); data_manip->hide_views_chk->setChecked(hide_views); data_manip->setAttributes(conn, schema, table); PgModelerUiNs::resizeDialog(data_manip); GeneralConfigWidget::restoreWidgetGeometry(data_manip); data_manip->show(); } void DatabaseExplorerWidget::dropDatabase(void) { Messagebox msg_box; QString dbname = connection.getConnectionParam(Connection::ParamDbName); msg_box.show(trUtf8("Warning"), trUtf8("CAUTION: You are about to drop the entire database %1 from the server %2! All data will be completely wiped out. Do you really want to proceed?") .arg(dbname).arg(connection.getConnectionId(true)), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { try { Connection conn=Connection(connection.getConnectionParams()); conn.setConnectionParam(Connection::ParamDbName, default_db); conn.connect(); conn.executeDDLCommand(QString("DROP DATABASE \"%1\";").arg(dbname)); conn.close(); this->setEnabled(false); emit s_databaseDropped(dbname); } catch(Exception &e) { if(connection.getConnectionParam(Connection::ParamDbName) == default_db) throw Exception(Exception::getErrorMessage(ErrorCode::DropCurrentDBDefault) .arg(dbname).arg(connection.getConnectionParam(Connection::ParamAlias)), ErrorCode::DropCurrentDBDefault,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } pgmodeler-0.9.2/libpgmodeler_ui/src/databaseexplorerwidget.h000066400000000000000000000205371360462764600243600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DatabaseExplorerWidge \brief Implements the operations to browse and manipulate database instances */ #ifndef DATABASE_EXPLORER_WIDGET_H #define DATABASE_EXPLORER_WIDGET_H #include "ui_databaseexplorerwidget.h" #include "databaseimporthelper.h" #include "schemaparser.h" #include "hinttextwidget.h" class DatabaseExplorerWidget: public QWidget, public Ui::DatabaseExplorerWidget { private: Q_OBJECT static const QString DepNotDefined, DepNotFound, ElemSeparator, DefaultSourceCode; //! \brief Stores the translations of all used attributes at properties panel static const attribs_map attribs_i18n; /*! \brief Connection used to handle objects on database. This connection is copied whenever a new operation must be performed on database */ Connection connection; QString default_db; //! \brief Database import helper used to list objects from current connection DatabaseImportHelper import_helper; //! \brief Catalog instance used to retrieve object's attributes Catalog catalog; SchemaParser schparser; //! \brief Stores the actions to be performed over the object QMenu handle_menu, //! \brief Stores the snippets' actions snippets_menu, toggle_disp_menu; QAction *copy_action, *drop_action, *drop_cascade_action, *show_data_action, *refresh_action, *properties_action, *trunc_cascade_action, *truncate_action, *rename_action, *source_action, *show_sys_objs, *show_ext_objs; QTreeWidgetItem *rename_item; HintTextWidget *filter_ht; unsigned sort_column; void configureImportHelper(void); //! \brief Drops the object represented by the specified item void dropObject(QTreeWidgetItem *item, bool cascade); //! \brief Truncates the table represented by the specified item void truncateTable(QTreeWidgetItem *item, bool cascade); //! \brief Marks the item as editable so that the user can change its name void startObjectRename(QTreeWidgetItem *item); bool eventFilter(QObject *object, QEvent *event); /*! \brief Returns the properly format object name by querying it using its OID and type. Optional schema and table names can be specified to filter the results */ QString getObjectName(ObjectType obj_type, const QString &oid, const QString &sch_name=QString(), const QString tab_name=QString()); /*! \brief Returns the properly format list of object names by querying them using their OIDs and type. Optional schema and table names can be specified to filter the results */ QStringList getObjectsNames(ObjectType obj_type, const QStringList &oids, const QString &sch_name=QString(), const QString tab_name=QString()); //! \brief Format the object's name based upon the passed attributes QString formatObjectName(attribs_map &attribs); /*! \brief Formats the keys and values for the passed object attributes returning a new map with the formatted attributes. This method do basic formattation on commom attributes and internally call the format[OBJECT]Attribs() method according to the object being currently processed. NOTE: the original 'attribs' has its value changed but the keys are preserved. */ attribs_map formatObjectAttribs(attribs_map &attribs); //! \brief Formats the boolean attributes translating the 1 ou "" values to true or false void formatBooleanAttribs(attribs_map &attribs, QStringList bool_attrs); //! \brief Convert oid attributes (or array of oids) in object names by querying it on catalog void formatOidAttribs(attribs_map &attribs, QStringList oid_attrs, ObjectType obj_type, bool is_oid_array); void formatCastAttribs(attribs_map &attribs); void formatLanguageAttribs(attribs_map &attribs); void formatRoleAttribs(attribs_map &attribs); void formatEventTriggerAttribs(attribs_map &attribs); void formatAggregateAttribs(attribs_map &attribs); void formatConversionAttribs(attribs_map &attribs); void formatDomainAttribs(attribs_map &attribs); void formatExtensionAttribs(attribs_map &attribs); void formatFunctionAttribs(attribs_map &attribs); void formatOperatorAttribs(attribs_map &attribs); void formatTableAttribs(attribs_map &attribs); void formatSequenceAttribs(attribs_map &attribs); void formatViewAttribs(attribs_map &attribs); void formatTypeAttribs(attribs_map &attribs); void formatOperatorClassAttribs(attribs_map &attribs); void formatTriggerAttribs(attribs_map &attribs); void formatRuleAttribs(attribs_map &attribs); void formatColumnAttribs(attribs_map &attribs); void formatConstraintAttribs(attribs_map &attribs); void formatIndexAttribs(attribs_map &attribs); void formatPolicyAttribs(attribs_map &attribs); void formatForeignDataWrapperAttribs(attribs_map &attribs); void formatServerAttribs(attribs_map &attribs); void formatUserMappingAttribs(attribs_map &attribs); void handleSelectedSnippet(const QString &snip_id); //! \brief Extract an attribute map containing the basic attributes for drop/rename commands attribs_map extractAttributesFromItem(QTreeWidgetItem *item); //! \brief Updates the selected tree item void updateItem(QTreeWidgetItem *item); //! \brief Generate the SQL code for the specified object appending the permissions code for it as well QString getObjectSource(BaseObject *object, DatabaseModel *dbmodel); public: DatabaseExplorerWidget(QWidget * parent = nullptr); //! \brief Configures the connection used to retrieve and manipulate objects on database void setConnection(Connection conn, const QString &default_db); //! \brief Returns a copy of the connection used by this explorer instance Connection getConnection(void); //! \brief Clears the object's properties table void clearObjectProperties(void); //! \brief Truncates a named table (in cascade mode or not) using the provided connection static bool truncateTable(const QString &sch_name, const QString &obj_name, bool cascade, Connection connection); public slots: //! \brief Lists all objects for the current selected database void listObjects(void); private slots: //! \brief Shows the menu to drop/show data void handleObject(QTreeWidgetItem *item, int); /*! \brief Loads the catalog properties of a selected object and stores them in the current selected item, the force_reload parameter is used to ignore the cached properties and retrieve them again */ void loadObjectProperties(bool force_reload=false); /*! \brief Loads (calling loadObjectProperties) and expose the attributes of the object in the properties grid, the force_reload parameter is used to ignore the cached properties and retrieve them again */ void showObjectProperties(bool force_reload=false); //! \brief Executes the rename command on the database void finishObjectRename(void); //! \brief Cancels the rename and restore the original item's name void cancelObjectRename(void); //! \brief Show the widget to handle data in tables void openDataGrid(const QString &schema=QString("public"), const QString &table=QString(), bool hide_views=true); //! \brief Drop the database void dropDatabase(void); void loadObjectSource(void); void filterObjects(void); signals: //! \brief This signal is emmited to indicate that a sql execution widget need to be opened void s_sqlExecutionRequested(void); //! \brief This signal is emmited to indicate that the named database was dropped void s_databaseDropped(QString dbname); //! \brief This signal is emmited containing the processed snippet to be shown in an input field void s_snippetShowRequested(QString snippet); //! \brief This signal is emmited containing the source code to be shown in an input field void s_sourceCodeShowRequested(QString source); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/databaseimportform.cpp000066400000000000000000000702351360462764600240450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "databaseimportform.h" #include "taskprogresswidget.h" #include "configurationform.h" #include "taskprogresswidget.h" #include "pgmodeleruins.h" #include "pgmodelerns.h" bool DatabaseImportForm::low_verbosity = false; DatabaseImportForm::DatabaseImportForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); model_wgt=nullptr; create_model=true; htmlitem_del=new HtmlItemDelegate(this); output_trw->setItemDelegateForColumn(0, htmlitem_del); rand_color_ht=new HintTextWidget(rand_color_hint, this); rand_color_ht->setText(rand_rel_color_chk->statusTip()); auto_res_deps_ht=new HintTextWidget(auto_res_deps_hint, this); auto_res_deps_ht->setText(resolve_deps_chk->statusTip()); imp_sys_objs_ht=new HintTextWidget(imp_sys_objs_hint, this); imp_sys_objs_ht->setText(import_sys_objs_chk->statusTip()); imp_ext_objs_ht=new HintTextWidget(imp_ext_objs_hint, this); imp_ext_objs_ht->setText(import_ext_objs_chk->statusTip()); debug_mode_ht=new HintTextWidget(debug_mode_hint, this); debug_mode_ht->setText(debug_mode_chk->statusTip()); ignore_errors_ht=new HintTextWidget(ignore_errors_hint, this); ignore_errors_ht->setText(ignore_errors_chk->statusTip()); import_to_model_ht=new HintTextWidget(import_to_model_hint, this); import_to_model_ht->setText(import_to_model_chk->statusTip()); settings_tbw->setTabEnabled(1, false); objs_parent_wgt->setEnabled(false); connect(close_btn, SIGNAL(clicked(bool)), this, SLOT(close(void))); connect(connections_cmb, SIGNAL(activated(int)), this, SLOT(listDatabases(void))); connect(database_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(listObjects(void))); connect(import_sys_objs_chk, SIGNAL(clicked(bool)), this, SLOT(listObjects(void))); connect(import_ext_objs_chk, SIGNAL(clicked(bool)), this, SLOT(listObjects(void))); connect(by_oid_chk, SIGNAL(toggled(bool)), this, SLOT(filterObjects(void))); connect(expand_all_tb, SIGNAL(clicked(bool)), db_objects_tw, SLOT(expandAll(void))); connect(collapse_all_tb, SIGNAL(clicked(bool)), db_objects_tw, SLOT(collapseAll(void))); connect(db_objects_tw, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(setItemCheckState(QTreeWidgetItem*,int))); connect(select_all_tb, SIGNAL(clicked(bool)), this, SLOT(setItemsCheckState(void))); connect(clear_all_tb, SIGNAL(clicked(bool)), this, SLOT(setItemsCheckState(void))); connect(filter_edt, SIGNAL(textChanged(QString)), this, SLOT(filterObjects(void))); connect(import_btn, SIGNAL(clicked(bool)), this, SLOT(importDatabase(void))); connect(cancel_btn, SIGNAL(clicked(bool)), this, SLOT(cancelImport(void))); connect(import_to_model_chk, &QCheckBox::toggled, [&](bool checked){ create_model=!checked; }); connect(database_cmb, &QComboBox::currentTextChanged, [&]() { if(database_cmb->currentIndex()==0) db_objects_tw->clear(); import_btn->setEnabled(database_cmb->currentIndex() > 0); objs_parent_wgt->setEnabled(database_cmb->currentIndex() > 0); }); #ifdef DEMO_VERSION #warning "DEMO VERSION: forcing ignore errors in reverse engineering due to the object count limit." ignore_errors_chk->setChecked(true); ignore_errors_chk->setEnabled(false); #endif } DatabaseImportForm::~DatabaseImportForm(void) { destroyThread(); } void DatabaseImportForm::setModelWidget(ModelWidget *model) { model_wgt=model; import_to_model_chk->setEnabled(model!=nullptr); } void DatabaseImportForm::setLowVerbosity(bool value) { low_verbosity = value; } void DatabaseImportForm::createThread(void) { import_thread=new QThread; import_helper=new DatabaseImportHelper; import_helper->moveToThread(import_thread); connect(import_thread, &QThread::started, [&](){ output_trw->setUniformRowHeights(true); }); connect(import_thread, &QThread::finished, [&](){ output_trw->setUniformRowHeights(false); }); connect(import_thread, SIGNAL(started(void)), import_helper, SLOT(importDatabase())); connect(import_helper, SIGNAL(s_importCanceled()), this, SLOT(handleImportCanceled())); connect(import_helper, SIGNAL(s_importFinished(Exception)), this, SLOT(handleImportFinished(Exception))); connect(import_helper, SIGNAL(s_importAborted(Exception)), this, SLOT(captureThreadError(Exception))); connect(import_helper, SIGNAL(s_progressUpdated(int,QString,ObjectType)), this, SLOT(updateProgress(int,QString,ObjectType)), Qt::BlockingQueuedConnection); } void DatabaseImportForm::destroyThread(void) { if(import_thread) { import_thread->quit(); import_thread->wait(); delete(import_thread); import_thread=nullptr; delete(import_helper); import_helper=nullptr; } } void DatabaseImportForm::updateProgress(int progress, QString msg, ObjectType obj_type) { QPixmap ico; msg=PgModelerUiNs::formatMessage(msg); progress_lbl->setText(msg); progress_pb->setValue(progress); if(obj_type!=ObjectType::BaseObject) ico=QPixmap(PgModelerUiNs::getIconPath(obj_type)); else ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_info")); ico_lbl->setPixmap(ico); if(!low_verbosity) PgModelerUiNs::createOutputTreeItem(output_trw, msg, ico); } void DatabaseImportForm::setItemCheckState(QTreeWidgetItem *item, int) { db_objects_tw->blockSignals(true); setItemCheckState(item, item->checkState(0)); setParentItemChecked(item->parent()); import_btn->setEnabled(hasCheckedItems()); db_objects_tw->blockSignals(false); } void DatabaseImportForm::setItemsCheckState(void) { QTreeWidgetItemIterator itr(db_objects_tw); Qt::CheckState chk_state=(sender()==select_all_tb ? Qt::Checked : Qt::Unchecked); db_objects_tw->blockSignals(true); while(*itr) { if(!(*itr)->isDisabled()) (*itr)->setCheckState(0, chk_state); ++itr; } db_objects_tw->blockSignals(false); import_btn->setEnabled(hasCheckedItems()); } void DatabaseImportForm::importDatabase(void) { try { Messagebox msg_box; map> obj_oids; map> col_oids; if(import_to_model_chk->isChecked()) { msg_box.show(trUtf8("ATTENTION: You are about to import objects to the current working model! This action will cause irreversible changes to it even in case of critical errors during the process. Do you want to proceed?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Rejected) return; } output_trw->clear(); settings_tbw->setTabEnabled(1, true); settings_tbw->setCurrentIndex(1); if(low_verbosity) PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Low verbosity is set: only key informations and errors will be displayed."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), nullptr, false); getCheckedItems(obj_oids, col_oids); obj_oids[ObjectType::Database].push_back(database_cmb->itemData(database_cmb->currentIndex()).value()); if(create_model) { model_wgt=new ModelWidget; model_wgt->getDatabaseModel()->createSystemObjects(true); } model_wgt->setUpdatesEnabled(false); import_helper->setImportOptions(import_sys_objs_chk->isChecked(), import_ext_objs_chk->isChecked(), resolve_deps_chk->isChecked(), ignore_errors_chk->isChecked(), debug_mode_chk->isChecked(), rand_rel_color_chk->isChecked(), true); import_helper->setSelectedOIDs(model_wgt->getDatabaseModel(), obj_oids, col_oids); import_thread->start(); cancel_btn->setEnabled(true); import_btn->setEnabled(false); database_gb->setEnabled(false); options_gb->setEnabled(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportForm::setItemCheckState(QTreeWidgetItem *item, Qt::CheckState chk_state) { for(int i=0; i < item->childCount(); i++) { if(!item->child(i)->isDisabled() && !db_objects_tw->isItemHidden(item->child(i))) item->child(i)->setCheckState(0, chk_state); setItemCheckState(item->child(i), chk_state); } } void DatabaseImportForm::setParentItemChecked(QTreeWidgetItem *item) { if(item && !item->isDisabled()) { if(item->checkState(0)!=Qt::Checked) item->setCheckState(0, Qt::Checked); setParentItemChecked(item->parent()); } } bool DatabaseImportForm::hasCheckedItems(void) { QTreeWidgetItemIterator itr(db_objects_tw); bool selected=false; while(*itr && !selected) { //Only valid items (OID > 0) and with Checked state are considered as selected selected=((*itr)->checkState(0)==Qt::Checked && (*itr)->data(ObjectId, Qt::UserRole).value() > 0); ++itr; } return(selected); } void DatabaseImportForm::getCheckedItems(map> &obj_oids, map> &col_oids) { QTreeWidgetItemIterator itr(db_objects_tw); ObjectType obj_type; unsigned tab_oid=0; obj_oids.clear(); col_oids.clear(); while(*itr) { //If the item is checked and its OID is valid if((*itr)->checkState(0)==Qt::Checked && (*itr)->data(ObjectId, Qt::UserRole).value() > 0) { obj_type=static_cast((*itr)->data(ObjectTypeId, Qt::UserRole).value()); //If the object is not a column store it on general object list if(obj_type!=ObjectType::Column) obj_oids[obj_type].push_back((*itr)->data(ObjectId, Qt::UserRole).value()); //If its a column else { //Get the table's oid from the parent item tab_oid=(*itr)->parent()->parent()->data(ObjectId, Qt::UserRole).value(); //Store the column oid on the selected colums map using the table oid as key col_oids[tab_oid].push_back((*itr)->data(ObjectId, Qt::UserRole).value()); } } ++itr; } } void DatabaseImportForm::listObjects(void) { try { bool enable=false; if(database_cmb->currentIndex() > 0) { Connection *conn=reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value()); //Set the working database on import helper import_helper->closeConnection(); import_helper->setConnection(*conn); import_helper->setCurrentDatabase(database_cmb->currentText()); import_helper->setImportOptions(import_sys_objs_chk->isChecked(), import_ext_objs_chk->isChecked(), resolve_deps_chk->isChecked(), ignore_errors_chk->isChecked(), debug_mode_chk->isChecked(), rand_rel_color_chk->isChecked(), true); //List the objects using the static helper method DatabaseImportForm::listObjects(*import_helper, db_objects_tw, true, true, false); } //Enable the control buttons only when objects were retrieved enable=(db_objects_tw->topLevelItemCount() > 0); objs_parent_wgt->setEnabled(enable); import_btn->setEnabled(hasCheckedItems()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportForm::listDatabases(void) { try { //Close a previous connection opened by the import helper import_helper->closeConnection(); if(connections_cmb->currentIndex()==connections_cmb->count()-1) { ConnectionsConfigWidget::openConnectionsConfiguration(connections_cmb, true); emit s_connectionsUpdateRequest(); } Connection *conn=reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value()); if(conn) { //List the available databases using the selected connection import_helper->setConnection(*conn); DatabaseImportForm::listDatabases(*import_helper, database_cmb); } else database_cmb->clear(); db_objects_tw->clear(); database_cmb->setEnabled(database_cmb->count() > 1); } catch(Exception &e) { db_objects_tw->clear(); database_cmb->clear(); database_cmb->setEnabled(false); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportForm::closeEvent(QCloseEvent *event) { /* Ignore the close event when the thread is running this avoid close the form and make thread execute in background */ if(import_thread->isRunning()) event->ignore(); else { if(create_model && !model_wgt) this->setResult(QDialog::Rejected); import_helper->closeConnection(); } } void DatabaseImportForm::captureThreadError(Exception e) { QPixmap ico; QTreeWidgetItem *item=nullptr; if(!create_model) model_wgt->rearrangeSchemasInGrid(); destroyModelWidget(); finishImport(trUtf8("Importing process aborted!")); ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_erro")); ico_lbl->setPixmap(ico); item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(e.getErrorMessage()), ico, nullptr, false, true); PgModelerUiNs::createExceptionsTree(output_trw, e, item); //Destroy the current import thread and helper to avoid reuse destroyThread(); //Recreates a new import thread and helper to force user to reconfigure the import createThread(); database_cmb->setCurrentIndex(0); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } void DatabaseImportForm::filterObjects(void) { DatabaseImportForm::filterObjects(db_objects_tw, filter_edt->text(), (by_oid_chk->isChecked() ? ObjectId : 0), false); } void DatabaseImportForm::filterObjects(QTreeWidget *tree_wgt, const QString &pattern, int search_column, bool sel_single_leaf) { if(!tree_wgt) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); QList items; QTreeWidgetItemIterator itr(tree_wgt); if(search_column == DatabaseImportForm::ObjectId) items = tree_wgt->findItems(QString("^(0)*(%1)(.)*").arg(pattern), Qt::MatchRegExp | Qt::MatchRecursive, search_column); else items = tree_wgt->findItems(pattern, Qt::MatchStartsWith | Qt::MatchRecursive, search_column); tree_wgt->blockSignals(true); tree_wgt->collapseAll(); tree_wgt->clearSelection(); while(*itr) { (*itr)->setHidden(!pattern.isEmpty()); ++itr; } if(pattern.isEmpty()) { tree_wgt->topLevelItem(0)->setExpanded(true); } else { QTreeWidgetItem *parent=nullptr, *item=nullptr, *leaf=nullptr; int leaf_count=0; while(!items.isEmpty()) { item=items.front(); item->setExpanded(true); item->setHidden(false); parent=item->parent(); while(parent) { parent->setHidden(false); parent->setExpanded(true); parent=parent->parent(); } items.pop_front(); //Counting the leaf items found so far if(sel_single_leaf && item->childCount()==0 && item->parent()) { leaf_count++; leaf=item; } } //Selecting the single leaf item if(sel_single_leaf && leaf_count == 1 && leaf) { leaf->setSelected(true); tree_wgt->setCurrentItem(leaf); } } tree_wgt->blockSignals(false); } void DatabaseImportForm::cancelImport(void) { import_helper->cancelImport(); cancel_btn->setEnabled(false); database_cmb->setCurrentIndex(0); } void DatabaseImportForm::destroyModelWidget(void) { if(create_model && model_wgt) { delete(model_wgt); model_wgt=nullptr; } } void DatabaseImportForm::handleImportCanceled(void) { QPixmap ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")); QString msg=trUtf8("Importing process canceled by user!"); if(!create_model) model_wgt->rearrangeSchemasInGrid(); destroyModelWidget(); finishImport(msg); ico_lbl->setPixmap(ico); PgModelerUiNs::createOutputTreeItem(output_trw, msg, ico); } void DatabaseImportForm::handleImportFinished(Exception e) { if(!e.getErrorMessage().isEmpty()) { Messagebox msgbox; msgbox.show(e, e.getErrorMessage(), Messagebox::AlertIcon); } model_wgt->getDatabaseModel()->setObjectsModified(); model_wgt->rearrangeSchemasInGrid(); model_wgt->getDatabaseModel()->setInvalidated(false); finishImport(trUtf8("Importing process sucessfuly ended!")); ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); import_helper->closeConnection(); import_thread->quit(); import_thread->wait(); this->accept(); } void DatabaseImportForm::finishImport(const QString &msg) { if(import_thread->isRunning()) import_thread->quit(); cancel_btn->setEnabled(false); options_gb->setEnabled(true); database_gb->setEnabled(true); progress_pb->setValue(100); progress_lbl->setText(msg); progress_lbl->repaint(); if(model_wgt) { model_wgt->setUpdatesEnabled(true); if(!create_model) model_wgt->getOperationList()->removeOperations(); } } void DatabaseImportForm::showEvent(QShowEvent *) { ConnectionsConfigWidget::fillConnectionsComboBox(connections_cmb, true, Connection::OpImport); createThread(); if(connections_cmb->currentIndex() > 0) listDatabases(); } ModelWidget *DatabaseImportForm::getModelWidget(void) { if(create_model) return(model_wgt); else return(nullptr); } void DatabaseImportForm::listDatabases(DatabaseImportHelper &import_helper, QComboBox *dbcombo) { if(dbcombo) { try { attribs_map db_attribs; attribs_map::iterator itr; QStringList list; map oids; db_attribs=import_helper.getObjects(ObjectType::Database); dbcombo->blockSignals(true); dbcombo->clear(); if(db_attribs.empty()) dbcombo->addItem(trUtf8("No databases found")); else { itr=db_attribs.begin(); while(itr!=db_attribs.end()) { list.push_back(itr->second); oids[itr->second]=itr->first.toUInt(); itr++; } list.sort(); dbcombo->addItems(list); for(int i=0; i < list.count(); i++) { dbcombo->setItemIcon(i, QPixmap(PgModelerUiNs::getIconPath(ObjectType::Database))); dbcombo->setItemData(i, oids[list[i]]); } dbcombo->insertItem(0, trUtf8("Found %1 database(s)").arg(db_attribs.size())); } dbcombo->setCurrentIndex(0); dbcombo->blockSignals(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void DatabaseImportForm::listObjects(DatabaseImportHelper &import_helper, QTreeWidget *tree_wgt, bool checkable_items, bool disable_empty_grps, bool create_db_item, bool create_dummy_item, unsigned sort_by) { TaskProgressWidget task_prog_wgt; try { if(tree_wgt) { QTreeWidgetItem *db_item=nullptr, *item=nullptr; vector sch_items, tab_items; double inc=0, inc1=0, aux_prog=0; if(!create_dummy_item) { task_prog_wgt.setWindowTitle(trUtf8("Retrieving objects from database...")); task_prog_wgt.show(); task_prog_wgt.updateProgress(1, trUtf8("Retrieving cluster level objects..."), enum_cast(ObjectType::Database)); } tree_wgt->clear(); tree_wgt->setColumnHidden(1, true); if(create_db_item) { Catalog catalog=import_helper.getCatalog(); vector attribs; //Creating database item db_item=new QTreeWidgetItem; db_item->setText(0, import_helper.getCurrentDatabase()); db_item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath(ObjectType::Database))); attribs=catalog.getObjectsAttributes(ObjectType::Database, QString(), QString(), {}, {{Attributes::Name, import_helper.getCurrentDatabase()}}); db_item->setData(ObjectId, Qt::UserRole, attribs[0].at(Attributes::Oid).toUInt()); db_item->setData(ObjectTypeId, Qt::UserRole, enum_cast(ObjectType::Database)); db_item->setToolTip(0, QString("OID: %1").arg(attribs[0].at(Attributes::Oid))); tree_wgt->addTopLevelItem(db_item); } //Retrieving and listing the cluster scoped objects sch_items=DatabaseImportForm::updateObjectsTree(import_helper, tree_wgt, BaseObject::getChildObjectTypes(ObjectType::Database), checkable_items, disable_empty_grps, db_item); if(create_dummy_item) { while(!sch_items.empty()) { item=new QTreeWidgetItem(sch_items.back()); item->setText(0, QString("...")); item->setData(ObjectOtherData, Qt::UserRole, QVariant::fromValue(-1)); sch_items.pop_back(); } } else { ObjectType obj_type = ObjectType::BaseObject; aux_prog=task_prog_wgt.progress_pb->value(); inc=40/static_cast(sch_items.size()); while(!sch_items.empty()) { task_prog_wgt.updateProgress(static_cast(aux_prog), trUtf8("Retrieving objects of schema `%1'...").arg(sch_items.back()->text(0)), enum_cast(ObjectType::Schema)); //Retrieving and listing the schema scoped objects tab_items=DatabaseImportForm::updateObjectsTree(import_helper, tree_wgt, BaseObject::getChildObjectTypes(ObjectType::Schema), checkable_items, disable_empty_grps, sch_items.back(), sch_items.back()->text(0)); inc1=(60/static_cast(tab_items.size()))/static_cast(sch_items.size()); while(!tab_items.empty()) { aux_prog+=inc1; if(aux_prog > 99) aux_prog=99; obj_type = static_cast(tab_items.back()->data(ObjectTypeId, Qt::UserRole).toUInt()); task_prog_wgt.updateProgress(static_cast(aux_prog), trUtf8("Retrieving objects of `%1' (%2)...").arg(tab_items.back()->text(0)).arg(BaseObject::getTypeName(obj_type)), enum_cast(obj_type)); DatabaseImportForm::updateObjectsTree(import_helper, tree_wgt, BaseObject::getChildObjectTypes(obj_type), checkable_items, disable_empty_grps, tab_items.back(), sch_items.back()->text(0), tab_items.back()->text(0)); tab_items.pop_back(); } aux_prog+=inc; if(aux_prog > 99) aux_prog=99; task_prog_wgt.progress_pb->setValue(static_cast(aux_prog)); sch_items.pop_back(); } } tree_wgt->sortItems(sort_by, Qt::AscendingOrder); if(db_item) db_item->setExpanded(true); if(!create_dummy_item) { task_prog_wgt.progress_pb->setValue(100); task_prog_wgt.close(); } } } catch(Exception &e) { task_prog_wgt.close(); tree_wgt->clear(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } vector DatabaseImportForm::updateObjectsTree(DatabaseImportHelper &import_helper, QTreeWidget *tree_wgt, vector types, bool checkable_items, bool disable_empty_grps, QTreeWidgetItem *root, const QString &schema, const QString &table, unsigned sort_by) { vector items_vect; if(tree_wgt) { QTreeWidgetItem *group=nullptr, *item=nullptr; QFont grp_fnt=tree_wgt->font(); attribs_map extra_attribs={{Attributes::FilterTableTypes, Attributes::True}}; QString tooltip=QString("OID: %1"), name, label; bool child_checked=false; vector objects_vect; map gen_groups; ObjectType obj_type; QList groups_list; unsigned oid=0; int start=-1, end=-1; grp_fnt.setItalic(true); tree_wgt->blockSignals(true); tree_wgt->setUpdatesEnabled(false); tree_wgt->setSortingEnabled(false); try { for(ObjectType grp_type : types) { //Create a group item for the current type group=new QTreeWidgetItem(root); group->setIcon(0, QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(grp_type) + QString("_grp")))); group->setFont(0, grp_fnt); //Group items does contains a zero valued id to indicate that is not a valide object group->setData(ObjectId, Qt::UserRole, 0); group->setData(ObjectTypeId, Qt::UserRole, enum_cast(grp_type)); group->setData(ObjectCount, Qt::UserRole, 0); group->setData(ObjectSchema, Qt::UserRole, schema); group->setData(ObjectTable, Qt::UserRole, table); gen_groups[grp_type]=group; groups_list.push_back(group); } objects_vect=import_helper.getObjects(types, schema, table, extra_attribs); for(attribs_map &attribs : objects_vect) { obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); group=gen_groups[obj_type]; group->setData(ObjectCount, Qt::UserRole, group->data(ObjectCount, Qt::UserRole).toUInt() + 1); //Creates individual items for each object of the current type oid=attribs[Attributes::Oid].toUInt(); attribs[Attributes::Name].remove(QRegExp(QString("( )(without)( time zone)"))); label=name=attribs[Attributes::Name]; //Removing the trailing type string from op. families or op. classes names if(obj_type==ObjectType::OpFamily || obj_type==ObjectType::OpClass) { start=name.indexOf(QChar('[')); end=name.lastIndexOf(QChar(']')); name.remove(start, (end-start)+1); name=name.trimmed(); } item=new QTreeWidgetItem(group); item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath(obj_type))); item->setText(0, label); item->setText(ObjectId, attribs[Attributes::Oid].rightJustified(10, '0')); item->setData(ObjectId, Qt::UserRole, attribs[Attributes::Oid].toUInt()); item->setData(ObjectName, Qt::UserRole, name); if(checkable_items) { if((oid > import_helper.getLastSystemOID()) || (obj_type==ObjectType::Schema && name==QString("public")) || (obj_type==ObjectType::Column && root && root->data(0, Qt::UserRole).toUInt() > import_helper.getLastSystemOID())) { item->setCheckState(0, Qt::Checked); child_checked=true; } else item->setCheckState(0, Qt::Unchecked); //Disabling items that refers to PostgreSQL's built-in data types if(obj_type==ObjectType::Type && oid <= import_helper.getLastSystemOID()) { item->setDisabled(true); item->setToolTip(0, trUtf8("This is a PostgreSQL built-in data type and cannot be imported.")); } //Disabling items that refers to pgModeler's built-in system objects else if((obj_type==ObjectType::Tablespace && (name==QString("pg_default") || name==QString("pg_global"))) || (obj_type==ObjectType::Role && (name==QString("postgres"))) || (obj_type==ObjectType::Schema && (name==QString("pg_catalog") || name==QString("public"))) || (obj_type==ObjectType::Language && (name==~LanguageType(LanguageType::C) || name==~LanguageType(LanguageType::Sql) || name==~LanguageType(LanguageType::PlPgsql)))) { item->setFont(0, grp_fnt); item->setForeground(0, BaseObjectView::getFontStyle(Attributes::ProtColumn).foreground()); item->setToolTip(0, trUtf8("This is a pgModeler's built-in object. It will be ignored if checked by user.")); } } //Stores the object's OID as the first data of the item item->setData(ObjectId, Qt::UserRole, oid); if(!item->toolTip(0).isEmpty()) item->setToolTip(0,item->toolTip(0) + QString("\n") + tooltip.arg(oid)); else item->setToolTip(0,tooltip.arg(oid)); //Stores the object's type as the second data of the item item->setData(ObjectTypeId, Qt::UserRole, enum_cast(obj_type)); //Stores the schema and the table's name of the object item->setData(ObjectSchema, Qt::UserRole, schema); item->setData(ObjectTable, Qt::UserRole, table); if(obj_type==ObjectType::Schema || BaseTable::isBaseTable(obj_type)) items_vect.push_back(item); } //Updating the object count in each group for(ObjectType grp_type : types) { group=gen_groups[grp_type]; group->setDisabled(disable_empty_grps && group->data(ObjectCount, Qt::UserRole).toUInt() == 0); group->setText(0, BaseObject::getTypeName(grp_type) + QString(" (%1)").arg(group->data(ObjectCount, Qt::UserRole).toUInt())); if(checkable_items) { if(!group->isDisabled() && child_checked) group->setCheckState(0, Qt::Checked); else group->setCheckState(0, Qt::Unchecked); } } tree_wgt->addTopLevelItems(groups_list); tree_wgt->sortItems(sort_by, Qt::AscendingOrder); tree_wgt->setUpdatesEnabled(true); tree_wgt->blockSignals(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } return(items_vect); } pgmodeler-0.9.2/libpgmodeler_ui/src/databaseimportform.h000066400000000000000000000150011360462764600235000ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DatabaseImportForm \brief Implements the form to execute the reverse engineering operations */ #ifndef DATABASE_IMPORT_FORM_H #define DATABASE_IMPORT_FORM_H #include "ui_databaseimportform.h" #include "databaseimporthelper.h" #include "hinttextwidget.h" #include "htmlitemdelegate.h" #include class DatabaseImportForm: public QDialog, public Ui::DatabaseImportForm { private: Q_OBJECT /*! \brief Indicates if the full output generated during the process should be displayed * When this attribute is true, only errors and some key info messages are displayed. */ static bool low_verbosity; //! \brief Custom delegate used to paint html texts in output tree HtmlItemDelegate *htmlitem_del; bool create_model; HintTextWidget *rand_color_ht, *auto_res_deps_ht, *imp_sys_objs_ht, *imp_ext_objs_ht, *debug_mode_ht, *ignore_errors_ht, *import_to_model_ht; /*! \brief Model widget allocated during the import. In case of success this model will be transferred to the main window or destroyed in case of failure */ ModelWidget *model_wgt; //! \brief Database importer helper DatabaseImportHelper *import_helper; //! \brief Thead that controls the database import helper QThread *import_thread; /*! \brief Toggles the checked state for the specified item. This method recursively changes the check state for the children items */ void setItemCheckState(QTreeWidgetItem *item, Qt::CheckState chk_state); //! \brief Checks the item's parent when its checked void setParentItemChecked(QTreeWidgetItem *item); //! \brief Returns true when there is at least one item checked on the objects tree bool hasCheckedItems(void); /*! \brief Returns the checked items oids on "obj_oids" vector. The second parameter "col_oids" stores the columns oids for each selected table */ void getCheckedItems(map> &obj_oids, map> &col_oids); void finishImport(const QString &msg); void showEvent(QShowEvent *); void closeEvent(QCloseEvent *event); void destroyModelWidget(void); //! \brief Allocates the import thread and helper void createThread(void); //! \brief Destroys both import thread and helper void destroyThread(void); public: //! \brief Constants used to access the tree widget items data static constexpr unsigned ObjectId=1, ObjectTypeId=2, ObjectName=3, ObjectSchema=4, ObjectTable=5, ObjectAttribs=6, //Stores the object's attributes returned by catalog query ObjectOtherData=7, //General purpose usage ObjectCount=8, ObjectSource=9; //Only for gropus DatabaseImportForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); ~DatabaseImportForm(void); void setModelWidget(ModelWidget *model); //! \brief Defines if all the output generated during the import process should be displayed static void setLowVerbosity(bool value); //! \brief Returns the configured model widget ModelWidget *getModelWidget(void); //! \brief Fills a combo box with all available databases according to the configurations of the specified import helper static void listDatabases(DatabaseImportHelper &import_helper, QComboBox *dbcombo); /*! \brief Fills a tree widget with all available database objects according to the configurations of the specified import helper. The parameter 'disable_empty_grps' will make empty group items disabled. The parameter 'create_db_item' will create the root item representing the database itself. The parameter 'create_dummy_item' create an empty child item that represent schema or table child. In this case the generation of schema's or table's children need to be done manually. */ static void listObjects(DatabaseImportHelper &import_helper, QTreeWidget *tree_wgt, bool checkable_items, bool disable_empty_grps, bool create_db_item, bool create_dummy_item = false, unsigned sort_by = 0); /*! \brief Filters an tree widget using a pattern. The 'search_column' indicates in which column the pattern is applied. The paramenter 'sel_single_leaf' indicates if the single leaf (resulting from filtering) must be selected. */ static void filterObjects(QTreeWidget *db_objects_tw, const QString &pattern, int search_column, bool sel_single_leaf); /*! \brief Retrieve the specified objects from the database and insert them onto the tree view. The "root" parameter is used to associate the group of objects as child of it. The "schema" and "table" parameter are used to filter objects by schema and/or table. This method automatically returns a list of QTreeWidgetItem when the vector "types" contains ObjectType::ObjSchema or ObjectType::Table or ObjectType::View */ static vector updateObjectsTree(DatabaseImportHelper &import_helper, QTreeWidget *tree_wgt, vector types, bool checkable_items=false, bool disable_empty_grps=true, QTreeWidgetItem *root=nullptr, const QString &schema=QString(), const QString &table=QString(), unsigned sort_by = 0); private slots: void importDatabase(void); void listObjects(void); void listDatabases(void); void updateProgress(int progress, QString msg, ObjectType obj_type); void cancelImport(void); void handleImportCanceled(void); void handleImportFinished(Exception e); void captureThreadError(Exception e); void filterObjects(void); //! \brief Toggles the check state for the specified item void setItemCheckState(QTreeWidgetItem *item,int); //! \brief Toggles the check state for all items void setItemsCheckState(void); signals: /*! \brief This signal is emitted whenever the user changes the connections settings within this widget without use the main configurations dialog */ void s_connectionsUpdateRequest(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/databaseimporthelper.cpp000066400000000000000000003044131360462764600243570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "databaseimporthelper.h" const QString DatabaseImportHelper::UnkownObjectOidXml=QString("\t\n"); DatabaseImportHelper::DatabaseImportHelper(QObject *parent) : QObject(parent) { random_device rand_seed; rand_num_engine.seed(rand_seed()); import_canceled=ignore_errors=import_sys_objs=import_ext_objs=rand_rel_colors=update_fk_rels=false; auto_resolve_deps=true; import_filter=Catalog::ListAllObjects | Catalog::ExclExtensionObjs | Catalog::ExclSystemObjs; xmlparser=nullptr; dbmodel=nullptr; } void DatabaseImportHelper::setConnection(Connection &conn) { try { connection.setConnectionParams(conn.getConnectionParams()); catalog.setConnection(connection); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::closeConnection(void) { connection.close(); catalog.closeConnection(); } void DatabaseImportHelper::setCurrentDatabase(const QString &dbname) { try { connection.switchToDatabase(dbname); catalog.setConnection(connection); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::setSelectedOIDs(DatabaseModel *db_model, const map > &obj_oids, const map > &col_oids) { if(!db_model) throw Exception(ErrorCode::AsgNotAllocattedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); dbmodel=db_model; xmlparser=dbmodel->getXMLParser(); object_oids.insert(obj_oids.begin(), obj_oids.end()); column_oids.insert(col_oids.begin(), col_oids.end()); //Fills the creation order vector with the selected OIDs creation_order.clear(); for(auto &itr : object_oids) creation_order.insert(creation_order.end(), itr.second.begin(), itr.second.end()); //Sort the creation order vector to create the object in the correct sequence std::sort(creation_order.begin(), creation_order.end()); user_objs.clear(); system_objs.clear(); } void DatabaseImportHelper::setImportOptions(bool import_sys_objs, bool import_ext_objs, bool auto_resolve_deps, bool ignore_errors, bool debug_mode, bool rand_rel_colors, bool update_rels) { this->import_sys_objs=import_sys_objs; this->import_ext_objs=import_ext_objs; this->auto_resolve_deps=auto_resolve_deps; this->ignore_errors=ignore_errors; this->debug_mode=debug_mode; this->rand_rel_colors=rand_rel_colors; this->update_fk_rels=update_rels; Connection::setPrintSQL(debug_mode); if(!import_sys_objs && import_ext_objs) import_filter=Catalog::ListAllObjects | Catalog::ExclBuiltinArrayTypes | Catalog::ExclSystemObjs; else if(import_sys_objs && !import_ext_objs) import_filter=Catalog::ListAllObjects | Catalog::ExclBuiltinArrayTypes | Catalog::ExclExtensionObjs; else if(import_sys_objs && import_ext_objs) import_filter=Catalog::ListAllObjects | Catalog::ExclBuiltinArrayTypes; else import_filter=Catalog::ListAllObjects | Catalog::ExclBuiltinArrayTypes | Catalog::ExclExtensionObjs | Catalog::ExclSystemObjs; } unsigned DatabaseImportHelper::getLastSystemOID(void) { return(catalog.getLastSysObjectOID()); } QString DatabaseImportHelper::getCurrentDatabase(void) { return(connection.getConnectionParam(Connection::ParamDbName)); } Catalog DatabaseImportHelper::getCatalog(void) { return(catalog); } attribs_map DatabaseImportHelper::getObjects(ObjectType obj_type, const QString &schema, const QString &table, attribs_map extra_attribs) { try { catalog.setFilter(import_filter); return(catalog.getObjectsNames(obj_type, schema, table, extra_attribs)); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } vector DatabaseImportHelper::getObjects(vector obj_types, const QString &schema, const QString &table, attribs_map extra_attribs) { try { catalog.setFilter(import_filter); return(catalog.getObjectsNames(obj_types, schema, table, extra_attribs)); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::swapSequencesTablesIds(void) { BaseObject *table=nullptr, *sequence=nullptr; map::iterator itr; //Swapping the id's between sequences and tables to avoid reference breaking on SQL code itr=seq_tab_swap.begin(); while(itr!=seq_tab_swap.end()) { sequence=dbmodel->getObject(getObjectName(itr->first), ObjectType::Sequence); table=dbmodel->getObject(getObjectName(itr->second), ObjectType::Table); if(sequence && table) BaseObject::swapObjectsIds(sequence, table, false); itr++; } } void DatabaseImportHelper::retrieveSystemObjects(void) { int progress=0; vector::iterator itr; map *obj_map=nullptr; vector objects; ObjectType sys_objs[]={ ObjectType::Schema, ObjectType::Role, ObjectType::Tablespace, ObjectType::Language, ObjectType::Type }; unsigned i=0, oid=0, cnt=sizeof(sys_objs)/sizeof(ObjectType); for(i=0; i < cnt && !import_canceled; i++) { emit s_progressUpdated(progress, trUtf8("Retrieving system objects... `%1'").arg(BaseObject::getTypeName(sys_objs[i])), sys_objs[i]); if(sys_objs[i]!=ObjectType::Type) { obj_map=&system_objs; if(sys_objs[i]!=ObjectType::Language) catalog.setFilter(Catalog::ListOnlySystemObjs); else catalog.setFilter(Catalog::ListAllObjects); } else { obj_map=&types; catalog.setFilter(Catalog::ListAllObjects); } //Query the objects on the catalog and put them on the map objects=catalog.getObjectsAttributes(sys_objs[i]); itr=objects.begin(); while(itr!=objects.end() && !import_canceled) { oid=itr->at(Attributes::Oid).toUInt(); (*obj_map)[oid]=(*itr); itr++; } progress=(i/static_cast(cnt))*10; } } void DatabaseImportHelper::retrieveUserObjects(void) { int progress=0; map>::iterator oid_itr=object_oids.begin(); vector::iterator itr; vector objects; unsigned i=0, oid=0; map>::iterator col_itr; QStringList names; i=0; catalog.setFilter(import_filter); //Retrieving selected database level objects and table children objects (except columns) while(oid_itr!=object_oids.end() && !import_canceled) { emit s_progressUpdated(progress, trUtf8("Retrieving objects... `%1'").arg(BaseObject::getTypeName(oid_itr->first)), oid_itr->first); objects=catalog.getObjectsAttributes(oid_itr->first, QString(), QString(), oid_itr->second); itr=objects.begin(); while(itr!=objects.end() && !import_canceled) { oid=itr->at(Attributes::Oid).toUInt(); user_objs[oid]=(*itr); itr++; } objects.clear(); progress=(i/static_cast(object_oids.size()))*100; oid_itr++; i++; } //Retrieving all selected table columns i=0; col_itr=column_oids.begin(); while(col_itr!=column_oids.end()) { names=getObjectName(QString::number(col_itr->first)).split("."); emit s_progressUpdated(progress, trUtf8("Retrieving columns of table `%1.%2', oid `%3'...").arg(names[0]).arg(names[1]).arg(col_itr->first), ObjectType::Column); if(names.size() > 1) retrieveTableColumns(names[0], names[1], col_itr->second); progress=(i/static_cast(column_oids.size()))*100; col_itr++; i++; } } void DatabaseImportHelper::retrieveTableColumns(const QString &sch_name, const QString &tab_name, vector col_ids) { try { vector cols; unsigned tab_oid=0, col_oid; cols=catalog.getObjectsAttributes(ObjectType::Column, sch_name, tab_name, col_ids); for(auto &itr : cols) { col_oid=itr.at(Attributes::Oid).toUInt(); tab_oid=itr.at(Attributes::Table).toUInt(); columns[tab_oid][col_oid]=itr; } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::createObjects(void) { int progress=0; attribs_map attribs; ObjectType obj_type; unsigned i=0, oid=0, prev_size=0; vector not_created_objs, oids; vector::iterator itr, itr_end; vector aux_errors; for(i=0; i < creation_order.size() && !import_canceled; i++) { oid=creation_order[i]; attribs=user_objs[oid]; obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); try { /* Constraints are ignored in these phase being pushed into an auxiliary list in order to be created later */ if(obj_type!=ObjectType::Constraint) { emit s_progressUpdated(progress, trUtf8("Creating object `%1' (%2), oid `%3'...") .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(obj_type)) .arg(attribs[Attributes::Oid]), obj_type); createObject(attribs); } else constr_creation_order.push_back(oid); } catch(Exception &) { //Storing the object id when some error occurs in order to try to create it again below not_created_objs.push_back(oid); } progress=(i/static_cast(creation_order.size())) * 100; } #ifdef DEMO_VERSION #warning "DEMO VERSION: disabling object recreation in reverse engineering." #else //Trying to recreate objects that failed to be created previously if(!not_created_objs.empty()) { unsigned max_tries=10, tries=1; do { /* Store the current size of the objects list. If this size is the same after scan the list recreating the objects means that any object was not created which determines an unrecoverable errors, e.g., objects that references system objects and this ones was not imported */ prev_size=not_created_objs.size(); progress=0; oids=not_created_objs; not_created_objs.clear(); itr=oids.begin(); itr_end=oids.end(); //Scan the oid list recreating the objects while(itr!=itr_end && !import_canceled) { attribs=user_objs[*itr]; obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); itr++; emit s_progressUpdated(progress, trUtf8("Trying to recreate object `%1' (%2), oid `%3'...") .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(obj_type)) .arg(attribs[Attributes::Oid]), obj_type); try { createObject(attribs); } catch(Exception &e) { //In case of some error store the oid and the error in separated lists not_created_objs.push_back(*itr); aux_errors.push_back(Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, dumpObjectAttributes(attribs))); } progress=(i/static_cast(not_created_objs.size())) * 100; } tries++; if(tries >= max_tries) emit s_progressUpdated(progress, trUtf8("Import failed to recreate some objects in `%1' tries.").arg(max_tries), ObjectType::BaseObject); if(!import_canceled) { /* If the previous list size is the same as the not_created_object list means that no object was created in this interaction which means error */ if(prev_size==not_created_objs.size() && !ignore_errors) throw Exception(aux_errors.back().getErrorMessage(), aux_errors.back().getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, aux_errors); else if(ignore_errors) errors.insert(errors.end(), aux_errors.begin(), aux_errors.end()); aux_errors.clear(); } } while(!not_created_objs.empty() && !import_canceled && tries < max_tries); } #endif } void DatabaseImportHelper::createConstraints(void) { int progress=0; attribs_map attribs; unsigned i=0, oid=0; for(i=0; i < constr_creation_order.size() && !import_canceled; i++) { oid=constr_creation_order[i]; attribs=user_objs[oid]; try { //Check constraints are created only if they are not inherited, other types are created normally if(attribs[Attributes::Type]!=Attributes::CkConstr || (attribs[Attributes::Type]==Attributes::CkConstr && attribs[Attributes::Inherited]!=Attributes::True)) { emit s_progressUpdated(progress, trUtf8("Creating object `%1' (%2)...") .arg(attribs[Attributes::Name]) .arg(BaseObject::getTypeName(ObjectType::Constraint)), ObjectType::Constraint); createObject(attribs); } } catch(Exception &e) { if(ignore_errors) errors.push_back(Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, dumpObjectAttributes(attribs))); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } progress=(i/static_cast(constr_creation_order.size())) * 100; } } void DatabaseImportHelper::createPermissions(void) { attribs_map attribs; try { unsigned i=0, progress=0; vector::iterator itr, itr_obj=obj_perms.begin(); map>::iterator itr_cols=col_perms.begin(); QString msg=trUtf8("Creating permissions for object `%1' (%2)..."); ObjectType obj_type; //Create the object level permission while(itr_obj!=obj_perms.end() && !import_canceled) { attribs=user_objs[*itr_obj]; obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); emit s_progressUpdated(progress, msg.arg(getObjectName(attribs[Attributes::Oid])) .arg(BaseObject::getTypeName(obj_type)), ObjectType::Permission); createPermission(attribs); itr_obj++; progress=((i++)/static_cast(obj_perms.size())) * 100; } emit s_progressUpdated(progress, trUtf8("Creating columns permissions..."), ObjectType::Permission); //Create the column level permission i=0; while(itr_cols!=col_perms.end() && !import_canceled) { itr=col_perms[itr_cols->first].begin(); while(itr!=itr_cols->second.end()) { attribs=columns[itr_cols->first][*itr]; obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); emit s_progressUpdated(progress, msg.arg(getObjectName(attribs[Attributes::Oid])) .arg(BaseObject::getTypeName(obj_type)), ObjectType::Permission); createPermission(attribs); itr++; } itr_cols++; progress=((i++)/static_cast(col_perms.size())) * 100; } } catch(Exception &e) { if(ignore_errors) errors.push_back(Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, dumpObjectAttributes(attribs))); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::updateFKRelationships(void) { int progress=0; vector::iterator itr_tab, itr_tab_end; unsigned i=0, count=0; Table *tab=nullptr; itr_tab=dbmodel->getObjectList(ObjectType::Table)->begin(); itr_tab_end=dbmodel->getObjectList(ObjectType::Table)->end(); count=dbmodel->getObjectList(ObjectType::Table)->size(); i=0; try { while(itr_tab!=itr_tab_end && !import_canceled) { tab=dynamic_cast
(*itr_tab); emit s_progressUpdated(progress, trUtf8("Updating relationships of `%1' (%2)...") .arg(tab->getName()) .arg(BaseObject::getTypeName(ObjectType::Table)), ObjectType::Table); dbmodel->updateTableFKRelationships(tab); progress=(i/static_cast(count)) * 90; itr_tab++; i++; } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::importDatabase(void) { try { if(!dbmodel) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); dbmodel->setLoadingModel(true); dbmodel->setObjectListsCapacity(creation_order.size()); retrieveSystemObjects(); retrieveUserObjects(); createObjects(); createTableInheritances(); createTablePartitionings(); createConstraints(); destroyDetachedColumns(); createPermissions(); if(update_fk_rels) updateFKRelationships(); if(!inherited_cols.empty()) { emit s_progressUpdated(100, trUtf8("Validating relationships..."), ObjectType::Relationship); dbmodel->validateRelationships(); } if(!import_canceled) { swapSequencesTablesIds(); assignSequencesToColumns(); if(!errors.empty()) { QString log_name; //Writing the erros to log file log_name=GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + QString("%1_%2_%3.log").arg(dbmodel->getName()) .arg(QString("import")) .arg(QDateTime::currentDateTime().toString(QString("yyyy-MM-dd_hhmmss"))); import_log.setFileName(log_name); import_log.open(QFile::WriteOnly); for(unsigned i=0; i < errors.size() && import_log.isOpen(); i++) import_log.write(errors[i].getExceptionsText().toStdString().c_str()); import_log.close(); emit s_importFinished(Exception(trUtf8("The database import ended but some errors were generated and saved into the log file `%1'. This file will last until pgModeler quit.").arg(log_name), __PRETTY_FUNCTION__,__FILE__,__LINE__)); } else emit s_importFinished(); } else emit s_importCanceled(); dbmodel->setLoadingModel(false); if(!import_canceled) { //Generating random colors for relationships if(rand_rel_colors) { vector *rels=nullptr; vector::iterator itr, itr_end; std::uniform_int_distribution dist(0,255); ObjectType rel_type[]={ ObjectType::Relationship, ObjectType::BaseRelationship }; BaseRelationship *rel=nullptr; for(unsigned i=0; i < 2; i++) { rels=dbmodel->getObjectList(rel_type[i]); itr=rels->begin(); itr_end=rels->end(); while(itr!=itr_end) { rel=dynamic_cast(*itr); rel->setPoints({}); rel->setCustomColor(QColor(dist(rand_num_engine), dist(rand_num_engine), dist(rand_num_engine))); itr++; } } } } dbmodel->setObjectsModified(); resetImportParameters(); } catch(Exception &e) { resetImportParameters(); /* When running in a separated thread (other than the main application thread) redirects the error in form of signal */ if(this->thread() && this->thread()!=qApp->thread()) emit s_importAborted(Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo())); else //Redirects any error to the user throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo()); } } void DatabaseImportHelper::cancelImport(void) { import_canceled=true; } void DatabaseImportHelper::createObject(attribs_map &attribs) { unsigned oid=attribs[Attributes::Oid].toUInt(); ObjectType obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); QString obj_name=getObjectName(attribs[Attributes::Oid], (obj_type==ObjectType::Function || obj_type==ObjectType::Operator)); //Avoiding the creation of pgModeler's temp objects created in database during the catalog reading if(obj_name.contains(Catalog::PgModelerTempDbObj)) return; try { if(!import_canceled && (obj_type==ObjectType::Database || TableObject::isTableObject(obj_type) || //If the object does not exists on both model and created objects vector ((std::find(created_objs.begin(), created_objs.end(), oid)==created_objs.end()) && dbmodel->getObjectIndex(obj_name, obj_type) < 0))) { if(TableObject::isTableObject(obj_type)) attribs[Attributes::DeclInTable]=QString(); //System objects will have the sql disabled by default attribs[Attributes::SqlDisabled]=(catalog.isSystemObject(oid) || catalog.isExtensionObject(oid) ? Attributes::True : QString()); attribs[Attributes::Comment]=getComment(attribs); if(attribs.count(Attributes::Owner)) attribs[Attributes::Owner]=getDependencyObject(attribs[Attributes::Owner], ObjectType::Role, false, auto_resolve_deps); if(attribs.count(Attributes::Tablespace)) attribs[Attributes::Tablespace]=getDependencyObject(attribs[Attributes::Tablespace], ObjectType::Tablespace, false, auto_resolve_deps); if(attribs.count(Attributes::Schema)) { //Here we preserve the schema oid for latter usage in certain methods attribs[Attributes::SchemaOid]=attribs[Attributes::Schema]; attribs[Attributes::Schema]=getDependencyObject(attribs[Attributes::Schema], ObjectType::Schema, false, auto_resolve_deps); } /* Due to the object recreation mechanism there are some situations when pgModeler fails to recreate them due to the duplication of permissions. So, to avoid this problem we need to check if the OID of the object was previously registered in the vector of permissions to be created */ if(!attribs[Attributes::Permission].isEmpty() && std::find(obj_perms.begin(), obj_perms.end(), oid)==obj_perms.end()) obj_perms.push_back(oid); if(debug_mode) { QTextStream ts(stdout); ts << dumpObjectAttributes(attribs) << endl; } switch(obj_type) { case ObjectType::Database: configureDatabase(attribs); break; case ObjectType::Tablespace: createTablespace(attribs); break; case ObjectType::Schema: createSchema(attribs); break; case ObjectType::Role: createRole(attribs); break; case ObjectType::Domain: createDomain(attribs); break; case ObjectType::Extension: createExtension(attribs); break; case ObjectType::Function: createFunction(attribs); break; case ObjectType::Language: createLanguage(attribs); break; case ObjectType::OpFamily: createOperatorFamily(attribs); break; case ObjectType::OpClass: createOperatorClass(attribs); break; case ObjectType::Operator: createOperator(attribs); break; case ObjectType::Collation: createCollation(attribs); break; case ObjectType::Cast: createCast(attribs); break; case ObjectType::Conversion: createConversion(attribs); break; case ObjectType::Sequence: createSequence(attribs); break; case ObjectType::Aggregate: createAggregate(attribs); break; case ObjectType::Type: createType(attribs); break; case ObjectType::Table: createTable(attribs); break; case ObjectType::View: createView(attribs); break; case ObjectType::Rule: createRule(attribs); break; case ObjectType::Trigger: createTrigger(attribs); break; case ObjectType::Index: createIndex(attribs); break; case ObjectType::Constraint: createConstraint(attribs); break; case ObjectType::Policy: createPolicy(attribs); break; case ObjectType::EventTrigger: createEventTrigger(attribs); break; case ObjectType::ForeignDataWrapper: createForeignDataWrapper(attribs); break; case ObjectType::ForeignServer: createForeignServer(attribs); break; case ObjectType::UserMapping: createUserMapping(attribs); break; case ObjectType::ForeignTable: createForeignTable(attribs); break; default: if(debug_mode) { qDebug() << QString("create() method for %s isn't implemented!").arg(BaseObject::getSchemaName(obj_type)) << endl; } break; } /* Register the object oid on the list of created objects to avoid creating it again on recursive object creation. (see getDependencyObject()) */ created_objs.push_back(oid); } } catch(Exception &e) { throw Exception(Exception::getErrorMessage(ErrorCode::ObjectNotImported) .arg(obj_name).arg(BaseObject::getTypeName(obj_type)).arg(attribs[Attributes::Oid]), ErrorCode::ObjectNotImported,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, dumpObjectAttributes(attribs)); } } QString DatabaseImportHelper::getComment(attribs_map &attribs) { try { QString xml_def; if(!attribs[Attributes::Comment].isEmpty()) xml_def=schparser.getCodeDefinition(Attributes::Comment, attribs, SchemaParser::XmlDefinition); return(xml_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString DatabaseImportHelper::getDependencyObject(const QString &oid, ObjectType obj_type, bool use_signature, bool recursive_dep_res, bool generate_xml, attribs_map extra_attribs) { try { QString xml_def; unsigned obj_oid=oid.toUInt(); if(obj_oid > 0) { attribs_map obj_attr; attribs_map::iterator itr=extra_attribs.begin(); if(user_objs.count(obj_oid)) obj_attr=user_objs[obj_oid]; else obj_attr=system_objs[obj_oid]; /* If the attributes for the dependency does not exists and the automatic dependency resolution is enable, the object's attributes will be retrieved from catalog */ if(auto_resolve_deps && obj_attr.empty() && ((import_ext_objs && catalog.isExtensionObject(obj_oid)) || (import_sys_objs && obj_oid <= catalog.getLastSysObjectOID()) || (obj_oid > catalog.getLastSysObjectOID() && !catalog.isExtensionObject(obj_oid)))) { catalog.setFilter(Catalog::ListAllObjects); vector attribs_vect=catalog.getObjectsAttributes(obj_type,QString(),QString(), { obj_oid }); if(!attribs_vect.empty()) { if(obj_oid <= catalog.getLastSysObjectOID()) system_objs[obj_oid]=attribs_vect[0]; else user_objs[obj_oid]=attribs_vect[0]; obj_attr=attribs_vect[0]; } } if(!obj_attr.empty()) { QString obj_name; while(itr!=extra_attribs.end()) { obj_attr[itr->first]=itr->second; itr++; } /* If the attributes of the dependency exists but it was not created on the model yet, pgModeler will create it and it's dependencies recursively */ if(recursive_dep_res && !TableObject::isTableObject(obj_type) && obj_type!=ObjectType::Database && dbmodel->getObjectIndex(obj_attr[Attributes::Name], obj_type) < 0) createObject(obj_attr); if(use_signature) obj_name=obj_attr[Attributes::Signature]=getObjectName(oid, true); else obj_name=obj_attr[Attributes::Name]=getObjectName(oid); if(generate_xml) { obj_attr[Attributes::ReducedForm]=Attributes::True; schparser.ignoreUnkownAttributes(true); xml_def=schparser.getCodeDefinition(BaseObject::getSchemaName(obj_type), obj_attr, SchemaParser::XmlDefinition); schparser.ignoreUnkownAttributes(false); } else xml_def=obj_name; } else /* If the object oid is valid but there is no attribute set to it creates a xml definition containing an alert indicating that the object is unknown */ xml_def=QString(UnkownObjectOidXml).arg(oid); } return(xml_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::loadObjectXML(ObjectType obj_type, attribs_map &attribs) { QString xml_buf; try { schparser.ignoreUnkownAttributes(true); xml_buf=schparser.getCodeDefinition(BaseObject::getSchemaName(obj_type), attribs, SchemaParser::XmlDefinition); schparser.ignoreUnkownAttributes(false); xmlparser->restartParser(); if(debug_mode) { QTextStream ts(stdout); ts << QString("").arg(attribs[Attributes::Name]).arg(attribs[Attributes::Oid]) << endl; ts << xml_buf << endl; } xmlparser->loadXMLBuffer(xml_buf); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xml_buf); } } void DatabaseImportHelper::resetImportParameters(void) { Connection::setPrintSQL(false); import_canceled=false; dbmodel=nullptr; column_oids.clear(); object_oids.clear(); types.clear(); user_objs.clear(); creation_order.clear(); seq_tab_swap.clear(); columns.clear(); system_objs.clear(); created_objs.clear(); errors.clear(); constr_creation_order.clear(); obj_perms.clear(); col_perms.clear(); connection.close(); catalog.closeConnection(); inherited_cols.clear(); imported_tables.clear(); } QString DatabaseImportHelper::dumpObjectAttributes(attribs_map &attribs) { QString dump_str; dump_str+=QString("-- Raw attributes: %1 (OID: %2) --\n") .arg(attribs[Attributes::Name]) .arg(attribs[Attributes::Oid]); for(auto &attr : attribs) dump_str+=QString("%1: %2\n").arg(attr.first).arg(attr.second); dump_str+=QString("---\n"); return(dump_str); } void DatabaseImportHelper::createTablespace(attribs_map &attribs) { Tablespace *tabspc=nullptr; try { loadObjectXML(ObjectType::Tablespace, attribs); tabspc=dbmodel->createTablespace(); dbmodel->addObject(tabspc); } catch(Exception &e) { if(tabspc) delete(tabspc); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::createSchema(attribs_map &attribs) { Schema *schema=nullptr; std::uniform_int_distribution dist(0,255); try { attribs[Attributes::RectVisible]=QString(); attribs[Attributes::FillColor]=QColor(dist(rand_num_engine), dist(rand_num_engine), dist(rand_num_engine)).name(); loadObjectXML(ObjectType::Schema, attribs); schema=dbmodel->createSchema(); dbmodel->addObject(schema); } catch(Exception &e) { if(schema) delete(schema); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createRole(attribs_map &attribs) { Role *role=nullptr; try { QString role_types[]={ Attributes::RefRoles, Attributes::AdminRoles, Attributes::MemberRoles }; for(unsigned i=0; i < 3; i++) attribs[role_types[i]]=getObjectNames(attribs[role_types[i]]).join(','); loadObjectXML(ObjectType::Role, attribs); role=dbmodel->createRole(); dbmodel->addObject(role); } catch(Exception &e) { if(role) delete(role); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createDomain(attribs_map &attribs) { Domain *dom=nullptr; QStringList constraints, constr_attrs; attribs_map aux_attribs; QString expr; try { constraints = Catalog::parseArrayValues(attribs[Attributes::Constraints]); attribs[Attributes::Constraints].clear(); for(auto constr : constraints) { constr.remove(0, 1); constr.remove(constr.length() - 1, 1); constr_attrs = constr.split(Table::DataSeparator); aux_attribs[Attributes::Name] = constr_attrs.at(0); expr = constr_attrs.at(1); expr.replace(QString("CHECK ("), QString()); expr.remove(expr.length() - 1,1); aux_attribs[Attributes::Expression] = expr; attribs[Attributes::Constraints]+= schparser.getCodeDefinition(Attributes::DomConstraint, aux_attribs, SchemaParser::XmlDefinition); } attribs[Attributes::Type]=getType(attribs[Attributes::Type], true, attribs); attribs[Attributes::Collation]=getDependencyObject(attribs[Attributes::Collation], ObjectType::Collation); loadObjectXML(ObjectType::Domain, attribs); dom=dbmodel->createDomain(); dbmodel->addDomain(dom); } catch(Exception &e) { if(dom) delete(dom); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createExtension(attribs_map &attribs) { Extension *ext=nullptr; try { loadObjectXML(ObjectType::Extension, attribs); ext=dbmodel->createExtension(); dbmodel->addExtension(ext); } catch(Exception &e) { if(ext) delete(ext); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createFunction(attribs_map &attribs) { Function *func=nullptr; Parameter param; PgSqlType type; unsigned dim=0; QStringList param_types, param_names, param_modes, param_def_vals, param_xmls; QString param_tmpl_name=QString("_param%1"); vector parameters; try { param_types=getTypes(attribs[Attributes::ArgTypes], false); param_names=Catalog::parseArrayValues(attribs[Attributes::ArgNames]); param_modes=Catalog::parseArrayValues(attribs[Attributes::ArgModes]); param_def_vals=Catalog::parseDefaultValues(attribs[Attributes::ArgDefaults]); for(int i=0; i < param_types.size(); i++) { /* If the function is to be used as a user-defined data type support functions the parameter type will be renamed to "any" (see rules on Type::setFunction()) */ if(i==0 && (attribs[Attributes::RefType]==Attributes::SendFunc || attribs[Attributes::RefType]==Attributes::OutputFunc || attribs[Attributes::RefType]==Attributes::CanonicalFunc)) type=PgSqlType(QString("\"any\"")); else { //If the type contains array descriptor [] set the dimension to 1 dim=(param_types[i].contains(QString("[]")) ? 1 : 0); //Create the type param_types[i].remove(QString("[]")); type=PgSqlType::parseString(param_types[i]); type.setDimension(dim); } //Alocates a new parameter param=Parameter(); param.setType(type); if(!param_names.isEmpty()) { param_names[i].remove('"'); if(param_names[i].isEmpty()) param.setName(param_tmpl_name.arg(i+1)); else param.setName(param_names[i]); } else param.setName(param_tmpl_name.arg(i+1)); //Parameter modes: i = IN, o = OUT, b = INOUT, v = VARIADIC if(!param_modes.isEmpty()) { param.setIn(param_modes[i]==QString("i") || param_modes[i]==QString("b")); param.setOut(param_modes[i]==QString("o") || param_modes[i]==QString("b")); param.setVariadic(param_modes[i]==QString("v")); } //If the mode is 't' indicates that the current parameter will be used as a return table colum if(!param_modes.isEmpty() && param_modes[i]==QString("t")) attribs[Attributes::ReturnTable]+=param.getCodeDefinition(SchemaParser::XmlDefinition); else parameters.push_back(param); } if(!parameters.empty()) { vector::reverse_iterator ritr, ritr_end; ritr = parameters.rbegin(); ritr_end = parameters.rend(); while(ritr != ritr_end) { param = *ritr; ritr++; //Setting the default value for the current paramenter. OUT parameter doesn't receive default values. if(!param_def_vals.isEmpty() && (!param.isOut() || (param.isIn() && param.isOut()))) { param.setDefaultValue(param_def_vals.back()); param_def_vals.pop_back(); } param_xmls.push_front(param.getCodeDefinition(SchemaParser::XmlDefinition)); } attribs[Attributes::Parameters]+=param_xmls.join(QChar('\n')); } //Case the function's language is C the symbol is the 'definition' attribute if(getObjectName(attribs[Attributes::Language])==~LanguageType("c")) { attribs[Attributes::Symbol]=attribs[Attributes::Definition]; attribs[Attributes::Definition]=QString(); } //Get the language reference code attribs[Attributes::Language]=getDependencyObject(attribs[Attributes::Language], ObjectType::Language); //Get the return type if there is no return table configured if(attribs[Attributes::ReturnTable].isEmpty()) { /* If the function is to be used as a user-defined data type support functions the return type will be renamed to "any" (see rules on Type::setFunction()) */ if(attribs[Attributes::RefType]==Attributes::InputFunc || attribs[Attributes::RefType]==Attributes::RecvFunc || attribs[Attributes::RefType]==Attributes::CanonicalFunc) attribs[Attributes::ReturnType]=PgSqlType(QString("\"any\"")).getCodeDefinition(SchemaParser::XmlDefinition); else attribs[Attributes::ReturnType]=getType(attribs[Attributes::ReturnType], true); } loadObjectXML(ObjectType::Function, attribs); func=dbmodel->createFunction(); dbmodel->addFunction(func); } catch(Exception &e) { if(func) delete(func); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createLanguage(attribs_map &attribs) { Language *lang=nullptr; try { unsigned lang_oid, func_oid; QString func_types[]={ Attributes::ValidatorFunc, Attributes::HandlerFunc, Attributes::InlineFunc }; lang_oid=attribs[Attributes::Oid].toUInt(); for(unsigned i=0; i < 3; i++) { func_oid=attribs[func_types[i]].toUInt(); /* Workaround: in case of importing system languages like "internal" where the validator/handler function is defined after the language pgModeler will raise errors so in order to continue the import these fuctions are simply ignored */ if(func_oid < lang_oid) attribs[func_types[i]]=getDependencyObject(attribs[func_types[i]], ObjectType::Function, true , true, true, {{Attributes::RefType, func_types[i]}}); else attribs[func_types[i]]=QString(); } loadObjectXML(ObjectType::Language, attribs); lang=dbmodel->createLanguage(); dbmodel->addLanguage(lang); } catch(Exception &e) { if(lang) delete(lang); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createOperatorFamily(attribs_map &attribs) { OperatorFamily *opfam=nullptr; try { loadObjectXML(ObjectType::OpFamily, attribs); opfam=dbmodel->createOperatorFamily(); dbmodel->addOperatorFamily(opfam); } catch(Exception &e) { if(opfam) delete(opfam); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createOperatorClass(attribs_map &attribs) { OperatorClass *opclass=nullptr; try { attribs_map elem_attr; vector elems; QStringList array_vals, list; attribs[Attributes::Family]=getObjectName(attribs[Attributes::Family], true); attribs[Attributes::Type]=getType(attribs[Attributes::Type], true, attribs); //Generating attributes for STORAGE elements if(attribs[Attributes::Storage]!=QString("0")) { elem_attr[Attributes::Storage]=Attributes::True; elem_attr[Attributes::Definition]=getType(attribs[Attributes::Storage], true); elems.push_back(elem_attr); } else if(attribs[Attributes::Function].isEmpty() && attribs[Attributes::Operator].isEmpty()) { elem_attr[Attributes::Storage]=Attributes::True; elem_attr[Attributes::Definition]=attribs[Attributes::Type]; elems.push_back(elem_attr); } //Generating attributes for FUNCTION elements if(!attribs[Attributes::Function].isEmpty()) { elem_attr.clear(); elem_attr[Attributes::Function]=Attributes::True; array_vals=Catalog::parseArrayValues(attribs[Attributes::Function]); for(int i=0; i < array_vals.size(); i++) { list=array_vals[i].split(':'); elem_attr[Attributes::StrategyNum]=list[0]; elem_attr[Attributes::Definition]=getDependencyObject(list[1], ObjectType::Function, true); elems.push_back(elem_attr); } } //Generating attributes for OPERATOR elements if(!attribs[Attributes::Operator].isEmpty()) { elem_attr.clear(); elem_attr[Attributes::Operator]=Attributes::True; array_vals=Catalog::parseArrayValues(attribs[Attributes::Operator]); for(int i=0; i < array_vals.size(); i++) { list=array_vals[i].split(':'); elem_attr[Attributes::Definition]=""; elem_attr[Attributes::StrategyNum]=list[0]; elem_attr[Attributes::Definition]+=getDependencyObject(list[1], ObjectType::Operator, true); elem_attr[Attributes::Definition]+=getDependencyObject(list[2], ObjectType::OpFamily, true); elems.push_back(elem_attr); } } //Generating the complete XML code for operator class elements for(unsigned i=0; i < elems.size(); i++) { schparser.ignoreUnkownAttributes(true); attribs[Attributes::Elements]+=schparser.getCodeDefinition(Attributes::Element, elems[i], SchemaParser::XmlDefinition); schparser.ignoreUnkownAttributes(false); } loadObjectXML(ObjectType::OpClass, attribs); opclass=dbmodel->createOperatorClass(); dbmodel->addOperatorClass(opclass); } catch(Exception &e) { if(opclass) delete(opclass); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createOperator(attribs_map &attribs) { Operator *oper=nullptr; try { int pos; QRegExp regexp; QString op_signature, func_types[]={ Attributes::OperatorFunc, Attributes::RestrictionFunc, Attributes::JoinFunc }, arg_types[]= { Attributes::LeftType, Attributes::RightType }, op_types[]= { Attributes::CommutatorOp, Attributes::NegatorOp }; for(unsigned i=0; i < 3; i++) attribs[func_types[i]]=getDependencyObject(attribs[func_types[i]], ObjectType::Function, true, true, true, {{Attributes::RefType, func_types[i]}}); for(unsigned i=0; i < 2; i++) attribs[arg_types[i]]=getType(attribs[arg_types[i]], true, {{Attributes::RefType, arg_types[i]}}); regexp.setPattern(Attributes::Signature + QString("(=)(\")")); for(unsigned i=0; i < 2; i++) { attribs[op_types[i]]=getDependencyObject(attribs[op_types[i]], ObjectType::Operator, true, false, true, {{Attributes::RefType, op_types[i]}}); if(!attribs[op_types[i]].isEmpty()) { /* Extracting the operator's signature to check if it was previouly created: Defining a operator as ++(A,B) and it's commutator as *++(B,A) PostgreSQL will automatically create on the second operator a commutator reference to ++(A,B). But to pgModeler only the first reference is valid, so the extracted signature is used to check if the commutator was previously created in order to avoid reference errors */ pos=regexp.indexIn(attribs[op_types[i]]) + regexp.matchedLength(); op_signature=attribs[op_types[i]].mid(pos, (attribs[op_types[i]].indexOf('"',pos) - pos)); //If the operator is not defined clear up the reference to it if(dbmodel->getObjectIndex(op_signature, ObjectType::Operator) < 0) attribs[op_types[i]].clear(); } } loadObjectXML(ObjectType::Operator, attribs); oper=dbmodel->createOperator(); dbmodel->addOperator(oper); } catch(Exception &e) { if(oper) delete(oper); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createCollation(attribs_map &attribs) { Collation *coll=nullptr; try { loadObjectXML(ObjectType::Collation, attribs); coll=dbmodel->createCollation(); dbmodel->addCollation(coll); } catch(Exception &e) { if(coll) delete(coll); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createCast(attribs_map &attribs) { Cast *cast=nullptr; try { attribs[Attributes::Function]=getDependencyObject(attribs[Attributes::Function], ObjectType::Function, true); attribs[Attributes::SourceType]=getType(attribs[Attributes::SourceType], true); attribs[Attributes::DestType]=getType(attribs[Attributes::DestType], true); loadObjectXML(ObjectType::Cast, attribs); cast=dbmodel->createCast(); dbmodel->addCast(cast); } catch(Exception &e) { if(cast) delete(cast); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createConversion(attribs_map &attribs) { Conversion *conv=nullptr; try { attribs[Attributes::Function]=getDependencyObject(attribs[Attributes::Function], ObjectType::Function, true, auto_resolve_deps); loadObjectXML(ObjectType::Conversion, attribs); conv=dbmodel->createConversion(); dbmodel->addConversion(conv); } catch(Exception &e) { if(conv) delete(conv); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createSequence(attribs_map &attribs) { Sequence *seq=nullptr; Column *col = nullptr; try { QStringList owner_col=attribs[Attributes::OwnerColumn].split(':'), seq_attribs=Catalog::parseArrayValues(attribs[Attributes::Attribute]); QString attr[]={ Attributes::Start, Attributes::MinValue, Attributes::MaxValue, Attributes::Increment, Attributes::Cache, Attributes::Cycle }; attribs[Attributes::OwnerColumn]=QString(); /* If there are owner columns and the oid of sequence is greater than the owner column's table oid stores the oid of both (sequence and table) in order to swap it's ids at the end of import to avoid reference breaking when generation SQL code */ if(owner_col.size()==2) { PhysicalTable *tab = nullptr; QString col_name, tab_name; attribs_map extra_attrs, pos_attrib={ { Attributes::XPos, QString("0") }, { Attributes::YPos, QString("0") }}; if(attribs[Attributes::Oid].toUInt() > owner_col[0].toUInt()) seq_tab_swap[attribs[Attributes::Oid]]=owner_col[0]; /* Get the table and the owner column instances so the sequence code can be disabled if the column is an identity one */ extra_attrs[Attributes::Position] = schparser.getCodeDefinition(Attributes::Position, pos_attrib, SchemaParser::XmlDefinition); tab_name = getDependencyObject(owner_col[0], ObjectType::Table, true, auto_resolve_deps, false, extra_attrs); tab = dbmodel->getTable(tab_name); if(!tab) { tab_name = getDependencyObject(owner_col[0], ObjectType::ForeignTable, true, auto_resolve_deps, false, extra_attrs); tab = dbmodel->getTable(tab_name); } col_name=getColumnName(owner_col[0], owner_col[1]); if(tab) col = tab->getColumn(col_name); } for(int i=0; i < seq_attribs.size(); i++) attribs[attr[i]]=seq_attribs[i]; loadObjectXML(ObjectType::Sequence, attribs); seq=dbmodel->createSequence(); dbmodel->addSequence(seq); //Disable the sequence's SQL when the owner column is identity if(col && col->isIdentity()) { col->setIdSeqAttributes(seq->getMinValue(), seq->getMaxValue(), seq->getIncrement(), seq->getStart(), seq->getCache(), seq->isCycle()); seq->setSQLDisabled(true); } } catch(Exception &e) { if(seq) delete(seq); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createAggregate(attribs_map &attribs) { Aggregate *agg=nullptr; try { QStringList types; QString func_types[]={ Attributes::TransitionFunc, Attributes::FinalFunc }, sch_name; for(unsigned i=0; i < 2; i++) attribs[func_types[i]]=getDependencyObject(attribs[func_types[i]], ObjectType::Function, true, auto_resolve_deps, true, {{Attributes::RefType, func_types[i]}}); types=getTypes(attribs[Attributes::Types], true); attribs[Attributes::Types]=QString(); if(!types.isEmpty()) { for(int i=0; i < types.size(); i++) attribs[Attributes::Types]+=types[i]; } attribs[Attributes::StateType]=getType(attribs[Attributes::StateType], true, {{Attributes::RefType, Attributes::StateType}}); attribs[Attributes::SortOp]=getDependencyObject(attribs[Attributes::SortOp], ObjectType::Operator, true); loadObjectXML(ObjectType::Aggregate, attribs); agg=dbmodel->createAggregate(); dbmodel->addAggregate(agg); /* Removing the schema name from the aggregate name. The catalog query for certain aggregates (under pg_catalog for instance) will return names in the form "pg_catalog.agg_name" which cause objects to be imported with wrong names so the fix below is needed */ sch_name=agg->getSchema()->getName() + QChar('.'); if(agg->getName().startsWith(sch_name)) agg->setName(agg->getName().remove(sch_name)); } catch(Exception &e) { if(agg) delete(agg); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createType(attribs_map &attribs) { Type *type=nullptr; try { attribs[attribs[Attributes::Configuration]]=Attributes::True; if(!attribs[Attributes::EnumType].isEmpty()) { attribs[Attributes::Enumerations]=Catalog::parseArrayValues(attribs[Attributes::Enumerations]).join(','); attribs[Attributes::Enumerations].remove('"'); } else if(!attribs[Attributes::CompositeType].isEmpty()) { QStringList comp_attribs, values; TypeAttribute type_attrib; comp_attribs=Catalog::parseArrayValues(attribs[Attributes::TypeAttribute]); attribs[Attributes::TypeAttribute]=QString(); for(int i=0; i < comp_attribs.size(); i++) { values=comp_attribs[i].split(':'); if(values.size() >= 2) { type_attrib.setName(values[0].remove('"')); type_attrib.setType(PgSqlType::parseString(values[1].remove('\\'))); type_attrib.setCollation(dbmodel->getObject(getObjectName(values[2].remove('"')), ObjectType::Collation)); attribs[Attributes::TypeAttribute]+=type_attrib.getCodeDefinition(SchemaParser::XmlDefinition); } } } else if(!attribs[Attributes::RangeType].isEmpty()) { QStringList range_attr=Catalog::parseArrayValues(attribs[Attributes::RangeAttribs]); attribs[Attributes::Subtype]=getType(range_attr[0], true); attribs[Attributes::Collation]=getDependencyObject(range_attr[1], ObjectType::Collation, true); attribs[Attributes::OpClass]=getDependencyObject(range_attr[2], ObjectType::OpClass, true); attribs[Attributes::CanonicalFunc]=getDependencyObject(range_attr[3], ObjectType::Function, true); attribs[Attributes::SubtypeDiffFunc]=getDependencyObject(range_attr[4], ObjectType::Function, true); } else { QString type_name=getObjectName(attribs[Attributes::Oid]), func_types[]={ Attributes::InputFunc, Attributes::OutputFunc, Attributes::RecvFunc, Attributes::SendFunc, Attributes::TpmodInFunc, Attributes::TpmodOutFunc, Attributes::AnalyzeFunc }; unsigned i, count=sizeof(func_types)/sizeof(QString); attribs[Attributes::Element]=getType(attribs[Attributes::Element], false); /* Workaround: if importing a datatype that is part of an extension we avoid the importing of * its supporting functions (since they will not be necessary here because the type will be sql-disabled)*/ if(!catalog.isExtensionObject(attribs[Attributes::Oid].toUInt())) { for(i=0; i < count; i++) { attribs[func_types[i]]=getDependencyObject(attribs[func_types[i]], ObjectType::Function, true, true, true, {{Attributes::RefType, func_types[i]}}); /* Since pgModeler requires that type functions refers to the constructing type as "any" it's necessary to replace the function parameter types names */ attribs[func_types[i]].replace(QString("IN ") + type_name, QString("IN any")); } } } loadObjectXML(ObjectType::Type, attribs); type=dbmodel->createType(); dbmodel->addType(type); } catch(Exception &e) { if(type) delete(type); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createTable(attribs_map &attribs) { Table *table=nullptr; try { vector inh_cols; attribs_map pos_attrib={ { Attributes::XPos, QString("0") }, { Attributes::YPos, QString("0") }}; attribs[Attributes::Columns]=QString(); attribs[Attributes::Position]=schparser.getCodeDefinition(Attributes::Position, pos_attrib, SchemaParser::XmlDefinition); createColumns(attribs, inh_cols); loadObjectXML(ObjectType::Table, attribs); table=dbmodel->createTable(); for(unsigned col_idx : inh_cols) inherited_cols.push_back(table->getColumn(col_idx)); // Storing the partition bound expression temporarily in the table in order to configure the partition hierarchy later table->setPartitionBoundingExpr(attribs[Attributes::PartitionBoundExpr].remove(QRegExp("^(FOR)( )+(VALUES)( )*", Qt::CaseInsensitive))); // Retrieving the partitioned table related to the partition table being created if(!attribs[Attributes::PartitionedTable].isEmpty()) { Table *partitioned_tab = nullptr; attribs[Attributes::PartitionedTable] = getDependencyObject(attribs[Attributes::PartitionedTable], ObjectType::Table, true, auto_resolve_deps, false); partitioned_tab = dbmodel->getTable(attribs[Attributes::PartitionedTable]); table->setPartionedTable(partitioned_tab); if(!partitioned_tab) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]).arg(BaseObject::getTypeName(ObjectType::Table)) .arg(attribs[Attributes::PartitionedTable]).arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel ,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } // Creating partition keys if present if(attribs[Attributes::IsPartitioned] == Attributes::True) { QStringList cols, collations, opclasses, exprs; PartitionKey part_key; PartitioningType part_type; QString coll_name, opc_name; Collation *coll = nullptr; OperatorClass *opclass = nullptr; vector part_keys; part_type = PartitioningType(attribs[Attributes::Partitioning]); table->setPartitioningType(part_type); cols=Catalog::parseArrayValues(attribs[Attributes::PartKeyCols]); collations=Catalog::parseArrayValues(attribs[Attributes::PartKeyColls]); opclasses=Catalog::parseArrayValues(attribs[Attributes::PartKeyOpCls]); exprs = Catalog::parseIndexExpressions(attribs[Attributes::PartKeyExprs]); for(int i = 0; i < cols.size(); i++) { part_key = PartitionKey(); // Retrieving the column used by the partition key if(cols[i] != QString("0")) part_key.setColumn(table->getColumn(getColumnName(attribs[Attributes::Oid], cols[i]))); else if(!exprs.isEmpty()) { part_key.setExpression(exprs.front()); exprs.pop_front(); } // Retriving the collation for the partion key if(i < collations.size() && collations[i] != QString("0")) { coll_name = getDependencyObject(collations[i], ObjectType::Collation, false, true, false); coll = dynamic_cast(dbmodel->getObject(coll_name, ObjectType::Collation)); //Even if the collation exists we'll ignore it when it is the "pg_catalog.default" if(coll && (!coll->isSystemObject() || (coll->isSystemObject() && coll->getName() != QString("default")))) part_key.setCollation(coll); } // Retriving the operator class for the partion key if(i < opclasses.size() && opclasses[i] != QString("0")) { opc_name = getDependencyObject(opclasses[i], ObjectType::OpClass, true, true, false); opclass = dynamic_cast(dbmodel->getObject(opc_name, ObjectType::OpClass)); if(opclass) part_key.setOperatorClass(opclass); } part_keys.push_back(part_key); } table->addPartitionKeys(part_keys); } dbmodel->addTable(table); imported_tables[attribs[Attributes::Oid].toUInt()] = table; } catch(Exception &e) { if(table) delete(table); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createView(attribs_map &attribs) { View *view=nullptr; Reference ref; Column col; unsigned type_oid = 0; QString type_name, type_def, unknown_obj_xml, sch_name; bool is_type_registered = false; QStringList ref_tab_oids; PhysicalTable *ref_tab = nullptr; try { attribs_map pos_attrib={{ Attributes::XPos, QString("0") }, { Attributes::YPos, QString("0") }}; attribs[Attributes::Position]=schparser.getCodeDefinition(Attributes::Position, pos_attrib, SchemaParser::XmlDefinition); ref=Reference(attribs[Attributes::Definition], QString()); ref.setDefinitionExpression(true); sch_name = getDependencyObject(attribs[Attributes::SchemaOid], ObjectType::Schema, true, auto_resolve_deps, false); retrieveTableColumns(sch_name, attribs[Attributes::Name]); //Creating columns for(auto &itr : columns[attribs[Attributes::Oid].toUInt()]) { col.setName(itr.second[Attributes::Name]); type_oid=itr.second[Attributes::TypeOid].toUInt(); /* If the type has an entry on the types map and its OID is greater than system object oids, * means that it's a user defined type, thus, there is the need to check if the type * is registered. */ if(types.count(type_oid)!=0 && type_oid > catalog.getLastSysObjectOID()) { /* Building the type name prepending the schema name in order to search it on * the user defined types list at PgSQLType class */ type_name=BaseObject::formatName(getObjectName(types[type_oid][Attributes::Schema], true), false); type_name+=QString("."); if(types[type_oid][Attributes::Category] == ~CategoryType(CategoryType::Array)) { int dim = types[type_oid][Attributes::Name].count(QString("[]")); QString aux_name = types[type_oid][Attributes::Name].remove(QString("[]")); type_name+=BaseObject::formatName(aux_name, false); type_name+=QString("[]").repeated(dim); } else type_name+=BaseObject::formatName(types[type_oid][Attributes::Name], false); is_type_registered=PgSqlType::isRegistered(type_name, dbmodel); } else { type_name = itr.second[Attributes::Type]; is_type_registered=(types.count(type_oid)!=0 && PgSqlType::isRegistered(type_name, dbmodel)); } /* Checking if the type used by the column exists (is registered), * if not it'll be created when auto_resolve_deps is checked. The only exception here if for * array types [] that will not be automatically created because they are derivated from * the non-array type, this way, if the original type is created there is no need to create the array form */ if(auto_resolve_deps && !is_type_registered && !type_name.contains(QString("[]"))) // Try to create the missing data type getType(itr.second[Attributes::TypeOid], false); col.setType(PgSqlType::parseString(type_name)); ref.addColumn(&col); } // Configuring the reference tables for(auto &tab_oid : Catalog::parseArrayValues(attribs[Attributes::RefTables])) { ref_tab = dbmodel->getTable(getDependencyObject(tab_oid, ObjectType::Table, true, true, false)); // If we couldn't get a table from tab_oid we try to get a foreign table if(!ref_tab) ref_tab = dbmodel->getForeignTable(getDependencyObject(tab_oid, ObjectType::ForeignTable, true, true, false)); ref.addReferencedTable(ref_tab); } attribs[Attributes::References]=ref.getXMLDefinition(); loadObjectXML(ObjectType::View, attribs); view = dbmodel->createView(); dbmodel->addView(view); } catch(Exception &e) { if(view) delete(view); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createRule(attribs_map &attribs) { Rule *rule=nullptr; QString cmds=attribs[Attributes::Commands]; int start=-1; QRegExp cond_regexp(QString("(WHERE)(.)+(DO)")); ObjectType table_type=ObjectType::Table; try { start=cond_regexp.indexIn(cmds); if(start >=0) { attribs[Attributes::Condition]=cmds.mid(start, cond_regexp.matchedLength()); attribs[Attributes::Condition].remove(QRegExp(QString("(DO)|(WHERE)"))); } attribs[Attributes::Commands]=Catalog::parseRuleCommands(attribs[Attributes::Commands]).join(';'); if(attribs[Attributes::TableType]==BaseObject::getSchemaName(ObjectType::View)) table_type=ObjectType::View; attribs[Attributes::Table]=getDependencyObject(attribs[Attributes::Table], table_type, true, auto_resolve_deps, false); loadObjectXML(ObjectType::Rule, attribs); rule=dbmodel->createRule(); } catch(Exception &e) { if(rule) delete(rule); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createTrigger(attribs_map &attribs) { try { ObjectType table_type; table_type=BaseObject::getObjectType(attribs[Attributes::TableType]); attribs[Attributes::Table]=getDependencyObject(attribs[Attributes::Table], table_type, true, auto_resolve_deps, false); attribs[Attributes::TriggerFunc]=getDependencyObject(attribs[Attributes::TriggerFunc], ObjectType::Function, true, true); attribs[Attributes::Arguments]=Catalog::parseArrayValues(attribs[Attributes::Arguments].remove(QString(",\"\""))).join(','); loadObjectXML(ObjectType::Trigger, attribs); dbmodel->createTrigger(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createIndex(attribs_map &attribs) { try { QStringList cols, opclasses, collations, exprs; IndexElement elem; BaseTable *parent_tab=nullptr; Collation *coll=nullptr; OperatorClass *opclass=nullptr; QString tab_name, coll_name, opc_name; int i; attribs[Attributes::Factor]=QString("90"); tab_name=getDependencyObject(attribs[Attributes::Table], ObjectType::Table, true, auto_resolve_deps, false); parent_tab=dynamic_cast(dbmodel->getObject(tab_name, ObjectType::Table)); if(!parent_tab) { tab_name=getDependencyObject(attribs[Attributes::Table], ObjectType::View, true, auto_resolve_deps, false); parent_tab=dynamic_cast(dbmodel->getObject(tab_name, ObjectType::View)); if(!parent_tab) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]).arg(BaseObject::getTypeName(ObjectType::Index)) .arg(tab_name).arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel ,__PRETTY_FUNCTION__,__FILE__,__LINE__); } cols=Catalog::parseArrayValues(attribs[Attributes::Columns]); collations=Catalog::parseArrayValues(attribs[Attributes::Collations]); opclasses=Catalog::parseArrayValues(attribs[Attributes::OpClasses]); exprs = Catalog::parseIndexExpressions(attribs[Attributes::Expressions]); for(i=0; i < cols.size(); i++) { elem=IndexElement(); if(cols[i]!=QString("0")) { if(parent_tab->getObjectType() == ObjectType::Table) elem.setColumn(dynamic_cast
(parent_tab)->getColumn(getColumnName(attribs[Attributes::Table], cols[i]))); else elem.setExpression(getColumnName(attribs[Attributes::Table], cols[i])); } else if(!exprs.isEmpty()) { elem.setExpression(exprs.front()); exprs.pop_front(); } if(i < collations.size() && collations[i]!=QString("0")) { coll_name=getDependencyObject(collations[i], ObjectType::Collation, false, true, false); coll=dynamic_cast(dbmodel->getObject(coll_name, ObjectType::Collation)); //Even if the collation exists we'll ignore it when it is the "pg_catalog.default" if(coll && (!coll->isSystemObject() || (coll->isSystemObject() && coll->getName() != QString("default")))) elem.setCollation(coll); } if(i < opclasses.size() && opclasses[i]!=QString("0")) { opc_name=getDependencyObject(opclasses[i], ObjectType::OpClass, true, true, false); opclass=dynamic_cast(dbmodel->getObject(opc_name, ObjectType::OpClass)); if(opclass) elem.setOperatorClass(opclass); } if(elem.getColumn() || !elem.getExpression().isEmpty()) attribs[Attributes::Elements]+=elem.getCodeDefinition(SchemaParser::XmlDefinition); } attribs[Attributes::Table]=tab_name; loadObjectXML(ObjectType::Index, attribs); dbmodel->createIndex(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createConstraint(attribs_map &attribs) { Constraint *constr=nullptr; try { QString table_oid=attribs[Attributes::Table], ref_tab_oid=attribs[Attributes::RefTable], tab_name; PhysicalTable *table=nullptr; //If the table oid is 0 indicates that the constraint is part of a data type like domains if(!table_oid.isEmpty() && table_oid!=QString("0")) { ObjectType tab_type = BaseObject::getObjectType(attribs[Attributes::TableType]); QStringList factor=Catalog::parseArrayValues(attribs[Attributes::Factor]); //Retrieving the table is it was not imported yet and auto_resolve_deps is true tab_name=getDependencyObject(table_oid, tab_type, true, auto_resolve_deps, false); if(!factor.isEmpty() && factor[0].startsWith(QString("fillfactor="))) attribs[Attributes::Factor]=factor[0].remove(QString("fillfactor=")); attribs[attribs[Attributes::Type]]=Attributes::True; table=dynamic_cast(dbmodel->getObject(tab_name, tab_type)); if(attribs[Attributes::Type]==Attributes::ExConstr) { QStringList cols, opclasses, opers, exprs; ExcludeElement elem; QString opc_name, op_name; OperatorClass *opclass=nullptr; Operator *oper=nullptr; attribs[Attributes::SrcColumns]=QString(); attribs[Attributes::Expression]=attribs[Attributes::Condition]; cols=Catalog::parseArrayValues(attribs[Attributes::Columns]); opers=Catalog::parseArrayValues(attribs[Attributes::Operators]); opclasses=Catalog::parseArrayValues(attribs[Attributes::OpClasses]); /* Due to the way exclude constraints are constructed (similar to indexes), * we get the constraint's definition in for of expressions. Internally we use pg_get_constraintdef. * This way we will get EXCLUDE USING [index type](elements). The elements in this case is a set of expression * which we work to separate column only references from complex expression. Only complex expression will be used * and assigned to their exclude constraint elements. Column references are used in exclude elements but relying in * the cols list above */ exprs=attribs[Attributes::Expressions] .replace(QString("EXCLUDE USING %1 (").arg(attribs[Attributes::IndexType]), QString()) .split(QRegExp("(WITH )(\\+|\\-|\\*|\\/|\\<|\\>|\\=|\\~|\\!|\\@|\\#|\\%|\\^|\\&|\\||\\'|\\?)+((,)?|(\\))?)"), QString::SkipEmptyParts); for(int i=0; i < cols.size(); i++) { elem=ExcludeElement(); if(cols[i] != QString("0")) elem.setColumn(table->getColumn(getColumnName(table_oid, cols[i]))); else elem.setExpression(exprs.front().trimmed()); exprs.pop_front(); if(i < opclasses.size() && opclasses[i]!=QString("0")) { opc_name=getDependencyObject(opclasses[i], ObjectType::OpClass, true, true, false); opclass=dynamic_cast(dbmodel->getObject(opc_name, ObjectType::OpClass)); if(opclass) elem.setOperatorClass(opclass); } if(i < opers.size() && opers[i]!=QString("0")) { op_name=getDependencyObject(opers[i], ObjectType::Operator, true, true, false); oper=dynamic_cast(dbmodel->getObject(op_name, ObjectType::Operator)); if(oper) elem.setOperator(oper); } attribs[Attributes::Elements]+=elem.getCodeDefinition(SchemaParser::XmlDefinition); } } else { //Clears the tablespace attribute when the constraint is fk avoiding errors if(attribs[Attributes::Type]==Attributes::FkConstr) attribs[Attributes::Tablespace]=QString(); else if(attribs[Attributes::Type]==Attributes::CkConstr) { QString expr = attribs[Attributes::Expressions]; expr.replace(QString("CHECK ("), QString()); expr.remove(expr.lastIndexOf(')'), 1); attribs[Attributes::Expression] = expr; } attribs[Attributes::SrcColumns]=getColumnNames(attribs[Attributes::Table], attribs[Attributes::SrcColumns]).join(','); } attribs[Attributes::RefTable]=getDependencyObject(ref_tab_oid, ObjectType::Table, false, true, false); attribs[Attributes::DstColumns]=getColumnNames(ref_tab_oid, attribs[Attributes::DstColumns]).join(','); attribs[Attributes::Table]=tab_name; loadObjectXML(ObjectType::Constraint, attribs); constr=dbmodel->createConstraint(nullptr); if(table && constr->getConstraintType()==ConstraintType::PrimaryKey) { table->addConstraint(constr); table->setModified(true); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createPolicy(attribs_map &attribs) { try { attribs[Attributes::Table]=getDependencyObject(attribs[Attributes::Table], ObjectType::Table, true, auto_resolve_deps, false); attribs[Attributes::Roles]=getObjectNames(attribs[Attributes::Roles]).join(','); loadObjectXML(ObjectType::Policy, attribs); dbmodel->createPolicy(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createEventTrigger(attribs_map &attribs) { try { attribs[Attributes::Function]=getDependencyObject(attribs[Attributes::Function], ObjectType::Function, true, true); attribs[Attributes::Filter]=QString("\t<%1 %2=\"%3\" %4=\"%5\"/>\n") .arg(Attributes::Filter) .arg(Attributes::Variable).arg(Attributes::Tag.toUpper()) .arg(Attributes::Values) .arg(Catalog::parseArrayValues(attribs[Attributes::Values].remove('"')).join(',')); loadObjectXML(ObjectType::EventTrigger, attribs); dbmodel->addEventTrigger(dbmodel->createEventTrigger()); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createForeignDataWrapper(attribs_map &attribs) { ForeignDataWrapper *fdw=nullptr; try { QStringList func_types={ Attributes::ValidatorFunc, Attributes::HandlerFunc }; for(auto &func_tp : func_types) attribs[func_tp] = getDependencyObject(attribs[func_tp], ObjectType::Function, true , true, true, {{Attributes::RefType, func_tp}}); attribs[Attributes::Options] = Catalog::parseArrayValues(attribs[Attributes::Options]).join(ForeignDataWrapper::OptionsSeparator); loadObjectXML(ObjectType::ForeignDataWrapper, attribs); fdw = dbmodel->createForeignDataWrapper(); dbmodel->addForeignDataWrapper(fdw); } catch(Exception &e) { if(fdw) delete(fdw); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createForeignServer(attribs_map &attribs) { ForeignServer *server=nullptr; try { attribs[Attributes::Fdw] = getDependencyObject(attribs[Attributes::Fdw], ObjectType::ForeignDataWrapper, true , true, true); attribs[Attributes::Options] = Catalog::parseArrayValues(attribs[Attributes::Options]).join(ForeignDataWrapper::OptionsSeparator); loadObjectXML(ObjectType::ForeignServer, attribs); server = dbmodel->createForeignServer(); dbmodel->addForeignServer(server); } catch(Exception &e) { if(server) delete(server); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createUserMapping(attribs_map &attribs) { UserMapping *usr_map=nullptr; try { attribs[Attributes::Server] = getDependencyObject(attribs[Attributes::Server], ObjectType::ForeignServer, true , true, true); attribs[Attributes::Options] = Catalog::parseArrayValues(attribs[Attributes::Options]).join(ForeignDataWrapper::OptionsSeparator); loadObjectXML(ObjectType::UserMapping, attribs); usr_map = dbmodel->createUserMapping(); dbmodel->addUserMapping(usr_map); } catch(Exception &e) { if(usr_map) delete(usr_map); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createForeignTable(attribs_map &attribs) { ForeignTable *ftable=nullptr; try { vector inh_cols; attribs_map pos_attrib={ { Attributes::XPos, QString("0") }, { Attributes::YPos, QString("0") }}; attribs[Attributes::Server] = getDependencyObject(attribs[Attributes::Server], ObjectType::ForeignServer, true , true, true); attribs[Attributes::Options] = Catalog::parseArrayValues(attribs[Attributes::Options]).join(ForeignDataWrapper::OptionsSeparator); attribs[Attributes::Columns]=QString(); attribs[Attributes::Position]=schparser.getCodeDefinition(Attributes::Position, pos_attrib, SchemaParser::XmlDefinition); createColumns(attribs, inh_cols); loadObjectXML(ObjectType::ForeignTable, attribs); ftable=dbmodel->createForeignTable(); for(unsigned col_idx : inh_cols) inherited_cols.push_back(ftable->getColumn(col_idx)); // Storing the partition bound expression temporarily in the table in order to configure the partition hierarchy later ftable->setPartitionBoundingExpr(attribs[Attributes::PartitionBoundExpr].remove(QRegExp("^(FOR)( )+(VALUES)( )*", Qt::CaseInsensitive))); // Retrieving the partitioned table related to the partition table being created if(!attribs[Attributes::PartitionedTable].isEmpty()) { Table *partitioned_tab = nullptr; attribs[Attributes::PartitionedTable] = getDependencyObject(attribs[Attributes::PartitionedTable], ObjectType::Table, true, auto_resolve_deps, false); partitioned_tab = dbmodel->getTable(attribs[Attributes::PartitionedTable]); ftable->setPartionedTable(partitioned_tab); if(!partitioned_tab) { throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(attribs[Attributes::Name]).arg(BaseObject::getTypeName(ObjectType::Table)) .arg(attribs[Attributes::PartitionedTable]).arg(BaseObject::getTypeName(ObjectType::Table)), ErrorCode::RefObjectInexistsModel ,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } dbmodel->addForeignTable(ftable); imported_tables[attribs[Attributes::Oid].toUInt()] = ftable; } catch(Exception &e) { if(ftable) delete(ftable); throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } void DatabaseImportHelper::createPermission(attribs_map &attribs) { ObjectType obj_type=static_cast(attribs[Attributes::ObjectType].toUInt()); Permission *perm=nullptr; QString sig; if(Permission::acceptsPermission(obj_type)) { QStringList perm_list; vector privs, gop_privs; QString role_name; Role *role=nullptr; BaseObject *object=nullptr; PhysicalTable *table=nullptr; //Parses the permissions vector string perm_list=Catalog::parseArrayValues(attribs[Attributes::Permission]); if(!perm_list.isEmpty()) { if(obj_type!=ObjectType::Column) { if(obj_type==ObjectType::Database) object=dbmodel; else { sig=getObjectName(attribs[Attributes::Oid], true); object=dbmodel->getObject(getObjectName(attribs[Attributes::Oid], true), obj_type); } } else { //If the object is column it's necessary to retrive the parent table to get the valid reference to column table=dynamic_cast(dbmodel->getObject(getObjectName(attribs[Attributes::Table]), {ObjectType::Table, ObjectType::ForeignTable})); object=table->getObject(getColumnName(attribs[Attributes::Table], attribs[Attributes::Oid]), ObjectType::Column); } } for(int i=0; i < perm_list.size(); i++) { //Parses the permission retrieving the role name as well the privileges over the object role_name=Permission::parsePermissionString(perm_list[i], privs, gop_privs); //Removing extra backslash from the role's names to avoid the role not to be found role_name.remove(QChar('\\')); if(!privs.empty() || gop_privs.empty()) { role=dynamic_cast(dbmodel->getObject(role_name, ObjectType::Role)); if(auto_resolve_deps && !role_name.isEmpty() && !role) { QString oid = catalog.getObjectOID(role_name, ObjectType::Role); getDependencyObject(oid, ObjectType::Role); role=dynamic_cast(dbmodel->getObject(role_name, ObjectType::Role)); } /* If the role doesn't exists and there is a name defined, throws an error because the roles wasn't found on the model */ if(!role && !role_name.isEmpty()) throw Exception(Exception::getErrorMessage(ErrorCode::RefObjectInexistsModel) .arg(QString("permission_%1").arg(perm_list[i])).arg(BaseObject::getTypeName(ObjectType::Permission)) .arg(role_name).arg(BaseObject::getTypeName(ObjectType::Role)) ,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { try { //Configuring the permisison perm=new Permission(object); if(role) perm->addRole(role); //Setting the ordinary privileges while(!privs.empty()) { perm->setPrivilege(privs.back(), true, false); privs.pop_back(); } //Setting the grant option privileges while(!gop_privs.empty()) { perm->setPrivilege(gop_privs.back(), true, true); gop_privs.pop_back(); } dbmodel->addPermission(perm); } catch(Exception &e) { if(perm) delete(perm); if(ignore_errors) errors.push_back(Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, dumpObjectAttributes(attribs))); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } } } } void DatabaseImportHelper::createTableInheritances(void) { //Creating table inheiritances if(dbmodel->getObjectCount(ObjectType::Table) > 0 && !import_canceled) { try { emit s_progressUpdated(90, trUtf8("Creating table inheritances..."), ObjectType::Relationship); __createTableInheritances(); } catch(Exception &e) { if(ignore_errors) errors.push_back(e); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void DatabaseImportHelper::createTablePartitionings(void) { if(imported_tables.empty()) return; try { PhysicalTable *table = nullptr, *part_table = nullptr; QString part_bound_expr; Relationship *rel_part = nullptr; emit s_progressUpdated(95, trUtf8("Creating table partitionings..."), ObjectType::Relationship); // Creating the paritioning relationships for(auto &itr : imported_tables) { table = itr.second; if(table->isPartition()) { part_bound_expr = table->getPartitionBoundingExpr(); part_table = table->getPartitionedTable(); /* Here, we force the detaching of the partition table so when * creating the relationship below all the needed validations can be done correctly */ table->setPartionedTable(nullptr); table->setPartitionBoundingExpr(QString()); rel_part = new Relationship(BaseRelationship::RelationshipPart, table, part_table); rel_part->setPartitionBoundingExpr(part_bound_expr); dbmodel->addRelationship(rel_part); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DatabaseImportHelper::destroyDetachedColumns(void) { if(inherited_cols.empty() || import_canceled) return; vector refs; PhysicalTable *parent_tab=nullptr; dbmodel->disconnectRelationships(); emit s_progressUpdated(100, trUtf8("Destroying unused detached columns..."), ObjectType::Column); //Destroying detached columns before create inheritances for(Column *col : inherited_cols) { dbmodel->getObjectReferences(col, refs, true); if(refs.empty()) { try { //Removing the column from the parent table and destroying it since they will be recreated by inheritances parent_tab=dynamic_cast(col->getParentTable()); parent_tab->removeObject(col); delete(col); } catch(Exception &e) { if(ignore_errors) errors.push_back(e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } } /* Force the validation and connection of inheritance relationships leading to the creation of inherited columns */ dbmodel->validateRelationships(); } void DatabaseImportHelper::createColumns(attribs_map &attribs, vector &inh_cols) { unsigned tab_oid=attribs[Attributes::Oid].toUInt(), type_oid=0, col_idx=0; bool is_type_registered=false; Column col; QString type_def, unknown_obj_xml, type_name, def_val; map::iterator itr, itr1, itr_end; if(tab_oid == 0) return; //Retrieving columns if they were not retrieved yet if(columns[attribs[Attributes::Oid].toUInt()].empty() && auto_resolve_deps) { QString sch_name; sch_name = getDependencyObject(attribs[Attributes::SchemaOid], ObjectType::Schema, true, auto_resolve_deps, false); retrieveTableColumns(sch_name, attribs[Attributes::Name]); } itr=itr1=columns[attribs[Attributes::Oid].toUInt()].begin(); itr_end=columns[attribs[Attributes::Oid].toUInt()].end(); attribs[Attributes::MaxObjCount]=QString::number(columns[attribs[Attributes::Oid].toUInt()].size()); //Creating columns while(itr!=itr_end) { if(itr->second.count(Attributes::Permission) && !itr->second.at(Attributes::Permission).isEmpty()) col_perms[tab_oid].push_back(itr->second[Attributes::Oid].toUInt()); if(itr->second[Attributes::Inherited]==Attributes::True) inh_cols.push_back(col_idx); col.setName(itr->second[Attributes::Name]); type_oid=itr->second[Attributes::TypeOid].toUInt(); /* If the type has an entry on the types map and its OID is greater than system object oids, means that it's a user defined type, thus, there is the need to check if the type is registered. */ if(types.count(type_oid)!=0 && type_oid > catalog.getLastSysObjectOID()) { /* Building the type name prepending the schema name in order to search it on * the user defined types list at PgSQLType class */ type_name=BaseObject::formatName(getObjectName(types[type_oid][Attributes::Schema], true), false); type_name+=QString("."); if(types[type_oid][Attributes::Category] == ~CategoryType(CategoryType::Array)) { int dim = types[type_oid][Attributes::Name].count(QString("[]")); QString aux_name = types[type_oid][Attributes::Name].remove(QString("[]")); type_name+=BaseObject::formatName(aux_name, false); type_name+=QString("[]").repeated(dim); } else type_name+=BaseObject::formatName(types[type_oid][Attributes::Name], false); is_type_registered=PgSqlType::isRegistered(type_name, dbmodel); } else { type_name=itr->second[Attributes::Type]; is_type_registered=(types.count(type_oid)!=0 && PgSqlType::isRegistered(type_name, dbmodel)); } /* Checking if the type used by the column exists (is registered), if not it'll be created when auto_resolve_deps is checked. The only exception here if for array types [] that will not be automatically created because they are derivated from the non-array type, this way, if the original type is created there is no need to create the array form */ if(auto_resolve_deps && !is_type_registered && !type_name.contains(QString("[]"))) // Try to create the missing data type getType(itr->second[Attributes::TypeOid], false); col.setIdentityType(BaseType::Null); col.setType(PgSqlType::parseString(type_name)); col.setNotNull(!itr->second[Attributes::NotNull].isEmpty()); col.setComment(itr->second[Attributes::Comment]); //Overriding the default value if the column is identity if(!itr->second[Attributes::IdentityType].isEmpty()) col.setIdentityType(itr->second[Attributes::IdentityType]); else { /* Removing extra/forced type casting in the retrieved default value. This is done in order to avoid unnecessary entries in the diff results. For instance: say in the model we have a column with the following configutation: > varchar(3) default 'foo' Now, when importing the same column the default value for it will be something like: > varchar(3) default 'foo'::character varying Since the extra chars in the default value of the imported column are redundant (casting varchar to character varying) we remove the '::character varying'. The idea here is to eliminate the cast if the casting is equivalent to the column type. */ def_val = itr->second[Attributes::DefaultValue]; if(!def_val.startsWith(QString("nextval(")) && def_val.contains(QString("::"))) { QStringList values = def_val.split(QString("::")); if(values.size() > 1 && ((~col.getType() == values[1]) || (~col.getType() == QString("char") && values[1] == QString("bpchar")) || (col.getType().isUserType() && (~col.getType()).endsWith(values[1])))) def_val=values[0]; } col.setDefaultValue(def_val); } //Checking if the collation used by the column exists, if not it'll be created when auto_resolve_deps is checked if(auto_resolve_deps && !itr->second[Attributes::Collation].isEmpty()) getDependencyObject(itr->second[Attributes::Collation], ObjectType::Collation); col.setCollation(dbmodel->getObject(getObjectName(itr->second[Attributes::Collation]),ObjectType::Collation)); attribs[Attributes::Columns]+=col.getCodeDefinition(SchemaParser::XmlDefinition); itr++; col_idx++; } } void DatabaseImportHelper::assignSequencesToColumns(void) { PhysicalTable *table=nullptr; Column *col=nullptr; vector tables; emit s_progressUpdated(100, trUtf8("Assigning sequences to columns..."), ObjectType::Sequence); tables = *dbmodel->getObjectList(ObjectType::Table); tables.insert(tables.end(), dbmodel->getObjectList(ObjectType::ForeignTable)->begin(), dbmodel->getObjectList(ObjectType::ForeignTable)->end()); for(auto &object : tables) { table=dynamic_cast(object); for(auto &tab_obj : *table->getObjectList(ObjectType::Column)) { col=dynamic_cast(tab_obj); //Translating the default value nextval('sequence'::regclass) if(col->getType().isIntegerType() && col->getDefaultValue().contains(QString("nextval("))) { QString seq_name=col->getDefaultValue(); Sequence *seq=nullptr; //Extracting the name from the nextval(''::regclass) portion and formating it seq_name.remove(0, seq_name.indexOf(QChar('\'')) + 1); seq_name.remove(seq_name.indexOf(QChar('\'')), seq_name.length()); seq_name=BaseObject::formatName(seq_name); /* Checking if the sequence name contains the schema prepended. If not, it'll be prepended by retrieving the table's schema name */ if(!seq_name.contains(QChar('.'))) seq_name.prepend(table->getSchema()->getName(true) + QString(".")); seq=dbmodel->getSequence(seq_name); if(seq) { col->setSequence(seq); if(col->getParentTable()->getObjectId() < seq->getObjectId()) BaseObject::swapObjectsIds(col->getParentTable(), seq, false); } } } } } void DatabaseImportHelper::__createTableInheritances(void) { vector table_oids; Relationship *rel=nullptr; PhysicalTable *parent_tab=nullptr, *child_tab=nullptr; QStringList inh_list; ObjectType tab_type; attribs_map tab_attribs; unsigned inh_oid; table_oids = object_oids[ObjectType::Table]; table_oids.insert(table_oids.end(), object_oids[ObjectType::ForeignTable].begin(), object_oids[ObjectType::ForeignTable].end()); for(auto &oid : table_oids) { tab_attribs=(user_objs.count(oid) ? user_objs[oid] : system_objs[oid]); tab_type = static_cast(tab_attribs[Attributes::ObjectType].toUInt()); //Get the list of parent table's oids inh_list=Catalog::parseArrayValues(user_objs[oid][Attributes::Parents]); if(!inh_list.isEmpty()) { //Get the child table resolving it's name from the oid child_tab=dynamic_cast(dbmodel->getObject(getObjectName(user_objs[oid][Attributes::Oid]), tab_type)); while(!inh_list.isEmpty()) { inh_oid = inh_list.front().toUInt(); tab_attribs=(user_objs.count(inh_oid) ? user_objs[inh_oid] : system_objs[inh_oid]); tab_type = static_cast(tab_attribs[Attributes::ObjectType].toUInt()); //Get the parent table resolving it's name from the oid parent_tab=dynamic_cast(dbmodel->getObject(getObjectName(inh_list.front()), tab_type)); try { if(!parent_tab && auto_resolve_deps) { getDependencyObject(inh_list.front(), ObjectType::Table, true); tab_type = static_cast(tab_attribs[Attributes::ObjectType].toUInt()); parent_tab=dynamic_cast(dbmodel->getObject(getObjectName(inh_list.front()), tab_type)); } if(!parent_tab) throw Exception(Exception::getErrorMessage(ErrorCode::InvInheritParentTableNotFound) .arg(child_tab->getSignature()).arg(inh_list.front()), ErrorCode::InvInheritParentTableNotFound,__PRETTY_FUNCTION__,__FILE__,__LINE__); inh_list.pop_front(); //Create the inheritance relationship rel=new Relationship(Relationship::RelationshipGen, child_tab, parent_tab); rel->setName(PgModelerNs::generateUniqueName(rel, (*dbmodel->getObjectList(ObjectType::Relationship)))); dbmodel->addRelationship(rel); rel=nullptr; } catch(Exception &e) { if(rel) delete(rel); if(ignore_errors) errors.push_back(e); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } } } void DatabaseImportHelper::configureDatabase(attribs_map &attribs) { try { attribs[Attributes::AppendAtEod]=QString(); attribs[Attributes::Layers]=QString(); attribs[Attributes::ActiveLayers]=QString(); loadObjectXML(ObjectType::Database, attribs); dbmodel->configureDatabase(attribs); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__,__FILE__,__LINE__, &e, xmlparser->getXMLBuffer()); } } QString DatabaseImportHelper::getObjectName(const QString &oid, bool signature_form) { unsigned obj_oid=oid.toUInt(); if(obj_oid==0) return(QString()); else { attribs_map obj_attr; //Get the object from one of the maps of objects if(user_objs.count(obj_oid)) obj_attr=user_objs[obj_oid]; else obj_attr=system_objs[obj_oid]; if(obj_attr.empty()) return(QString()); else { QString sch_name, obj_name=obj_attr[Attributes::Name]; ObjectType obj_type=static_cast(obj_attr[Attributes::ObjectType].toUInt()); //If the object accepts an schema retrieve the schema name too if(BaseObject::acceptsSchema(obj_type)) sch_name=getObjectName(obj_attr[Attributes::Schema]); if(!sch_name.isEmpty()) obj_name.prepend(sch_name + QString(".")); //Formatting the name in form of signature (only for functions and operators) if(signature_form && (obj_type==ObjectType::Function || obj_type==ObjectType::Operator || obj_type==ObjectType::Aggregate || obj_type==ObjectType::OpFamily || obj_type==ObjectType::OpClass)) { QStringList params; if(obj_type==ObjectType::Function) { QStringList arg_types=getTypes(obj_attr[Attributes::ArgTypes], false), arg_modes=Catalog::parseArrayValues(obj_attr[Attributes::ArgModes]); for(int i=0; i < arg_types.size(); i++) { if(arg_modes.isEmpty()) params.push_back(arg_types[i]); else if(arg_modes[i]!=QString("t") && arg_modes[i]!=QString("o")) { if(arg_modes[i]==QString("i")) params.push_back(/* QString("IN ") + */ arg_types[i]); else if(arg_modes[i]==QString("b")) params.push_back(QString("INOUT ") + arg_types[i]); else params.push_back(QString("VARIADIC ") + arg_types[i]); } } } else if(obj_type==ObjectType::Aggregate) { QStringList params=getTypes(obj_attr[Attributes::Types], false); if(params.isEmpty()) params.push_back(QString("*")); } else if(obj_type==ObjectType::Operator) { if(obj_attr[Attributes::LeftType].toUInt() > 0) params.push_back(getType(obj_attr[Attributes::LeftType], false)); else params.push_back(QString("NONE")); if(obj_attr[Attributes::RightType].toUInt() > 0) params.push_back(getType(obj_attr[Attributes::RightType], false)); else params.push_back(QString("NONE")); } else { obj_name += QString(" USING %1").arg(obj_attr[Attributes::IndexType]); } if(obj_type != ObjectType::OpFamily && obj_type != ObjectType::OpClass) obj_name+=QString("(") + params.join(',') + QString(")"); } return(obj_name); } } } QStringList DatabaseImportHelper::getObjectNames(const QString &oid_vect, bool signature_form) { QStringList list=Catalog::parseArrayValues(oid_vect); if(!list.isEmpty()) { for(int i=0; i < list.size(); i++) list[i]=getObjectName(list[i], signature_form); } return(list); } QString DatabaseImportHelper::getColumnName(const QString &tab_oid_str, const QString &col_id_str, bool prepend_tab_name) { QString col_name; unsigned tab_oid=tab_oid_str.toUInt(), col_id=col_id_str.toUInt(); if(columns.count(tab_oid) && columns[tab_oid].count(col_id)) { if(prepend_tab_name) col_name=getObjectName(tab_oid_str) + QString("."); col_name+=columns[tab_oid][col_id].at(Attributes::Name); } return(col_name); } QStringList DatabaseImportHelper::getColumnNames(const QString &tab_oid_str, const QString &col_id_vect, bool prepend_tab_name) { QStringList col_names, col_ids; QString tab_name; unsigned tab_oid=tab_oid_str.toUInt(), col_id=0; if(columns.count(tab_oid)) { if(prepend_tab_name) tab_name=getObjectName(tab_oid_str) + QString("."); col_ids=Catalog::parseArrayValues(col_id_vect); for(int i=0; i < col_ids.size(); i++) { col_id=col_ids[i].toUInt(); if(columns[tab_oid].count(col_id)) col_names.push_back(tab_name + columns[tab_oid][col_id].at(Attributes::Name)); } } return(col_names); } QString DatabaseImportHelper::getType(const QString &oid_str, bool generate_xml, attribs_map extra_attribs) { try { attribs_map type_attr; QString xml_def, sch_name, obj_name, aux_name; unsigned type_oid=oid_str.toUInt(), elem_tp_oid = 0, dimension=0, object_id=0; bool is_derivated_from_obj = false; if(type_oid > 0) { if(types.count(type_oid)) { type_attr=types[type_oid]; object_id=type_attr[Attributes::ObjectId].toUInt(); } //Special treatment for array types. Removes the [] descriptor when generating XML code for the type if(!type_attr.empty() && type_attr[Attributes::Category]==QString("A") && type_attr[Attributes::Name].contains(QString("[]"))) { obj_name=type_attr[Attributes::Name]; elem_tp_oid=type_attr[Attributes::Element].toUInt(); if(generate_xml) { dimension=type_attr[Attributes::Name].count(QString("[]")); obj_name.remove(QString("[]")); } } else obj_name=type_attr[Attributes::Name]; /* If the type was generated from a table/sequence/view/domain and the source object is not yet imported and the auto resolve deps is enabled, we need to import it */ if(auto_resolve_deps && (!type_attr[Attributes::TypeClass].isEmpty() || type_attr[Attributes::Configuration] == BaseObject::getSchemaName(ObjectType::Domain))) { ObjectType obj_type; if(type_attr[Attributes::TypeClass]==BaseObject::getSchemaName(ObjectType::Table)) obj_type=ObjectType::Table; else if(type_attr[Attributes::TypeClass]==BaseObject::getSchemaName(ObjectType::View)) obj_type=ObjectType::View; else if(type_attr[Attributes::TypeClass]==BaseObject::getSchemaName(ObjectType::Sequence)) obj_type=ObjectType::Sequence; else { /* Domains are the only kind of object associated to data types that don't * contains an object-id attribute (which is related to the object in pg_class that generates the type) * this way we need to use type_oid instead to force the importing of the domain */ obj_type=ObjectType::Domain; object_id = type_oid; } is_derivated_from_obj = true; if(!user_objs.count(object_id) && !system_objs.count(object_id)) getDependencyObject(QString::number(object_id), obj_type, true, true, false); } /* Removing the optional modifier "without time zone" from date/time types. Since the class PgSQLTypes ommits the modifier it is necessary to reproduce this behavior here to avoid futher errors */ if(obj_name.startsWith(QString("timestamp")) || obj_name.startsWith(QString("time"))) obj_name.remove(QString(" without time zone")); /* Prepend the schema name only if it is not a system schema ('pg_catalog' or 'information_schema') and if the schema's names is already present in the type's name (in case of table types) */ sch_name = getObjectName(type_attr[Attributes::Schema]); if(!sch_name.isEmpty() && (is_derivated_from_obj || (sch_name != QString("pg_catalog") && sch_name!=QString("information_schema")) || type_oid > catalog.getLastSysObjectOID()) && !obj_name.contains(QRegExp(QString("^(\\\")?(%1)(\\\")?(\\.)").arg(sch_name)))) obj_name.prepend(sch_name + QString(".")); /* In case of auto resolve dependencies, if the type is a user defined one and is not derivated from table/view/sequence and was not created in the database model but its attributes were retrieved, the object will be created to avoid reference errors */ aux_name = obj_name; aux_name.remove(QString("[]")); if(auto_resolve_deps && !type_attr.empty() && !is_derivated_from_obj && type_oid > catalog.getLastSysObjectOID() && !dbmodel->getType(aux_name)) { //If the type is not an array one we simply use the current type attributes map if(type_attr[Attributes::Category] != QString("A")) createObject(type_attr); /* In case the type is an array one we should use the oid held by "element" attribute to create the type related to current one */ else if(elem_tp_oid > catalog.getLastSysObjectOID() && types.count(elem_tp_oid)) createObject(types[elem_tp_oid]); } if(generate_xml) { extra_attribs[Attributes::Name]=obj_name; extra_attribs[Attributes::Dimension]=(dimension > 0 ? QString::number(dimension) : QString()); schparser.ignoreUnkownAttributes(true); xml_def=schparser.getCodeDefinition(Attributes::PgSqlBaseType, extra_attribs, SchemaParser::XmlDefinition); schparser.ignoreUnkownAttributes(false); } else return(obj_name); } return(xml_def); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QStringList DatabaseImportHelper::getTypes(const QString &oid_vect, bool generate_xml) { QStringList list=Catalog::parseArrayValues(oid_vect); for(int i=0; i < list.size(); i++) list[i]=getType(list[i], generate_xml); return(list); } pgmodeler-0.9.2/libpgmodeler_ui/src/databaseimporthelper.h000066400000000000000000000316171360462764600240270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DatabaseImportHelper \brief Implements the base operations to import existing databases into model (reverse engineering) */ #ifndef DATABASE_IMPORT_HELPER_H #define DATABASE_IMPORT_HELPER_H #include #include #include "catalog.h" #include "modelwidget.h" #include class DatabaseImportHelper: public QObject { private: Q_OBJECT //! \brief Random number generator engine used to generate random colors for imported schemas default_random_engine rand_num_engine; static const QString UnkownObjectOidXml; /*! \brief File handle to log the import process. This file is opened for writing only when the 'ignore_errors' is true */ QFile import_log; //! \brief Stores the errors generated during the import vector errors; //! \brief Instance of catalog class to query system catalogs Catalog catalog; //! \brief Instance of a connection to work on Connection connection; //! \brief Stores the current configured catalog filter unsigned import_filter; //! \brief Indicates that import was canceled by user (only on thread mode) bool import_canceled, //! \brief Indicates that import must ignore any error generated during the import ignore_errors, //! \brief Enables the import of system objects (under pg_catalog / information_schema) import_sys_objs, //! \brief Enables the import of extension created objects import_ext_objs, //! \brief Enables the dependency resolution by query the catalog when a needed object wasn't retrieved auto_resolve_deps, //! \brief Outputs to STDOUT the executed query catalogs as well the generated XML debug_mode, //! \brief Generate random colors for relationships rand_rel_colors, //! \brief Indicates to the importer that the relationship update step must be executed update_fk_rels; //! \brief Stores the selected objects oids to be imported map> object_oids; /*! \brief Stores the selected column ids to be imported. The key of this map it the oid of parent table */ map> column_oids; //! \brief Stores the oid of objects sucessfully created vector created_objs; //! \brief Stores the selected objects oids to be imported vector creation_order; //! \brief Stores the creation order for constraints vector constr_creation_order; //! \brief Stores the user defined objects attributes map user_objs; //! \brief Stores the system catalog objects attributes map system_objs; //! \brief Stores all defined types attributes map types; //! \brief Stores all selected columns attributes map> columns; //! \brief Stores the oids of all objects that has permissions to be created vector obj_perms; //! \brief Stores the oids of all columns that has permissions to be created map> col_perms; /*! \brief This special map is used to swap the id of a table and the sequence that is referenced by it in order to avoid reference breaking */ map seq_tab_swap; /*! \brief Stores all columns that are inherited on the database. Since these columns are created dettached from parent columns on the resulting model before the inheritances creation they will be removed from their related tables if there is no object referencing them */ vector inherited_cols; //! \brief Reference for the database model instance of the model widget DatabaseModel *dbmodel; //! \brief Stored the table created (value) from the oid (key) so the partitioning hierarchy (if existent) can be reconstructed map imported_tables; XmlParser *xmlparser; SchemaParser schparser; void configureDatabase(attribs_map &attribs); void createObject(attribs_map &attribs); void createTablespace(attribs_map &attribs); void createSchema(attribs_map &attribs); void createRole(attribs_map &attribs); void createDomain(attribs_map &attribs); void createExtension(attribs_map &attribs); void createFunction(attribs_map &attribs); void createLanguage(attribs_map &attribs); void createOperatorFamily(attribs_map &attribs); void createOperatorClass(attribs_map &attribs); void createOperator(attribs_map &attribs); void createCollation(attribs_map &attribs); void createCast(attribs_map &attribs); void createConversion(attribs_map &attribs); void createSequence(attribs_map &attribs); void createAggregate(attribs_map &attribs); void createType(attribs_map &attribs); void createTable(attribs_map &attribs); void createView(attribs_map &attribs); void createRule(attribs_map &attribs); void createTrigger(attribs_map &attribs); void createIndex(attribs_map &attribs); void createConstraint(attribs_map &attribs); void createPolicy(attribs_map &attribs); void createPermission(attribs_map &attribs); void createEventTrigger(attribs_map &attribs); void createForeignDataWrapper(attribs_map &attribs); void createForeignServer(attribs_map &attribs); void createUserMapping(attribs_map &attribs); void createForeignTable(attribs_map &attribs); void __createTableInheritances(void); void createTableInheritances(void); void createTablePartitionings(void); void destroyDetachedColumns(void); /*! \brief Create the columns of the table represented by the passed attributes. * The inh_cols is used to hold the id of inherited columns to be managed later */ void createColumns(attribs_map &attribs, vector &inh_cols); //! \brief Tries to assign imported sequences that are related to nextval() calls used in columns default values void assignSequencesToColumns(void); /*! \brief Retrieve the schema qualified name for the specified object oid. If the oid represents a function or operator the signature can be retrieved instead by using the boolean parameter */ QString getObjectName(const QString &oid, bool signature_form=false); //! \brief Get the names for the objects oids inside the oid vector. QStringList getObjectNames(const QString &oid_vect, bool signature_form=false); /*! \brief Returns the column name represented by the parent table's oid and column id. If the boolean parameter is true then the table name is prepend to the column name */ QString getColumnName(const QString &tab_oid_str, const QString &col_id, bool prepend_tab_name=false); /*! \brief Returns the list of columns names translated from the id vector. This method works the same way of getColumnName() but returns a list instead of single result */ QStringList getColumnNames(const QString &tab_oid_str, const QString &col_id_vect, bool prepend_tab_name=false); /*! \brief Returns the name for the type represented by a oid. If the boolean parameter is true then the method will return the xml defintion for the type instead of the name */ QString getType(const QString &oid, bool generate_xml, attribs_map extra_attribs=attribs_map()); //! \brief Returns the type names or xml code for the specified oid vector QStringList getTypes(const QString &oid_vect, bool generate_xml); /*! \brief Returns the xml definition for the specified oid. If the boolean param 'use_signature' is true then the method will return the xml definition with signature attribute instead of name. If the param 'recursive_dep_res' is true the method will create a dependency if it's attributes exists but it doesn't exists on the model yet (note: this is different from auto_resolve_deps attribute) */ QString getDependencyObject(const QString &oid, ObjectType dep_type, bool use_signature=false, bool recursive_dep_res=true, bool generate_xml=true, attribs_map extra_attribs=attribs_map()); //! \brief Returns the xml defintion for the object's comment QString getComment(attribs_map &attribs); /*! \brief Loads the xml parser buffer with the xml schema file relative to the object type using the specified set of attributes */ void loadObjectXML(ObjectType obj_type, attribs_map &attribs); //! \brief Clears the vectors and maps used in the import process void resetImportParameters(void); //! \brief Return a string containing all attributes and their values in a formatted way QString dumpObjectAttributes(attribs_map &attribs); public: DatabaseImportHelper(QObject *parent = nullptr); //! \brief Set the connection used to access the PostgreSQL server void setConnection(Connection &conn); /*! \brief Closes all connections opened by this object including the catalog connection. Once this method is called the user must call setConnection() again or the import will fail */ void closeConnection(void); //! \brief Set the current database to work on void setCurrentDatabase(const QString &dbname); //! \brief Defines the selected object to be imported. This method always expect filled maps. Hint: use the method Catalog::getObjectOIDs() void setSelectedOIDs(DatabaseModel *db_model, const map> &obj_oids, const map> &col_oids); //! \brief Configures the import parameters void setImportOptions(bool import_sys_objs, bool import_ext_objs, bool auto_resolve_deps, bool ignore_errors, bool debug_mode, bool rand_rel_colors, bool update_fk_rels); //! \brief Returns the last system OID value for the current database unsigned getLastSystemOID(void); //! \brief Returns the current database in which the helper is working on QString getCurrentDatabase(void); //! \brief Returns a copy of the current catalog instance being used Catalog getCatalog(void); /*! \brief Returns an attribute map for the specified object type. The parameters "schema" and "table" must be used only when retrieving table children objects. The returned map contains only a key and a value, which are, respectively, the OID and object name. \note: The database used as reference is the same as the currently connection. So, if the user want a different database it must call Connection::switchToDatabase() method before assign the connection to this class. */ attribs_map getObjects(ObjectType obj_type, const QString &schema=QString(), const QString &table=QString(), attribs_map extra_attribs=attribs_map()); /*! \brief Retuns a vector of attribute maps that contains the name, OID and object type of each retrieved object. This method receives a list of object types to be retrieved and the catalog query is constructed and joint through UNION operator resulting in a result set contains all specified object types. This is the recommended method to use if you intend to retrive several objects names and oids of different kinds using the same query. \note: The database used as reference is the same as the currently connection. So, if the user want a different database it must call Connection::switchToDatabase() method before assign the connection to this class. */ vector getObjects(vector obj_type, const QString &schema=QString(), const QString &table=QString(), attribs_map extra_attribs=attribs_map()); void retrieveSystemObjects(void); void retrieveUserObjects(void); void retrieveTableColumns(const QString &sch_name, const QString &tab_name, vector col_ids={}); void createObjects(void); void createConstraints(void); void createPermissions(void); void swapSequencesTablesIds(void); void updateFKRelationships(void); signals: //! \brief This singal is emitted whenever the export progress changes void s_progressUpdated(int progress, QString msg, ObjectType obj_type=ObjectType::BaseObject); //! \brief This signal is emited when the import has finished void s_importFinished(Exception e=Exception()); //! \brief This signal is emited when the import has been cancelled void s_importCanceled(void); //! \brief This signal is emited when the import has encountered a critical error (only in thread mode) void s_importAborted(Exception e); protected slots: void cancelImport(void); public slots: void importDatabase(void); friend class DatabaseImportForm; friend class ModelDatabaseDiffForm; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/databasewidget.cpp000066400000000000000000000136401360462764600231270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "databasewidget.h" DatabaseWidget::DatabaseWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Database) { try { QStringList loc_list, encodings; QFrame *frame=nullptr; QGridLayout *grid=nullptr; Ui_DatabaseWidget::setupUi(this); configureFormLayout(database_grid, ObjectType::Database); def_schema_sel=new ObjectSelectorWidget(ObjectType::Schema, true, this); def_collation_sel=new ObjectSelectorWidget(ObjectType::Collation, true, this); def_owner_sel=new ObjectSelectorWidget(ObjectType::Role, true, this); def_tablespace_sel=new ObjectSelectorWidget(ObjectType::Tablespace, true, this); frame=generateInformationFrame(trUtf8("The fields LC_COLLATE and LC_CTYPE have pre-configured values based upon the running system. You can freely modify those values if you intend to export the model to another host.")); grid=dynamic_cast(attributes_twg->widget(0)->layout()); grid->addItem(new QSpacerItem(10,1,QSizePolicy::Fixed,QSizePolicy::Expanding), grid->count()+1, 0); grid->addWidget(frame, grid->count()+1, 0, 1, 0); frame=generateInformationFrame(trUtf8("Use the above fields to specify the default attributes assigned to new objects created on the database model. Leaving a field empty will cause PostgreSQL to use the default values when exporting the model.")); grid=dynamic_cast(attributes_twg->widget(1)->layout()); grid->addWidget(def_collation_sel, 0, 1); grid->addWidget(def_schema_sel, 1, 1); grid->addWidget(def_owner_sel, 2, 1); grid->addWidget(def_tablespace_sel, 3, 1); grid->addItem(new QSpacerItem(10,1,QSizePolicy::Fixed,QSizePolicy::Expanding), grid->count()+1, 0); grid->addWidget(frame, grid->count()+1, 0, 1, 0); frame->setParent(attributes_twg->widget(1)); //Configures the encoding combobox EncodingType::getTypes(encodings); encodings.push_front(trUtf8("Default")); encoding_cmb->addItems(encodings); //Configures the localizations combobox for(int i=QLocale::C; i <= QLocale::Chewa; i++) { for(int i1=QLocale::Afghanistan; i1 <= QLocale::Zimbabwe; i1++) loc_list.append(QLocale(static_cast(i),static_cast(i1)).name()); } loc_list.removeDuplicates(); loc_list.sort(); loc_list.push_front(trUtf8("Default")); lccollate_cmb->addItems(loc_list); lcctype_cmb->addItems(loc_list); setMinimumSize(560, 380); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DatabaseWidget::setAttributes(DatabaseModel *model) { if(model) { int idx; connlim_sb->setValue(model->getConnectionLimit()); templatedb_edt->setText(model->getTemplateDB()); author_edt->setText(model->getAuthor()); idx=encoding_cmb->findText(~model->getEncoding()); if(idx < 0) idx=0; encoding_cmb->setCurrentIndex(idx); if(!model->getLocalization(Collation::LcCollate).isEmpty()) lccollate_cmb->setCurrentText(model->getLocalization(Collation::LcCollate)); if(!model->getLocalization(Collation::LcCtype).isEmpty()) lcctype_cmb->setCurrentText(model->getLocalization(Collation::LcCtype)); def_schema_sel->setModel(model); def_schema_sel->setSelectedObject(model->getDefaultObject(ObjectType::Schema)); def_collation_sel->setModel(model); def_collation_sel->setSelectedObject(model->getDefaultObject(ObjectType::Collation)); def_owner_sel->setModel(model); def_owner_sel->setSelectedObject(model->getDefaultObject(ObjectType::Role)); def_tablespace_sel->setModel(model); def_tablespace_sel->setSelectedObject(model->getDefaultObject(ObjectType::Tablespace)); allow_conn_chk->setChecked(model->isAllowConnections()); is_template_chk->setChecked(model->isTemplate()); BaseObjectWidget::setAttributes(model, model, nullptr); } } void DatabaseWidget::applyConfiguration(void) { try { //Apply the basic configurations BaseObjectWidget::applyConfiguration(); model->setAuthor(author_edt->text().toUtf8()); model->setTemplateDB(templatedb_edt->text()); model->setConnectionLimit(connlim_sb->value()); if(encoding_cmb->currentIndex() > 0) model->setEncoding(EncodingType(encoding_cmb->currentText())); else model->setEncoding(EncodingType(BaseType::Null)); if(lccollate_cmb->currentText()!=trUtf8("Default")) model->setLocalization(Collation::LcCollate, lccollate_cmb->currentText()); else model->setLocalization(Collation::LcCollate, QString()); if(lcctype_cmb->currentText()!=trUtf8("Default")) model->setLocalization(Collation::LcCtype, lcctype_cmb->currentText()); else model->setLocalization(Collation::LcCtype, QString()); model->setDefaultObject(def_schema_sel->getSelectedObject(), ObjectType::Schema); model->setDefaultObject(def_owner_sel->getSelectedObject(), ObjectType::Role); model->setDefaultObject(def_collation_sel->getSelectedObject(), ObjectType::Collation); model->setDefaultObject(def_tablespace_sel->getSelectedObject(), ObjectType::Tablespace); model->setIsTemplate(is_template_chk->isChecked()); model->setAllowConnections(allow_conn_chk->isChecked()); finishConfiguration(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/databasewidget.h000066400000000000000000000025001360462764600225650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DatabaseWidget \brief Implements the operations to create/edit database attributes via form. */ #ifndef DATABASE_WIDGET_H #define DATABASE_WIDGET_H #include "ui_databasewidget.h" #include "baseobjectwidget.h" class DatabaseWidget: public BaseObjectWidget, public Ui::DatabaseWidget { private: Q_OBJECT ObjectSelectorWidget *def_collation_sel, *def_schema_sel, *def_owner_sel, *def_tablespace_sel; public: DatabaseWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/datamanipulationform.cpp000066400000000000000000001442761360462764600244070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "datamanipulationform.h" #include "sqlexecutionwidget.h" #include "pgmodeleruins.h" #include "pgmodelerns.h" #include "plaintextitemdelegate.h" #include "baseform.h" #include "bulkdataeditwidget.h" #include "databaseexplorerwidget.h" #include "generalconfigwidget.h" const QColor DataManipulationForm::RowColors[3]={ QColor(QString("#C0FFC0")), QColor(QString("#FFFFC0")), QColor(QString("#FFC0C0")) }; constexpr unsigned DataManipulationForm::NoOperation; constexpr unsigned DataManipulationForm::OpInsert; constexpr unsigned DataManipulationForm::OpUpdate; constexpr unsigned DataManipulationForm::OpDelete; DataManipulationForm::DataManipulationForm(QWidget * parent, Qt::WindowFlags f): QDialog(parent, f) { QAction *act = nullptr; QToolButton *btn = nullptr; QFont fnt; setupUi(this); setWindowFlags(Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); for(auto &obj : bnts_parent_wgt->children()) { btn = dynamic_cast(obj); if(!btn) continue; fnt = btn->font(); fnt.setBold(true); btn->setFont(fnt); PgModelerUiNs::createDropShadow(btn); PgModelerUiNs::configureWidgetFont(btn, PgModelerUiNs::SmallFontFactor); } table_oid=0; PgModelerUiNs::configureWidgetFont(hint_lbl, PgModelerUiNs::MediumFontFactor); PgModelerUiNs::configureWidgetFont(warning_lbl, PgModelerUiNs::MediumFontFactor); filter_hl=new SyntaxHighlighter(filter_txt); filter_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); code_compl_wgt=new CodeCompletionWidget(filter_txt); code_compl_wgt->configureCompletion(nullptr, filter_hl); results_tbw->setItemDelegate(new PlainTextItemDelegate(this, false)); browse_tabs_tb->setMenu(&fks_menu); act = copy_menu.addAction(trUtf8("Copy as CSV")); act->setShortcut(QKeySequence("Ctrl+C")); connect(act, &QAction::triggered, [&](){ SQLExecutionWidget::copySelection(results_tbw, false, true); paste_tb->setEnabled(true); }); act = copy_menu.addAction(trUtf8("Copy as text")); act->setShortcut(QKeySequence("Ctrl+Shift+C")); connect(act, &QAction::triggered, [&](){ SQLExecutionWidget::copySelection(results_tbw, false, false); paste_tb->setEnabled(true); }); act = paste_menu.addAction(trUtf8("Paste as text")); act->setShortcut(QKeySequence("Ctrl+V")); connect(act, &QAction::triggered, [&](){ loadDataFromCsv(true, false); paste_tb->setEnabled(false); }); act = paste_menu.addAction(trUtf8("Paste as CSV")); act->setShortcut(QKeySequence("Ctrl+Shift+V")); connect(act, &QAction::triggered, [&](){ loadDataFromCsv(true, true); paste_tb->setEnabled(false); }); paste_tb->setMenu(&paste_menu); truncate_tb->setMenu(&truncate_menu); truncate_menu.addAction(QIcon(PgModelerUiNs::getIconPath("truncate")), trUtf8("Truncate"), this, SLOT(truncateTable()), QKeySequence("Ctrl+Del"))->setData(QVariant::fromValue(false)); truncate_menu.addAction(QIcon(PgModelerUiNs::getIconPath("trunccascade")), trUtf8("Truncate cascade"), this, SLOT(truncateTable()), QKeySequence("Ctrl+Shift+Del"))->setData(QVariant::fromValue(true)); copy_tb->setMenu(©_menu); refresh_tb->setToolTip(refresh_tb->toolTip() + QString(" (%1)").arg(refresh_tb->shortcut().toString())); save_tb->setToolTip(save_tb->toolTip() + QString(" (%1)").arg(save_tb->shortcut().toString())); paste_tb->setToolTip(paste_tb->toolTip() + QString(" (%1)").arg(paste_tb->shortcut().toString())); export_tb->setToolTip(export_tb->toolTip() + QString(" (%1)").arg(export_tb->shortcut().toString())); undo_tb->setToolTip(undo_tb->toolTip() + QString(" (%1)").arg(undo_tb->shortcut().toString())); add_tb->setToolTip(add_tb->toolTip() + QString(" (%1)").arg(add_tb->shortcut().toString())); delete_tb->setToolTip(delete_tb->toolTip() + QString(" (%1)").arg(delete_tb->shortcut().toString())); bulkedit_tb->setToolTip(bulkedit_tb->toolTip() + QString(" (%1)").arg(bulkedit_tb->shortcut().toString())); duplicate_tb->setToolTip(duplicate_tb->toolTip() + QString(" (%1)").arg(duplicate_tb->shortcut().toString())); csv_load_tb->setToolTip(csv_load_tb->toolTip() + QString(" (%1)").arg(csv_load_tb->shortcut().toString())); filter_tb->setToolTip(filter_tb->toolTip() + QString(" (%1)").arg(filter_tb->shortcut().toString())); new_window_tb->setToolTip(new_window_tb->toolTip() + QString(" (%1)").arg(new_window_tb->shortcut().toString())); clear_tb->setToolTip(clear_tb->toolTip() + QString(" (%1)").arg(clear_tb->shortcut().toString())); result_info_wgt->setVisible(false); //Forcing the splitter that handles the bottom widgets to resize its children to their minimum size h_splitter->setSizes({500, 250, 500}); filter_tbw->setVisible(false); csv_load_parent->setVisible(false); csv_load_wgt = new CsvLoadWidget(this, false); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(csv_load_wgt); layout->setContentsMargins(0,0,0,0); csv_load_parent->setLayout(layout); csv_load_parent->setMinimumSize(csv_load_wgt->minimumSize()); connect(columns_lst, &QListWidget::itemDoubleClicked, [&](QListWidgetItem *item){ if(item->checkState() == Qt::Checked) item->setCheckState(Qt::Unchecked); else item->setCheckState(Qt::Checked); toggleColumnDisplay(item); }); connect(select_all_tb, &QToolButton::clicked, [&](){ setColumnsCheckState(Qt::Checked); }); connect(clear_all_tb, &QToolButton::clicked, [&](){ setColumnsCheckState(Qt::Unchecked); }); connect(clear_tb, SIGNAL(clicked(bool)), this, SLOT(clearItemsText())); connect(columns_lst, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(toggleColumnDisplay(QListWidgetItem*))); connect(csv_load_tb, SIGNAL(toggled(bool)), csv_load_parent, SLOT(setVisible(bool))); connect(close_btn, SIGNAL(clicked()), this, SLOT(reject())); connect(schema_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(listTables())); connect(hide_views_chk, SIGNAL(toggled(bool)), this, SLOT(listTables())); connect(schema_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(disableControlButtons())); connect(table_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(disableControlButtons())); connect(table_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(listColumns())); connect(table_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(retrieveData())); connect(refresh_tb, SIGNAL(clicked()), this, SLOT(retrieveData())); connect(add_ord_col_tb, SIGNAL(clicked()), this, SLOT(addColumnToList())); connect(ord_columns_lst, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(removeColumnFromList())); connect(ord_columns_lst, SIGNAL(itemPressed(QListWidgetItem*)), this, SLOT(changeOrderMode(QListWidgetItem*))); connect(rem_ord_col_tb, SIGNAL(clicked()), this, SLOT(removeColumnFromList())); connect(clear_ord_cols_tb, SIGNAL(clicked()), this, SLOT(clearColumnList())); connect(results_tbw, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(markUpdateOnRow(QTableWidgetItem *))); connect(delete_tb, SIGNAL(clicked()), this, SLOT(markDeleteOnRows())); connect(add_tb, SIGNAL(clicked()), this, SLOT(addRow())); connect(duplicate_tb, SIGNAL(clicked()), this, SLOT(duplicateRows())); connect(undo_tb, SIGNAL(clicked()), this, SLOT(undoOperations())); connect(save_tb, SIGNAL(clicked()), this, SLOT(saveChanges())); connect(ord_columns_lst, SIGNAL(currentRowChanged(int)), this, SLOT(enableColumnControlButtons())); connect(move_down_tb, SIGNAL(clicked()), this, SLOT(swapColumns())); connect(move_up_tb, SIGNAL(clicked()), this, SLOT(swapColumns())); connect(filter_tb, SIGNAL(toggled(bool)), filter_tbw, SLOT(setVisible(bool))); connect(truncate_tb, SIGNAL(clicked(bool)), this, SLOT(truncateTable())); connect(new_window_tb, SIGNAL(clicked(bool)), this, SLOT(openNewWindow())); connect(bulkedit_tb, &QToolButton::clicked, [&](){ PgModelerUiNs::bulkDataEdit(results_tbw); }); connect(filter_tb, &QToolButton::toggled, [&](bool checked){ v_splitter->setVisible(checked); if(checked) filter_txt->setFocus(); }); //Using the QueuedConnection here to avoid the "edit: editing failed" when editing and navigating through items using tab key connect(results_tbw, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(insertRowOnTabPress(int,int,int,int)), Qt::QueuedConnection); connect(results_tbw, SIGNAL(itemPressed(QTableWidgetItem *)), this, SLOT(showPopupMenu())); connect(export_tb, &QToolButton::clicked, [&](){ SQLExecutionWidget::exportResults(results_tbw); }); connect(results_tbw, SIGNAL(itemSelectionChanged()), this, SLOT(enableRowControlButtons())); connect(csv_load_wgt, SIGNAL(s_csvFileLoaded()), this, SLOT(loadDataFromCsv())); } void DataManipulationForm::setAttributes(Connection conn, const QString curr_schema, const QString curr_table, const QString &filter) { try { QString db_name; tmpl_conn_params=conn.getConnectionParams(); db_name=QString("%1@%2:%3").arg(conn.getConnectionParam(Connection::ParamDbName)) .arg(conn.getConnectionParam(Connection::ParamServerIp).isEmpty() ? conn.getConnectionParam(Connection::ParamServerFqdn) : conn.getConnectionParam(Connection::ParamServerIp)) .arg(conn.getConnectionParam(Connection::ParamPort)); db_name_lbl->setText(db_name); db_name.remove(QRegExp("<(/)?(strong|em)>")); this->setWindowTitle(this->windowTitle() + QString(" - ") + db_name); schema_cmb->clear(); listObjects(schema_cmb, { ObjectType::Schema }); disableControlButtons(); schema_cmb->setCurrentText(curr_schema); if(!filter.isEmpty() && !curr_schema.isEmpty() && !curr_table.isEmpty()) { table_cmb->blockSignals(true); table_cmb->setCurrentText(curr_table); table_cmb->blockSignals(false); listColumns(); filter_txt->setPlainText(filter); retrieveData(); refresh_tb->setEnabled(true); } else table_cmb->setCurrentText(curr_table); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DataManipulationForm::reject(void) { GeneralConfigWidget::saveWidgetGeometry(this); QDialog::reject(); } void DataManipulationForm::clearItemsText(void) { for(auto &sel : results_tbw->selectedRanges()) { for(int row = sel.topRow(); row <= sel.bottomRow(); row++) { for(int col = sel.leftColumn(); col <= sel.rightColumn(); col++) results_tbw->item(row,col)->setText(""); } } } void DataManipulationForm::listTables(void) { table_cmb->clear(); csv_load_tb->setChecked(false); if(schema_cmb->currentIndex() > 0) { vector types = { ObjectType::Table, ObjectType::ForeignTable }; if(!hide_views_chk->isChecked()) types.push_back(ObjectType::View); listObjects(table_cmb, types, schema_cmb->currentText()); } table_lbl->setEnabled(table_cmb->count() > 0); table_cmb->setEnabled(table_cmb->count() > 0); result_info_wgt->setVisible(false); } void DataManipulationForm::listColumns(void) { Catalog catalog; Connection conn=Connection(tmpl_conn_params); try { resetAdvancedControls(); col_names.clear(); code_compl_wgt->clearCustomItems(); if(table_cmb->currentIndex() > 0) { vector cols; catalog.setConnection(conn); cols=catalog.getObjectsAttributes(ObjectType::Column, schema_cmb->currentText(), table_cmb->currentText()); for(auto &col : cols) { col_names.push_back(col[Attributes::Name]); code_compl_wgt->insertCustomItem(col[Attributes::Name], {}, QPixmap(PgModelerUiNs::getIconPath("column"))); } ord_column_cmb->addItems(col_names); } add_ord_col_tb->setEnabled(ord_column_cmb->count() > 0); filter_tb->setEnabled(ord_column_cmb->count() > 0); } catch(Exception &e) { catalog.closeConnection(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void DataManipulationForm::retrieveData(void) { if(table_cmb->currentIndex() <= 0) return; Messagebox msg_box; Catalog catalog; Connection conn_sql=Connection(tmpl_conn_params), conn_cat=Connection(tmpl_conn_params); try { if(!changed_rows.empty()) { msg_box.show(trUtf8("WARNING: There are some changed rows waiting the commit! Do you really want to discard them and retrieve the data now?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Rejected) return; } QString query=QString("SELECT * FROM \"%1\".\"%2\"").arg(schema_cmb->currentText()).arg(table_cmb->currentText()), prev_tab_name; ResultSet res; unsigned limit=limit_spb->value(); ObjectType obj_type = static_cast(table_cmb->currentData(Qt::UserRole).toUInt()); vector curr_hidden_cols; int col_cnt = results_tbw->horizontalHeader()->count(); prev_tab_name = curr_table_name; curr_table_name = QString("%1.%2").arg(schema_cmb->currentText()).arg(table_cmb->currentText()); /* Storing the current hidden columns to make them hidden again after retrive data * if the table is the same */ for(int idx = 0; prev_tab_name == curr_table_name && idx < col_cnt; idx++) { if(results_tbw->horizontalHeader()->isSectionHidden(idx)) curr_hidden_cols.push_back(idx); } //Building the where clause if(!filter_txt->toPlainText().trimmed().isEmpty()) query+=QString(" WHERE ") + filter_txt->toPlainText(); //Building the order by clause if(ord_columns_lst->count() > 0) { QStringList ord_cols, col; query+=QString("\n ORDER BY "); for(int idx=0; idx < ord_columns_lst->count(); idx++) { col=ord_columns_lst->item(idx)->text().split(" "); ord_cols.push_back(QString("\"") + col[0] + QString("\" ") + col[1]); } query+=ord_cols.join(QString(", ")); } //Building the limit clause if(limit > 0) query+=QString(" LIMIT %1").arg(limit); QApplication::setOverrideCursor(Qt::WaitCursor); catalog.setConnection(conn_cat); conn_sql.connect(); conn_sql.executeDMLCommand(query, res); retrievePKColumns(schema_cmb->currentText(), table_cmb->currentText()); retrieveFKColumns(schema_cmb->currentText(), table_cmb->currentText()); SQLExecutionWidget::fillResultsTable(catalog, res, results_tbw, true); export_tb->setEnabled(results_tbw->rowCount() > 0); result_info_wgt->setVisible(results_tbw->rowCount() > 0); result_info_lbl->setText(QString("[%1] ").arg(QTime::currentTime().toString(QString("hh:mm:ss.zzz"))) + trUtf8("Rows returned: %1   ").arg(results_tbw->rowCount()) + trUtf8("(Limit: %1)").arg(limit_spb->value()==0 ? trUtf8("none") : QString::number(limit_spb->value()))); //Reset the changed rows state clearChangedRows(); //If the table is empty automatically creates a new row if(results_tbw->rowCount()==0 && PhysicalTable::isPhysicalTable(obj_type)) addRow(); else results_tbw->setFocus(); if(PhysicalTable::isPhysicalTable(obj_type)) csv_load_tb->setEnabled(!col_names.isEmpty()); else { csv_load_tb->setEnabled(false); csv_load_tb->setChecked(false); } conn_sql.close(); catalog.closeConnection(); QApplication::restoreOverrideCursor(); paste_tb->setEnabled(!qApp->clipboard()->text().isEmpty() && PhysicalTable::isPhysicalTable(obj_type) && !col_names.isEmpty()); truncate_tb->setEnabled(obj_type == ObjectType::Table && res.getTupleCount() > 0 && !col_names.isEmpty()); code_compl_wgt->clearCustomItems(); code_compl_wgt->insertCustomItems(col_names, trUtf8("Column"), ObjectType::Column); columns_lst->clear(); QListWidgetItem *item = nullptr; for(auto &col : col_names) { columns_lst->addItem(col); item = columns_lst->item(columns_lst->count() - 1); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(Qt::Checked); item->setData(Qt::UserRole, item->checkState()); } //Restoring the visibily of the columns results_tbw->horizontalHeader()->blockSignals(true); col_cnt = results_tbw->horizontalHeader()->count(); for(int idx = 0; idx < col_cnt; idx++) results_tbw->horizontalHeader()->setSectionHidden(idx, false); for(auto &idx : curr_hidden_cols) { item = columns_lst->item(idx); item->setCheckState(Qt::Unchecked); item->setData(Qt::UserRole, item->checkState()); results_tbw->horizontalHeader()->setSectionHidden(idx, true); } if(!curr_hidden_cols.empty()) results_tbw->resizeRowsToContents(); results_tbw->horizontalHeader()->blockSignals(false); } catch(Exception &e) { QApplication::restoreOverrideCursor(); conn_sql.close(); catalog.closeConnection(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DataManipulationForm::disableControlButtons(void) { refresh_tb->setEnabled(schema_cmb->currentIndex() > 0 && table_cmb->currentIndex() > 0); results_tbw->setRowCount(0); results_tbw->setColumnCount(0); warning_frm->setVisible(false); hint_frm->setVisible(false); add_tb->setEnabled(false); duplicate_tb->setEnabled(false); export_tb->setEnabled(false); paste_tb->setEnabled(false); truncate_tb->setEnabled(false); csv_load_tb->setEnabled(false); csv_load_tb->setChecked(false); clearChangedRows(); } void DataManipulationForm::enableRowControlButtons(void) { QList sel_ranges=results_tbw->selectedRanges(); bool cols_selected, rows_selected; ObjectType obj_type = static_cast(table_cmb->currentData(Qt::UserRole).toUInt()); cols_selected = rows_selected = !sel_ranges.isEmpty(); for(auto &sel_rng : sel_ranges) { cols_selected &= (sel_rng.columnCount() == results_tbw->columnCount()); rows_selected &= (sel_rng.rowCount() == results_tbw->rowCount()); } delete_tb->setEnabled(cols_selected); duplicate_tb->setEnabled(cols_selected); copy_tb->setEnabled(sel_ranges.count() != 0); clear_tb->setEnabled(sel_ranges.count() != 0); paste_tb->setEnabled(!qApp->clipboard()->text().isEmpty() && PhysicalTable::isPhysicalTable(obj_type) && !col_names.isEmpty()); browse_tabs_tb->setEnabled((!fk_infos.empty() || !ref_fk_infos.empty()) && sel_ranges.count() == 1 && sel_ranges.at(0).rowCount() == 1); bulkedit_tb->setEnabled(sel_ranges.count() != 0); } void DataManipulationForm::resetAdvancedControls(void) { ord_column_cmb->clear(); ord_columns_lst->clear(); add_ord_col_tb->setEnabled(false); filter_txt->clear(); asc_rb->setChecked(true); clear_ord_cols_tb->setEnabled(false); } void DataManipulationForm::addColumnToList(void) { if(ord_column_cmb->count() > 0) { QString item_text; item_text=ord_column_cmb->currentText(); item_text+=(asc_rb->isChecked() ? QString(" ASC") : QString(" DESC")); ord_columns_lst->addItem(item_text); ord_column_cmb->removeItem(ord_column_cmb->currentIndex()); enableColumnControlButtons(); } } void DataManipulationForm::enableColumnControlButtons(void) { clear_ord_cols_tb->setEnabled(ord_columns_lst->count() > 0); add_ord_col_tb->setEnabled(ord_column_cmb->count() > 0); rem_ord_col_tb->setEnabled(ord_columns_lst->currentRow() >= 0); move_up_tb->setEnabled(ord_columns_lst->count() > 1 && ord_columns_lst->currentRow() > 0); move_down_tb->setEnabled(ord_columns_lst->count() > 1 && ord_columns_lst->currentRow() >= 0 && ord_columns_lst->currentRow() <= ord_columns_lst->count() - 2); } void DataManipulationForm::swapColumns(void) { int curr_idx=0, new_idx=0; QStringList items; curr_idx=new_idx=ord_columns_lst->currentRow(); if(sender()==move_up_tb) new_idx--; else new_idx++; for(int i=0; i < ord_columns_lst->count(); i++) items.push_back(ord_columns_lst->item(i)->text()); items.move(curr_idx, new_idx); ord_columns_lst->blockSignals(true); ord_columns_lst->clear(); ord_columns_lst->addItems(items); ord_columns_lst->blockSignals(false); ord_columns_lst->setCurrentRow(new_idx); } void DataManipulationForm::loadDataFromCsv(bool load_from_clipboard, bool force_csv_parsing) { QList rows; QStringList cols; int row_id = 0, col_id = 0; if(load_from_clipboard) { if(qApp->clipboard()->text().isEmpty()) return; QString csv_pattern="(%1)(.)*(%1)(;)"; QString separator="\t", delimiter="", text=qApp->clipboard()->text(); if(force_csv_parsing) { if(text.contains(QRegExp(csv_pattern.arg("\"")))) delimiter="\""; else if(text.contains(QRegExp(csv_pattern.arg("'")))) delimiter="'"; // If one of the patterns matched the buffer we configure the right delimiter for csv buffer if(!delimiter.isEmpty()) separator=";"; } rows = CsvLoadWidget::loadCsvFromBuffer(text, separator, delimiter, false, cols); } else { rows = csv_load_wgt->getCsvRows(); cols = csv_load_wgt->getCsvColumns(); } /* If there is only one empty row in the grid, this one will be removed prior the csv loading */ if(results_tbw->rowCount()==1) { bool is_empty=true; for(int col=0; col < results_tbw->columnCount(); col++) { if(!results_tbw->item(0, col)->text().isEmpty()) { is_empty=false; break; } } if(is_empty) removeNewRows({0}); } for(QStringList &values : rows) { addRow(); row_id=results_tbw->rowCount() - 1; for(int i = 0; i < values.count(); i++) { if(i > values.count()) break; if((!load_from_clipboard && csv_load_wgt->isColumnsInFirstRow()) || (load_from_clipboard && !cols.isEmpty())) { //First we need to get the index of the column by its name col_id=col_names.indexOf(cols[i]); //If a matching column is not found we add the value at the current position if(col_id < 0) col_id = i; if(col_id >= 0 && col_id < results_tbw->columnCount()) results_tbw->item(row_id, col_id)->setText(values.at(i)); } else if(i < results_tbw->columnCount()) { //Insert the value to the cell in order of appearance results_tbw->item(row_id, i)->setText(values.at(i)); } } } } void DataManipulationForm::removeColumnFromList(void) { if(qApp->mouseButtons()==Qt::NoButton || qApp->mouseButtons()==Qt::LeftButton) { QStringList items=col_names; int idx=0; ord_columns_lst->takeItem(ord_columns_lst->currentRow()); while(idx < ord_columns_lst->count()) items.removeOne(ord_columns_lst->item(idx++)->text()); ord_column_cmb->clear(); ord_column_cmb->addItems(items); enableColumnControlButtons(); } } void DataManipulationForm::clearColumnList(void) { ord_column_cmb->clear(); ord_column_cmb->addItems(col_names); ord_columns_lst->clear(); clear_ord_cols_tb->setEnabled(false); move_up_tb->setEnabled(false); move_down_tb->setEnabled(false); add_ord_col_tb->setEnabled(true); } void DataManipulationForm::changeOrderMode(QListWidgetItem *item) { if(qApp->mouseButtons()==Qt::RightButton) { QStringList texts=item->text().split(QString(" ")); if(texts.size() > 1) texts[1]=(texts[1]==QString("ASC") ? QString("DESC") : QString("ASC")); item->setText(texts[0] + QString(" ") + texts[1]); } } void DataManipulationForm::listObjects(QComboBox *combo, vector obj_types, const QString &schema) { Catalog catalog; Connection conn=Connection(tmpl_conn_params); try { attribs_map objects; QStringList items; int idx=0, count=0; QApplication::setOverrideCursor(Qt::WaitCursor); catalog.setConnection(conn); catalog.setFilter(Catalog::ListAllObjects); combo->blockSignals(true); combo->clear(); for(auto &obj_type : obj_types) { objects=catalog.getObjectsNames(obj_type, schema); for(auto &attr : objects) items.push_back(attr.second); items.sort(); combo->addItems(items); count+=items.size(); items.clear(); for(; idx < count; idx++) { combo->setItemIcon(idx, QPixmap(PgModelerUiNs::getIconPath(obj_type))); combo->setItemData(idx, enum_cast(obj_type)); } idx=count; } if(combo->count()==0) combo->insertItem(0, trUtf8("No objects found")); else combo->insertItem(0, trUtf8("Found %1 object(s)").arg(combo->count())); combo->setCurrentIndex(0); combo->blockSignals(false); catalog.closeConnection(); QApplication::restoreOverrideCursor(); } catch(Exception &e) { catalog.closeConnection(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DataManipulationForm::retrievePKColumns(const QString &schema, const QString &table) { Catalog catalog; Connection conn=Connection(tmpl_conn_params); try { vector pks, columns; ObjectType obj_type=static_cast(table_cmb->currentData().toUInt()); table_oid = 0; if(obj_type==ObjectType::View) { warning_frm->setVisible(true); warning_lbl->setText(trUtf8("Views can't have their data handled through this grid, this way, all operations are disabled.")); } else { catalog.setConnection(conn); //Retrieving the constraints from catalog using a custom filter to select only primary keys (contype=p) pks=catalog.getObjectsAttributes(ObjectType::Constraint, schema, table, {}, {{Attributes::CustomFilter, QString("contype='p'")}}); warning_frm->setVisible(pks.empty()); if(pks.empty()) warning_lbl->setText(trUtf8("The selected table doesn't owns a primary key! Updates and deletes will be performed by considering all columns as primary key. WARNING: those operations can affect more than one row.")); else table_oid = pks[0][Attributes::Table].toUInt(); } hint_frm->setVisible(PhysicalTable::isPhysicalTable(obj_type)); add_tb->setEnabled(PhysicalTable::isPhysicalTable(obj_type) && !col_names.empty()); pk_col_names.clear(); if(!pks.empty()) { QStringList col_str_ids=Catalog::parseArrayValues(pks[0][Attributes::Columns]); vector col_ids; for(QString id : col_str_ids) col_ids.push_back(id.toUInt()); columns=catalog.getObjectsAttributes(ObjectType::Column, schema, table, col_ids); for(auto &col : columns) pk_col_names.push_back(col[Attributes::Name]); } catalog.closeConnection(); //For tables, even if there is no pk the user can manipulate data if(PhysicalTable::isPhysicalTable(obj_type)) results_tbw->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::AnyKeyPressed); else results_tbw->setEditTriggers(QAbstractItemView::NoEditTriggers); } catch(Exception &e) { catalog.closeConnection(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DataManipulationForm::retrieveFKColumns(const QString &schema, const QString &table) { Catalog catalog; Connection conn=Connection(tmpl_conn_params); try { QAction *action = nullptr; vector fks, ref_fks; ObjectType obj_type=static_cast(table_cmb->currentData().toUInt()); QString fk_name; fks_menu.clear(); ref_fk_infos.clear(); fk_infos.clear(); if(obj_type==ObjectType::View) return; catalog.setConnection(conn); //Retrieving the constraints from catalog using a custom filter to select only foreign keys (contype=f) fks=catalog.getObjectsAttributes(ObjectType::Constraint, schema, table, {}, {{Attributes::CustomFilter, QString("contype='f'")}}); ref_fks=catalog.getObjectsAttributes(ObjectType::Constraint, QString(), QString(), {}, {{Attributes::CustomFilter, QString("contype='f' AND cs.confrelid=%1").arg(table_oid)}}); if(!fks.empty() || !ref_fks.empty()) { vector col_ids; QMenu *submenu = nullptr; attribs_map aux_table, aux_schema; QStringList name_list; submenu = new QMenu(this); fks_menu.addAction(QPixmap(PgModelerUiNs::getIconPath("referenced")), trUtf8("Referenced tables"))->setMenu(submenu); if(fks.empty()) submenu->addAction(trUtf8("(none)"))->setEnabled(false); for(auto &fk : fks) { aux_table = catalog.getObjectAttributes(ObjectType::Table, fk[Attributes::RefTable].toUInt()); aux_schema = catalog.getObjectAttributes(ObjectType::Schema, aux_table[Attributes::Schema].toUInt()); fk_name = QString("%1.%2.%3") .arg(aux_schema[Attributes::Name]) .arg(aux_table[Attributes::Name]) .arg(fk[Attributes::Name]); //Store the referenced schema and table names fk_infos[fk_name][Attributes::RefTable] = aux_table[Attributes::Name]; fk_infos[fk_name][Attributes::Schema] = aux_schema[Attributes::Name]; action = submenu->addAction(QPixmap(PgModelerUiNs::getIconPath("table")), QString("%1.%2 (%3)").arg(aux_schema[Attributes::Name]) .arg(aux_table[Attributes::Name]) .arg(fk[Attributes::Name]), this, SLOT(browseReferencedTable())); action->setData(fk_name); col_ids.clear(); name_list.clear(); //Storing the source columns in a string for(QString id : Catalog::parseArrayValues(fk[Attributes::SrcColumns])) col_ids.push_back(id.toUInt()); for(auto &col : catalog.getObjectsAttributes(ObjectType::Column, schema, table, col_ids)) name_list.push_back(BaseObject::formatName(col[Attributes::Name])); fk_infos[fk_name][Attributes::SrcColumns] = name_list.join(Table::DataSeparator); col_ids.clear(); name_list.clear(); //Storing the referenced columns in a string for(QString id : Catalog::parseArrayValues(fk[Attributes::DstColumns])) col_ids.push_back(id.toUInt()); for(auto &col : catalog.getObjectsAttributes(ObjectType::Column, aux_schema[Attributes::Name], aux_table[Attributes::Name], col_ids)) name_list.push_back(BaseObject::formatName(col[Attributes::Name])); fk_infos[fk_name][Attributes::DstColumns] = name_list.join(Table::DataSeparator); } submenu = new QMenu(this); fks_menu.addAction(QPixmap(PgModelerUiNs::getIconPath("referrer")), trUtf8("Referrer tables"))->setMenu(submenu); if(ref_fks.empty()) submenu->addAction(trUtf8("(none)"))->setEnabled(false); for(auto &fk : ref_fks) { col_ids.clear(); name_list.clear(); aux_table = catalog.getObjectAttributes(ObjectType::Table, fk[Attributes::Table].toUInt()); aux_schema = catalog.getObjectAttributes(ObjectType::Schema, aux_table[Attributes::Schema].toUInt()); fk_name = QString("%1.%2.%3") .arg(aux_schema[Attributes::Name]) .arg(aux_table[Attributes::Name]) .arg(fk[Attributes::Name]); //Storing the source columns in a string for(QString id : Catalog::parseArrayValues(fk[Attributes::SrcColumns])) col_ids.push_back(id.toUInt()); for(auto &col : catalog.getObjectsAttributes(ObjectType::Column, aux_schema[Attributes::Name], aux_table[Attributes::Name], col_ids)) name_list.push_back(BaseObject::formatName(col[Attributes::Name])); action = submenu->addAction(QPixmap(PgModelerUiNs::getIconPath("table")), QString("%1.%2 (%3)").arg(aux_schema[Attributes::Name]) .arg(aux_table[Attributes::Name]) .arg(fk[Attributes::Name]), this, SLOT(browseReferrerTable())); action->setData(fk_name); ref_fk_infos[fk_name][Attributes::SrcColumns] = name_list.join(Table::DataSeparator); ref_fk_infos[fk_name][Attributes::Table] = aux_table[Attributes::Name]; ref_fk_infos[fk_name][Attributes::Schema] = aux_schema[Attributes::Name]; } } catalog.closeConnection(); } catch(Exception &e) { catalog.closeConnection(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DataManipulationForm::markOperationOnRow(unsigned operation, int row) { if(row < results_tbw->rowCount() && (operation==NoOperation || results_tbw->verticalHeaderItem(row)->data(Qt::UserRole)!=OpInsert)) { QTableWidgetItem *item=nullptr, *header_item=results_tbw->verticalHeaderItem(row); QString tooltip=trUtf8("This row is marked to be %1"); QFont fnt=results_tbw->font(); int marked_cols=0; if(operation==OpDelete) tooltip=tooltip.arg(trUtf8("deleted")); else if(operation==OpUpdate) tooltip=tooltip.arg(trUtf8("updated")); else if(operation==OpInsert) tooltip=tooltip.arg(trUtf8("inserted")); else tooltip.clear(); results_tbw->blockSignals(true); for(int col=0; col < results_tbw->columnCount(); col++) { item=results_tbw->item(row, col); if(results_tbw->horizontalHeaderItem(col)->data(Qt::UserRole)!=QString("bytea")) { item->setToolTip(tooltip); //Restore the item's font and text when the operation is delete or none if(operation==NoOperation || operation==OpDelete) { item->setFont(fnt); item->setText(item->data(Qt::UserRole).toString()); } if(operation==NoOperation) //Restore the item's background item->setBackground(prev_row_colors[row]); else { //Saves the item's background if it isn't already marked if(header_item->data(Qt::UserRole)!=OpDelete && header_item->data(Qt::UserRole)!=OpUpdate) prev_row_colors[row]=item->background(); //Changes the item's background according to the operation item->setBackground(RowColors[operation - 1]); } marked_cols++; } } if(marked_cols > 0) { auto itr=std::find(changed_rows.begin(), changed_rows.end(), row); if(operation==NoOperation && itr!=changed_rows.end()) { changed_rows.erase(std::find(changed_rows.begin(), changed_rows.end(), row)); prev_row_colors.erase(row); } else if(operation!=NoOperation && itr==changed_rows.end()) changed_rows.push_back(row); header_item->setData(Qt::UserRole, operation); undo_tb->setEnabled(!changed_rows.empty()); save_tb->setEnabled(!changed_rows.empty()); std::sort(changed_rows.begin(), changed_rows.end()); } results_tbw->blockSignals(false); } } void DataManipulationForm::markUpdateOnRow(QTableWidgetItem *item) { if(results_tbw->verticalHeaderItem(item->row())->data(Qt::UserRole)!=OpInsert) { bool items_changed=false; QTableWidgetItem *aux_item=nullptr; QFont fnt=item->font(); //Before mark the row to update it's needed to check if some item was changed for(int col=0; col < results_tbw->columnCount(); col++) { aux_item=results_tbw->item(item->row(), col); if(!items_changed && aux_item->text()!=aux_item->data(Qt::UserRole)) { items_changed=true; break; } } fnt.setBold(items_changed); item->setFont(fnt); markOperationOnRow((items_changed ? OpUpdate : NoOperation), item->row()); } } void DataManipulationForm::markDeleteOnRows(void) { QList sel_ranges=results_tbw->selectedRanges(); QTableWidgetItem *item=nullptr; vector ins_rows; for(auto &sel_rng : sel_ranges) { for(int row=sel_rng.topRow(); row <= sel_rng.bottomRow(); row++) { item=results_tbw->verticalHeaderItem(row); if(item->data(Qt::UserRole)==OpInsert) ins_rows.push_back(row); else markOperationOnRow(OpDelete, row); } } removeNewRows(ins_rows); results_tbw->clearSelection(); } void DataManipulationForm::addRow(bool focus_new_row) { int row=results_tbw->rowCount(); QTableWidgetItem *item=nullptr; results_tbw->blockSignals(true); results_tbw->insertRow(row); for(int col=0; col < results_tbw->columnCount(); col++) { item=new QTableWidgetItem; //bytea (binary data) columns can't be handled this way the new item is disabled if(results_tbw->horizontalHeaderItem(col)->data(Qt::UserRole)==QString("bytea")) { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); item->setText(trUtf8("[binary data]")); } else item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); results_tbw->setItem(row, col, item); } results_tbw->setVerticalHeaderItem(row, new QTableWidgetItem(QString::number(row + 1))); results_tbw->blockSignals(false); markOperationOnRow(OpInsert, row); item=results_tbw->item(row, 0); hint_frm->setVisible(true); if(focus_new_row) { results_tbw->setFocus(); results_tbw->setCurrentCell(row, 0, QItemSelectionModel::ClearAndSelect); results_tbw->editItem(item); } } void DataManipulationForm::duplicateRows(void) { QList sel_ranges=results_tbw->selectedRanges(); if(!sel_ranges.isEmpty()) { for(auto &sel_rng : sel_ranges) { for(int row=sel_rng.topRow(); row <= sel_rng.bottomRow(); row++) { addRow(false); for(int col=0; col < results_tbw->columnCount(); col++) { results_tbw->item(results_tbw->rowCount() - 1, col) ->setText(results_tbw->item(row, col)->text()); } } } results_tbw->setCurrentItem(results_tbw->item(results_tbw->rowCount() - 1, 0), QItemSelectionModel::ClearAndSelect); } } void DataManipulationForm::removeNewRows(vector ins_rows) { if(!ins_rows.empty()) { unsigned idx=0, cnt=ins_rows.size(); int row_idx=0; vector::reverse_iterator itr, itr_end; //Mark the rows as no-op to remove their indexes from changed rows set for(idx=0; idx < cnt; idx++) markOperationOnRow(NoOperation, ins_rows[idx]); //Remove the rows std::sort(ins_rows.begin(), ins_rows.end()); while(!ins_rows.empty()) { results_tbw->removeRow(ins_rows.back()); ins_rows.pop_back(); } //Reorganizing the changed rows vector to avoid row index out-of-bound errors row_idx=results_tbw->rowCount() - 1; itr=changed_rows.rbegin(); itr_end=changed_rows.rend(); while(itr!=itr_end) { if((*itr) > row_idx) { (*itr)=row_idx; results_tbw->verticalHeaderItem(row_idx)->setText(QString::number(row_idx + 1)); row_idx--; } else break; itr++; } } } void DataManipulationForm::clearChangedRows(void) { changed_rows.clear(); prev_row_colors.clear(); undo_tb->setEnabled(false); save_tb->setEnabled(false); } void DataManipulationForm::browseTable(const QString &fk_name, bool browse_ref_tab) { QString value, schema, table; DataManipulationForm *data_manip = new DataManipulationForm; Connection conn = Connection(tmpl_conn_params); QStringList filter, src_cols, ref_cols; if(browse_ref_tab) { src_cols = pk_col_names; ref_cols = ref_fk_infos[fk_name][Attributes::SrcColumns].split(Table::DataSeparator); schema = ref_fk_infos[fk_name][Attributes::Schema]; table = ref_fk_infos[fk_name][Attributes::Table]; } else { src_cols = fk_infos[fk_name][Attributes::SrcColumns].split(Table::DataSeparator); ref_cols = fk_infos[fk_name][Attributes::DstColumns].split(Table::DataSeparator); schema = fk_infos[fk_name][Attributes::Schema]; table = fk_infos[fk_name][Attributes::RefTable]; } for(QString col_name : src_cols) { value = results_tbw->item(results_tbw->currentRow(), col_names.indexOf(col_name))->text(); if(value.isEmpty()) filter.push_back(QString("%1 IS NULL").arg(ref_cols.front())); else filter.push_back(QString("%1 = '%2'").arg(ref_cols.front()).arg(value)); ref_cols.pop_front(); } data_manip->setWindowModality(Qt::NonModal); data_manip->setAttribute(Qt::WA_DeleteOnClose, true); data_manip->setAttributes(conn, schema, table, filter.join(QString("AND"))); PgModelerUiNs::resizeDialog(data_manip); data_manip->show(); } void DataManipulationForm::browseReferrerTable(void) { browseTable(qobject_cast(sender())->data().toString(), true); } void DataManipulationForm::browseReferencedTable(void) { browseTable(qobject_cast(sender())->data().toString(), false); } void DataManipulationForm::undoOperations(void) { QTableWidgetItem *item=nullptr; vector rows, ins_rows; QList sel_range=results_tbw->selectedRanges(); if(!sel_range.isEmpty()) { for(int row=sel_range[0].topRow(); row <= sel_range[0].bottomRow(); row++) { if(results_tbw->verticalHeaderItem(row)->data(Qt::UserRole).toUInt()==OpInsert) ins_rows.push_back(row); else rows.push_back(row); } } else { sel_range.clear(); rows=changed_rows; } //Marking rows to be deleted/updated as no-op for(auto &row : rows) { item=results_tbw->verticalHeaderItem(row); if(item->data(Qt::UserRole).toUInt()!=OpInsert) markOperationOnRow(NoOperation, row); } //If there is no selection, remove all new rows if(sel_range.isEmpty()) { if(results_tbw->rowCount() > 0 && results_tbw->verticalHeaderItem(results_tbw->rowCount()-1)->data(Qt::UserRole)==OpInsert) { do { results_tbw->removeRow(results_tbw->rowCount()-1); item=results_tbw->verticalHeaderItem(results_tbw->rowCount()-1); } while(item && item->data(Qt::UserRole)==OpInsert); } clearChangedRows(); } else //Removing just the selected new rows removeNewRows(ins_rows); results_tbw->clearSelection(); hint_frm->setVisible(results_tbw->rowCount() > 0); } void DataManipulationForm::insertRowOnTabPress(int curr_row, int curr_col, int prev_row, int prev_col) { if(qApp->mouseButtons()==Qt::NoButton && curr_row==0 && curr_col==0 && prev_row==results_tbw->rowCount()-1 && prev_col==results_tbw->columnCount()-1) addRow(); } void DataManipulationForm::saveChanges(void) { #ifdef DEMO_VERSION #warning "DEMO VERSION: data manipulation save feature disabled warning." Messagebox msg_box; msg_box.show(trUtf8("Warning"), trUtf8("You're running a demonstration version! The save feature of the data manipulation form is available only in the full version!"), Messagebox::AlertIcon, Messagebox::OkButton); #else int row=0; Connection conn=Connection(tmpl_conn_params); try { QString cmd; Messagebox msg_box; msg_box.show(trUtf8("WARNING: Once commited its not possible to undo the changes! Proceed with saving?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { //Forcing the cell editor to be closed by selecting an unexistent cell and clearing the selection results_tbw->setCurrentCell(-1,-1, QItemSelectionModel::Clear); conn.connect(); conn.executeDDLCommand(QString("START TRANSACTION")); for(unsigned idx=0; idx < changed_rows.size(); idx++) { row=changed_rows[idx]; cmd=getDMLCommand(row); conn.executeDDLCommand(cmd); } conn.executeDDLCommand(QString("COMMIT")); conn.close(); changed_rows.clear(); retrieveData(); undo_tb->setEnabled(false); save_tb->setEnabled(false); } } catch(Exception &e) { map op_names={{ OpDelete, trUtf8("delete") }, { OpUpdate, trUtf8("update") }, { OpInsert, trUtf8("insert") }}; QString tab_name=QString("%1.%2") .arg(schema_cmb->currentText()) .arg(table_cmb->currentText()); unsigned op_type=results_tbw->verticalHeaderItem(row)->data(Qt::UserRole).toUInt(); if(conn.isStablished()) { conn.executeDDLCommand(QString("ROLLBACK")); conn.close(); } results_tbw->selectRow(row); results_tbw->scrollToItem(results_tbw->item(row, 0)); throw Exception(Exception::getErrorMessage(ErrorCode::RowDataNotManipulated) .arg(op_names[op_type]).arg(tab_name).arg(row + 1).arg(e.getErrorMessage()), ErrorCode::RowDataNotManipulated,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } #endif } QString DataManipulationForm::getDMLCommand(int row) { if(row < 0 || row >= results_tbw->rowCount()) return(QString()); QString tab_name=QString("\"%1\".\"%2\"").arg(schema_cmb->currentText()).arg(table_cmb->currentText()), upd_cmd=QString("UPDATE %1 SET %2 WHERE %3"), del_cmd=QString("DELETE FROM %1 WHERE %2"), ins_cmd=QString("INSERT INTO %1(%2) VALUES (%3)"), fmt_cmd; QTableWidgetItem *item=nullptr; unsigned op_type=results_tbw->verticalHeaderItem(row)->data(Qt::UserRole).toUInt(); QStringList val_list, col_list, flt_list; QString col_name, value; QVariant data; if(op_type==OpDelete || op_type==OpUpdate) { if(pk_col_names.isEmpty()) { //Considering all columns as pk when the tables doesn't has one (except bytea columns) for(int col=0; col < results_tbw->columnCount(); col++) { if(results_tbw->horizontalHeaderItem(col)->data(Qt::UserRole)!=QString("bytea")) pk_col_names.push_back(results_tbw->horizontalHeaderItem(col)->text()); } } //Creating the where clause with original column's values for(QString pk_col : pk_col_names) { data = results_tbw->item(row, col_names.indexOf(pk_col))->data(Qt::UserRole); if(data.toString() == SQLExecutionWidget::ColumnNullValue) flt_list.push_back(QString("\"%1\" IS NULL").arg(pk_col)); else flt_list.push_back(QString("\"%1\"='%2'").arg(pk_col).arg(data.toString().replace("\'","''"))); } } if(op_type==OpDelete) { fmt_cmd=QString(del_cmd).arg(tab_name).arg(flt_list.join(QString(" AND "))); } else if(op_type==OpUpdate || op_type==OpInsert) { fmt_cmd=(op_type==OpUpdate ? upd_cmd : ins_cmd); for(int col=0; col < results_tbw->columnCount(); col++) { item=results_tbw->item(row, col); //bytea columns are ignored if(results_tbw->horizontalHeaderItem(col)->data(Qt::UserRole)!=QString("bytea")) { value=item->text(); col_name=results_tbw->horizontalHeaderItem(col)->text(); if(op_type==OpInsert || (op_type==OpUpdate && value!=item->data(Qt::UserRole))) { //Checking if the value is a malformed unescaped value, e.g., {value, value}, {value\} if((value.startsWith(PgModelerNs::UnescValueStart) && value.endsWith(QString("\\") + PgModelerNs::UnescValueEnd)) || (value.startsWith(PgModelerNs::UnescValueStart) && !value.endsWith(PgModelerNs::UnescValueEnd)) || (!value.startsWith(PgModelerNs::UnescValueStart) && !value.endsWith(QString("\\") + PgModelerNs::UnescValueEnd) && value.endsWith(PgModelerNs::UnescValueEnd))) throw Exception(Exception::getErrorMessage(ErrorCode::MalformedUnescapedValue) .arg(row + 1).arg(col_name), ErrorCode::MalformedUnescapedValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); col_list.push_back(QString("\"%1\"").arg(col_name)); //Empty values as considered as DEFAULT if(value.isEmpty()) { value=QString("DEFAULT"); } //Unescaped values will not be enclosed in quotes else if(value.startsWith(PgModelerNs::UnescValueStart) && value.endsWith(PgModelerNs::UnescValueEnd)) { value.remove(0,1); value.remove(value.length()-1, 1); } //Quoting value else { value.replace(QString("\\") + PgModelerNs::UnescValueStart, PgModelerNs::UnescValueStart); value.replace(QString("\\") + PgModelerNs::UnescValueEnd, PgModelerNs::UnescValueEnd); value.replace("\'","''"); value=QString("E'") + value + QString("'"); } if(op_type==OpInsert) val_list.push_back(value); else val_list.push_back(QString("\"%1\"=%2").arg(col_name).arg(value)); } } } if(col_list.isEmpty()) return(QString()); else { if(op_type==OpUpdate) fmt_cmd=fmt_cmd.arg(tab_name).arg(val_list.join(QString(", "))).arg(flt_list.join(QString(" AND "))); else fmt_cmd=fmt_cmd.arg(tab_name).arg(col_list.join(QString(", "))).arg(val_list.join(QString(", "))); } } return(fmt_cmd); } void DataManipulationForm::resizeEvent(QResizeEvent *event) { Qt::ToolButtonStyle style = Qt::ToolButtonIconOnly; QToolButton *btn = nullptr; if(event->size().height() > this->baseSize().height()) style = Qt::ToolButtonTextUnderIcon; if(refresh_tb->toolButtonStyle() != style) { for(auto obj : bnts_parent_wgt->children()) { btn = qobject_cast(obj); if(btn) btn->setToolButtonStyle(style); } } } void DataManipulationForm::closeEvent(QCloseEvent *) { GeneralConfigWidget::saveWidgetGeometry(this); } void DataManipulationForm::setColumnsCheckState(Qt::CheckState state) { QListWidgetItem *item = nullptr; results_tbw->blockSignals(true); for(int idx = 0; idx < columns_lst->count(); idx++) { item = columns_lst->item(idx); item->setCheckState(state); toggleColumnDisplay(item); } results_tbw->blockSignals(false); } void DataManipulationForm::truncateTable(void) { try { QAction *act = dynamic_cast(sender()); if(DatabaseExplorerWidget::truncateTable(schema_cmb->currentText(), table_cmb->currentText(), act->data().toBool(), Connection(tmpl_conn_params))) retrieveData(); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } void DataManipulationForm::toggleColumnDisplay(QListWidgetItem *item) { if(!item) return; if(item->checkState() != static_cast(item->data(Qt::UserRole).toInt())) { int idx = 0; bool hide = false; idx = col_names.indexOf(item->text()); hide = item->checkState() == Qt::Unchecked; results_tbw->horizontalHeader()->setSectionHidden(idx, hide); item->setCheckState(hide ? Qt::Unchecked : Qt::Checked); item->setData(Qt::UserRole, item->checkState()); results_tbw->resizeRowsToContents(); } } void DataManipulationForm::openNewWindow(void) { DataManipulationForm *data_manip = new DataManipulationForm; data_manip->setAttributes(tmpl_conn_params, QString()); data_manip->show(); } void DataManipulationForm::showPopupMenu(void) { if(QApplication::mouseButtons()==Qt::RightButton) { QMenu item_menu; QAction *act = nullptr; ObjectType obj_type=static_cast(table_cmb->currentData().toUInt()); act = item_menu.addAction(QIcon(PgModelerUiNs::getIconPath("copiar")), trUtf8("Copy items")); act->setMenu(©_menu); act = item_menu.addAction(QIcon(PgModelerUiNs::getIconPath("colar")), trUtf8("Pase items")); act->setMenu(&paste_menu); act->setEnabled(paste_tb->isEnabled()); act = item_menu.addAction(QIcon(PgModelerUiNs::getIconPath("limpar")), trUtf8("Clear items"), this, SLOT(clearItemsText())); act->setEnabled(!results_tbw->selectedRanges().isEmpty()); if(obj_type == ObjectType::Table) { item_menu.addSeparator(); act = item_menu.addAction(browse_tabs_tb->icon(), trUtf8("Browse tables")); act->setMenu(&fks_menu); act->setEnabled(browse_tabs_tb->isEnabled()); item_menu.addSeparator(); act = item_menu.addAction(duplicate_tb->icon(), trUtf8("Duplicate row(s)"), this, SLOT(duplicateRows()), duplicate_tb->shortcut()); act->setEnabled(duplicate_tb->isEnabled()); act = item_menu.addAction(delete_tb->icon(), trUtf8("Delete row(s)"), this, SLOT(markDeleteOnRows()), delete_tb->shortcut()); act->setEnabled(delete_tb->isEnabled()); act = item_menu.addAction(bulkedit_tb->icon(), trUtf8("Edit cell(s)"), bulkedit_tb, SLOT(click()), bulkedit_tb->shortcut()); act->setEnabled(bulkedit_tb->isEnabled()); } item_menu.exec(QCursor::pos()); } } pgmodeler-0.9.2/libpgmodeler_ui/src/datamanipulationform.h000066400000000000000000000165131360462764600240440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DataGridForm \brief Implements the operations to handle table's data */ #ifndef DATA_MANIPULATION_FORM_H #define DATA_MANIPULATION_FORM_H #include "ui_datamanipulationform.h" #include "catalog.h" #include "syntaxhighlighter.h" #include "codecompletionwidget.h" #include "csvloadwidget.h" class DataManipulationForm: public QDialog, public Ui::DataManipulationForm { private: Q_OBJECT //! \brief Constants used to mark the type of operation performed on rows static constexpr unsigned NoOperation=0, OpInsert=1, OpUpdate=2, OpDelete=3; //! \brief Default row colors for each operation type static const QColor RowColors[3]; CsvLoadWidget *csv_load_wgt; SyntaxHighlighter *filter_hl; CodeCompletionWidget *code_compl_wgt; QMenu fks_menu, copy_menu, truncate_menu, paste_menu; //! \brief Store the template connection params to be used by catalogs and command execution connections attribs_map tmpl_conn_params; //! \brief Current editing table columns names QStringList col_names, //! \brief Current editing table pk columns names pk_col_names; //! \brief Stores the current table's name (schema.table) QString curr_table_name; /*! \brief Stores the current opened table's oid. This attribute is filled only the table has an primary and it is used to retrieve all foreign keys that references the current table */ unsigned table_oid; //! \brief Stores the ids of changed rows. These ids are handled on saveChanges() method vector changed_rows; //! \brief Stores the previous color of the rows before being marked with some operation map prev_row_colors; //! \brief Stores the fk informations about referenced tables map fk_infos, //! \brief Stores the fk informations about referencing tables ref_fk_infos; //! \brief Fills a combobox with the names of objects retrieved from catalog void listObjects(QComboBox *combo, vector obj_types, const QString &schema=QString()); //! \brief Retrieve the primary key column ids for the specified table void retrievePKColumns(const QString &schema, const QString &table); /*! \brief Retrieve the foreign key columns info for the specified table. These data is used to browse referenced tables in the data that the selected line holds */ void retrieveFKColumns(const QString &schema, const QString &table); /*! \brief Mark the line as changed, changing its background color and applying the respective operation (see OP_??? constant) when user call saveChanged() */ void markOperationOnRow(unsigned operation, int row); //! \brief Generates a DML command for the row depending on the it's operation type QString getDMLCommand(int row); //! \brief Remove the rows marked as OP_INSERT which ids are specified on the parameter vector void removeNewRows(vector ins_rows); //! \brief Reset the state of changed rows, clearing all attributes used to control the modifications on them void clearChangedRows(void); //! brief Browse a referenced or referencing table by the provided foreign key name void browseTable(const QString &fk_name, bool browse_ref_tab); void resizeEvent(QResizeEvent *event); void closeEvent(QCloseEvent *); void setColumnsCheckState(Qt::CheckState state); public: DataManipulationForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); //! \brief Defines the connection and current schema and table to be handled, this method should be called before show the dialog void setAttributes(Connection conn, const QString curr_schema=QString("public"), const QString curr_table_name=QString(), const QString &filter=QString()); private slots: void reject(void); void clearItemsText(void); //! \brief List the tables based upon the current schema void listTables(void); //! \brief List the columns based upon the current table void listColumns(void); //! \brief Retrieve the data for the current table filtering the data as configured on the advanced tab void retrieveData(void); //! \brief Disable the buttons used to handle data void disableControlButtons(void); //! \brief Enables the delete/duplicate/copy buttons depending on the selected rows void enableRowControlButtons(void); //! \brief Reset the state of advaced tab's controls void resetAdvancedControls(void); //! \brief Enables/disables the buttons of the order by list depending on the state of it void enableColumnControlButtons(void); //! \brief Add a column to the "order by" list void addColumnToList(void); //! \brief Remove a column from the "order by" list void removeColumnFromList(void); //! \brief Clears the "order by" list void clearColumnList(void); //! \brief Toggles the sort mode between ASC and DESC when right clicking on a element at order by list void changeOrderMode(QListWidgetItem *item); //! \brief Mark the entire row in which the item resides void markUpdateOnRow(QTableWidgetItem *item); //! \brief Mark a seleciton of rows to be delete. New rows are automatically removed void markDeleteOnRows(void); //! \brief Add a new row on the grid with the first column with edition enabled void addRow(bool focus_new_row = true); //! \brief Duplicate the selected rows creating new ones with the same values as the selection void duplicateRows(void); //! \brief Undo the operation made on all rows or in a set of selected rows void undoOperations(void); //! \brief Insert a new row as the user press tab key on the last column at last row void insertRowOnTabPress(int curr_row, int curr_col, int prev_row, int prev_col); //! \brief Commit all changes made on the rows rolling back changes when some error is triggered void saveChanges(void); //! \brief Swap two rows on the order by list void swapColumns(void); //! \brief Add new rows to the grid based upon the CSV loaded void loadDataFromCsv(bool load_from_clipboard = false, bool force_csv_parsing = false); //! \brief Browse the referenced table data using the selected row in the results grid void browseReferencedTable(void); //! \brief Browse the referencing table data using the selected row in the results grid void browseReferrerTable(void); //! \brief Truncates the browsed table void truncateTable(void); //! \brief Display or hides a column when the related item is interacted in the column list at filter section void toggleColumnDisplay(QListWidgetItem *item); //! \brief Opens a new data manipulation windows void openNewWindow(void); //! \brief Shows the popup menu over the current selection void showPopupMenu(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/domainwidget.cpp000066400000000000000000000107071360462764600226330ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "domainwidget.h" #include "numberedtexteditor.h" DomainWidget::DomainWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Domain) { try { Ui_DomainWidget::setupUi(this); check_expr_hl=nullptr; check_expr_hl=new SyntaxHighlighter(check_expr_txt, false, true); check_expr_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); data_type=nullptr; data_type=new PgSQLTypeWidget(this); QGridLayout *grid = dynamic_cast(dom_attribs_tbw->widget(0)->layout()); grid->addWidget(data_type, 1, 0, 1, 2); grid->addItem(new QSpacerItem(10, 1, QSizePolicy::Fixed,QSizePolicy::Expanding), 2, 0, 1, 1); constr_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::DuplicateButton), true, this); constr_tab->setColumnCount(2); constr_tab->setHeaderLabel(trUtf8("Name"), 0); constr_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("constraint_ck")), 0); constr_tab->setHeaderLabel(trUtf8("Expression"), 1); constr_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("codigofonte")), 1); grid = dynamic_cast(dom_attribs_tbw->widget(1)->layout()); grid->addWidget(constr_tab, 2, 0, 1, 2); connect(constr_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleConstraint(int))); connect(constr_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleConstraint(int))); connect(constr_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editConstraint(int))); configureFormLayout(domain_grid, ObjectType::Domain); setRequiredField(data_type); configureTabOrder({ def_value_edt, not_null_chk, data_type, constr_name_edt, check_expr_txt }); setMinimumSize(580, 580); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void DomainWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Domain *domain) { PgSqlType type; BaseObjectWidget::setAttributes(model, op_list, domain, schema); if(domain) { type=domain->getType(); def_value_edt->setText(domain->getDefaultValue()); not_null_chk->setChecked(domain->isNotNull()); constr_tab->blockSignals(true); for(auto itr : domain->getCheckConstraints()) { constr_tab->addRow(); constr_tab->setCellText(itr.first, constr_tab->getRowCount() - 1, 0); constr_tab->setCellText(itr.second, constr_tab->getRowCount() - 1, 1); } constr_tab->clearSelection(); constr_tab->blockSignals(false); } data_type->setAttributes(type, model); } void DomainWidget::handleConstraint(int row) { if(!constr_name_edt->text().isEmpty() && !check_expr_txt->toPlainText().isEmpty()) { constr_tab->setCellText(constr_name_edt->text(), row, 0); constr_tab->setCellText(check_expr_txt->toPlainText(), row, 1); constr_name_edt->clear(); check_expr_txt->clear(); } else if(constr_tab->getCellText(row, 0).isEmpty()) constr_tab->removeRow(row); } void DomainWidget::editConstraint(int row) { constr_name_edt->setText(constr_tab->getCellText(row, 0)); check_expr_txt->setPlainText(constr_tab->getCellText(row, 1)); } void DomainWidget::applyConfiguration(void) { try { Domain *domain=nullptr; startConfiguration(); domain=dynamic_cast(this->object); domain->setType(data_type->getPgSQLType()); domain->setDefaultValue(def_value_edt->text()); domain->setNotNull(not_null_chk->isChecked()); domain->removeCheckConstraints(); for(unsigned row = 0; row < constr_tab->getRowCount(); row++) domain->addCheckConstraint(constr_tab->getCellText(row, 0), constr_tab->getCellText(row, 1)); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/domainwidget.h000066400000000000000000000027501360462764600222770ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DomainWidget \brief Implements the operations to create/edit domains via form. */ #ifndef DOMAIN_WIDGET_H #define DOMAIN_WIDGET_H #include "baseobjectwidget.h" #include "ui_domainwidget.h" #include "pgsqltypewidget.h" #include "objectstablewidget.h" class DomainWidget: public BaseObjectWidget, public Ui::DomainWidget { private: Q_OBJECT SyntaxHighlighter *check_expr_hl; PgSQLTypeWidget *data_type; ObjectsTableWidget *constr_tab; public: DomainWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Domain *domain); private slots: void handleConstraint(int row); void editConstraint(int row); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/donatewidget.cpp000066400000000000000000000030361360462764600226330ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "donatewidget.h" #include "globalattributes.h" #include #include #include "pgmodeleruins.h" DonateWidget::DonateWidget(QWidget *parent) : QWidget(parent) { setupUi(this); setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); QGraphicsDropShadowEffect * drop_shadow=new QGraphicsDropShadowEffect(this); drop_shadow->setOffset(5,5); drop_shadow->setBlurRadius(30); this->setGraphicsEffect(drop_shadow); connect(hide_tb, &QToolButton::clicked, [&](){ this->close(); emit s_visibilityChanged(false); }); connect(donate_tb, &QToolButton::clicked, [&](){ QDesktopServices::openUrl(QUrl(GlobalAttributes::PgModelerDonateURL)); this->close(); emit s_visibilityChanged(false); }); PgModelerUiNs::configureWidgetFont(title_lbl, PgModelerUiNs::BigFontFactor); this->adjustSize(); } pgmodeler-0.9.2/libpgmodeler_ui/src/donatewidget.h000066400000000000000000000022731360462764600223020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DonateWidget \brief Implements a basic dialog to ask for donations shown as a popup widget on main window. */ #ifndef DONATE_WIDGET_H #define DONATE_WIDGET_H #include #include #include "ui_donatewidget.h" class DonateWidget: public QWidget, public Ui::DonateWidget { private: Q_OBJECT public: DonateWidget(QWidget *parent = nullptr); signals: void s_visibilityChanged(bool value); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/elementstablewidget.cpp000066400000000000000000000133761360462764600242150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "elementstablewidget.h" #include "generalconfigwidget.h" ElementsTableWidget::ElementsTableWidget(QWidget *parent) : QWidget(parent) { try { handled_elem = nullptr; model = nullptr; parent_obj = nullptr; element_wgt = new ElementWidget; element_form.setMainWidget(element_wgt); element_form.setButtonConfiguration(); connect(&element_form, SIGNAL(accepted()), element_wgt, SLOT(applyConfiguration())); QVBoxLayout *vbox = new QVBoxLayout(this); elements_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton | ObjectsTableWidget::DuplicateButton), true, this); elements_tab->setColumnCount(7); elements_tab->setHeaderLabel(trUtf8("Element"), 0); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); elements_tab->setHeaderLabel(trUtf8("Type"), 1); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); elements_tab->setHeaderLabel(trUtf8("Operator"), 2); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("operator")),2); elements_tab->setHeaderLabel(trUtf8("Operator Class"), 3); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("opclass")),3); elements_tab->setHeaderLabel(trUtf8("Collation"), 4); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("collation")),4); elements_tab->setHeaderLabel(trUtf8("Sorting"), 5); elements_tab->setHeaderLabel(trUtf8("Nulls First"), 6); vbox->setContentsMargins(4,4,4,4); vbox->addWidget(elements_tab); connect(elements_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addElement(int))); connect(elements_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editElement(int))); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } ElementsTableWidget::~ElementsTableWidget(void) { if(handled_elem) delete(handled_elem); } void ElementsTableWidget::showElementData(Element *elem, int elem_idx) { if(!elem) return; if(elem->getColumn()) { elements_tab->setCellText(elem->getColumn()->getName(), elem_idx, 0); elements_tab->setCellText(elem->getColumn()->getTypeName(), elem_idx, 1); } else { elements_tab->setCellText(elem->getExpression(), elem_idx, 0); elements_tab->setCellText(trUtf8("Expression"), elem_idx, 1); } elements_tab->clearCellText(elem_idx, 2); if(elem->getOperator()) elements_tab->setCellText(elem->getOperator()->getSignature(true), elem_idx, 2); elements_tab->clearCellText(elem_idx, 3); if(elem->getOperatorClass()) elements_tab->setCellText(elem->getOperatorClass()->getName(true), elem_idx, 3); elements_tab->clearCellText(elem_idx, 4); if(elem->getCollation()) elements_tab->setCellText(elem->getCollation()->getName(true), elem_idx, 4); if(elem->isSortingEnabled()) { if(elem->getSortingAttribute(IndexElement::AscOrder)) elements_tab->setCellText(trUtf8("Ascending"), elem_idx, 5); else elements_tab->setCellText(trUtf8("Descending"), elem_idx, 5); if(elem->getSortingAttribute(IndexElement::NullsFirst)) elements_tab->setCellText(trUtf8("Yes"), elem_idx, 6); else elements_tab->setCellText(trUtf8("No"), elem_idx, 6); } else { elements_tab->clearCellText(elem_idx, 4); elements_tab->clearCellText(elem_idx, 5); } elements_tab->setRowData(copyElementData(elem), elem_idx); } QVariant ElementsTableWidget::copyElementData(Element *elem) { if(dynamic_cast(elem)) return(QVariant::fromValue(*dynamic_cast(elem))); if(dynamic_cast(elem)) return(QVariant::fromValue(*dynamic_cast(elem))); if(dynamic_cast(elem)) return(QVariant::fromValue(*dynamic_cast(elem))); return(QVariant()); } int ElementsTableWidget::openElementForm(Element *elem) { int res = 0; GeneralConfigWidget::restoreWidgetGeometry(&element_form, element_wgt->metaObject()->className()); element_wgt->setAttributes(model, parent_obj, elem); element_form.setWindowTitle(element_wgt->windowTitle()); res = element_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&element_form, element_wgt->metaObject()->className()); return(res); } void ElementsTableWidget::editElement(int elem_idx) { QVariant data = elements_tab->getRowData(elem_idx); Element *elem = nullptr; IndexElement idx_elem; ExcludeElement exc_elem; PartitionKey part_key; int res = 0; if(data.canConvert()) { idx_elem = data.value(); elem = &idx_elem; } if(data.canConvert()) { exc_elem = data.value(); elem = &exc_elem; } if(data.canConvert()) { part_key = data.value(); elem = &part_key; } res = openElementForm(elem); if(elem && res == QDialog::Accepted) showElementData(element_wgt->getElement(), elem_idx); } void ElementsTableWidget::addElement(int elem_idx) { if(openElementForm(handled_elem) == QDialog::Accepted) showElementData(element_wgt->getElement(), elem_idx); else elements_tab->removeRow(elem_idx); } pgmodeler-0.9.2/libpgmodeler_ui/src/elementstablewidget.h000066400000000000000000000101271360462764600236510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ElementsTableWidget \brief Implements the operations to create/edit constraints (exclude), indexes and partition keys elements via form storing them on a objects table (grid). */ #ifndef ELEMENTS_TABLES_WIDGET_H #define ELEMENTS_TABLES_WIDGET_H #include #include "objectstablewidget.h" #include "indexelement.h" #include "excludeelement.h" #include "partitionkey.h" #include "baseform.h" #include "elementwidget.h" /* Declaring the IndexElement and ExcludeElement class as a Qt metatype in order to permit * that instances of the class be used as data of QVariant and QMetaType */ #include Q_DECLARE_METATYPE(IndexElement) Q_DECLARE_METATYPE(ExcludeElement) Q_DECLARE_METATYPE(PartitionKey) class ElementsTableWidget: public QWidget { private: Q_OBJECT /*! \brief Store an instance of the element being handled (see setAttributes()) * This one is used to determine the settings of the element widget open when the user * wants to create new elements on the grid */ Element *handled_elem; ElementWidget *element_wgt; BaseForm element_form; DatabaseModel *model; BaseObject *parent_obj; //! \brief Table widget used to control the index elements ObjectsTableWidget *elements_tab; //! \brief Shows the element data on the elements table at the specified line void showElementData(Element *elem, int elem_idx); //! \brief Copies the provided element storing it on a QVariant according to its real type (class) QVariant copyElementData(Element *elem); //! \brief Opens the element editing form using the attributes of the provided element int openElementForm(Element *elem); public: ElementsTableWidget(QWidget *parent = nullptr); ~ElementsTableWidget(void); //! \brief Configures the grid based upon the template Class in use template void setAttributes(DatabaseModel *model, BaseObject *parent_obj) { if(handled_elem && !dynamic_cast(handled_elem)) { delete(handled_elem); handled_elem = nullptr; } if(!handled_elem) handled_elem = new Class; this->model = model; this->parent_obj = parent_obj; if(dynamic_cast(handled_elem)) elements_tab->setHeaderVisible(2, false); if(dynamic_cast(handled_elem)) elements_tab->setHeaderVisible(4, false); if(dynamic_cast(handled_elem)) { elements_tab->setHeaderVisible(2, false); elements_tab->setHeaderVisible(5, false); elements_tab->setHeaderVisible(6, false); } } //! \brief Fills the grid with the elements on the vector vector template void setElements(vector elems) { elements_tab->blockSignals(true); for(auto &elem : elems) { elements_tab->addRow(); showElementData(&elem, elements_tab->getRowCount() - 1); } elements_tab->clearSelection(); elements_tab->blockSignals(false); } //! \brief Fills the provided vector with the elements on the grid template void getElements(vector &elems) { if(elements_tab->getRowCount() > 0) { if(elements_tab->getRowData(0).canConvert()) { elems.clear(); for(unsigned i=0; i < elements_tab->getRowCount(); i++) elems.push_back(elements_tab->getRowData(i).value()); } } } private slots: void addElement(int elem_idx); void editElement(int elem_idx); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/elementwidget.cpp000066400000000000000000000215331360462764600230140ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "elementwidget.h" ElementWidget::ElementWidget(QWidget *parent) : QWidget(parent) { try { map > fields_map; warning_frame=nullptr; element = nullptr; setupUi(this); elem_expr_hl=new SyntaxHighlighter(elem_expr_txt, false, true); elem_expr_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); parent_obj=nullptr; op_class_sel=new ObjectSelectorWidget(ObjectType::OpClass, true, this); collation_sel=new ObjectSelectorWidget(ObjectType::Collation, true, this); operator_sel=new ObjectSelectorWidget(ObjectType::Operator, true, this); element_grid->addWidget(collation_sel, 3,1,1,2); element_grid->addWidget(op_class_sel, 4,1,1,2); element_grid->addWidget(operator_sel, 5,1,1,2); fields_map[BaseObjectWidget::generateVersionsInterval(BaseObjectWidget::AfterVersion, PgSqlVersions::PgSqlVersion91)].push_back(collation_lbl); warning_frame=BaseObjectWidget::generateVersionWarningFrame(fields_map); element_grid->addWidget(warning_frame, element_grid->count()+1, 0, 1, 3); warning_frame->setParent(this); connect(column_rb, SIGNAL(toggled(bool)), this, SLOT(selectElementObject(void))); connect(expression_rb, SIGNAL(toggled(bool)), this, SLOT(selectElementObject(void))); connect(sorting_chk, SIGNAL(toggled(bool)), ascending_rb, SLOT(setEnabled(bool))); connect(sorting_chk, SIGNAL(toggled(bool)), descending_rb, SLOT(setEnabled(bool))); connect(sorting_chk, SIGNAL(toggled(bool)), nulls_first_chk, SLOT(setEnabled(bool))); this->setEnabled(false); collation_sel->setVisible(false); collation_lbl->setVisible(false); operator_sel->setVisible(false); operator_lbl->setVisible(false); BaseObjectWidget::setRequiredField(operator_sel); BaseObjectWidget::setRequiredField(operator_lbl); setTabOrder(column_rb, column_cmb); setTabOrder(column_cmb, expression_rb); setTabOrder(expression_rb, elem_expr_txt); setTabOrder(elem_expr_txt, collation_sel); setTabOrder(collation_sel, collation_sel->rem_object_tb); setTabOrder(collation_sel->rem_object_tb, collation_sel->sel_object_tb); setTabOrder(collation_sel->sel_object_tb, op_class_sel); setTabOrder(op_class_sel, op_class_sel->rem_object_tb); setTabOrder(op_class_sel->rem_object_tb, op_class_sel->sel_object_tb); setTabOrder(op_class_sel->sel_object_tb, sorting_chk); setTabOrder(sorting_chk, ascending_rb); setTabOrder(ascending_rb, descending_rb); setTabOrder(descending_rb, nulls_first_chk); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ElementWidget::setAttributes(DatabaseModel *model, BaseObject *parent_obj, Element *elem) { if(!elem) this->setEnabled(false); else { IndexElement *idx_elem = dynamic_cast(elem); ExcludeElement *exc_elem = dynamic_cast(elem); PartitionKey *part_key = dynamic_cast(elem); Column *column = elem->getColumn(); setAttributes(model, parent_obj); if(idx_elem) setIndexElement(idx_elem); else if(exc_elem) setExcludeElement(exc_elem); else setPartitionKey(part_key); if(parent_obj->getObjectType() == ObjectType::Table && (column || (!column && elem->getExpression().isEmpty()))) { column_rb->setChecked(true); if(column) column_cmb->setCurrentIndex(column_cmb->findText(column->getName())); } else { expression_rb->setChecked(true); elem_expr_txt->setPlainText(elem->getExpression()); } if(elem->getSortingAttribute(IndexElement::AscOrder)) ascending_rb->setChecked(true); else descending_rb->setChecked(true); nulls_first_chk->setChecked(elem->getSortingAttribute(IndexElement::NullsFirst)); sorting_chk->setChecked(elem->isSortingEnabled()); op_class_sel->setSelectedObject(elem->getOperatorClass()); collation_sel->setSelectedObject(elem->getCollation()); operator_sel->setSelectedObject(elem->getOperator()); } } void ElementWidget::setAttributes(DatabaseModel *model, BaseObject *parent_obj) { if(!model || !parent_obj) { this->setEnabled(false); throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(parent_obj->getObjectType()!=ObjectType::Table && parent_obj->getObjectType()!=ObjectType::View && parent_obj->getObjectType()!=ObjectType::Relationship) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->setEnabled(true); this->parent_obj=parent_obj; op_class_sel->setModel(model); collation_sel->setModel(model); operator_sel->setModel(model); cols_combo_parent->setVisible(parent_obj->getObjectType() == ObjectType::Table); column_rb->setVisible(parent_obj->getObjectType() == ObjectType::Table); expression_rb->setChecked(parent_obj->getObjectType() == ObjectType::View); if(parent_obj->getObjectType() == ObjectType::Table) updateColumnsCombo(); } void ElementWidget::setIndexElement(IndexElement *elem) { createElement(elem); setWindowTitle(trUtf8("Index element properties")); collation_sel->setVisible(true); collation_lbl->setVisible(true); warning_frame->setVisible(true); } void ElementWidget::setExcludeElement(ExcludeElement *elem) { createElement(elem); setWindowTitle(trUtf8("Exclude element properties")); operator_sel->setVisible(true); operator_lbl->setVisible(true); warning_frame->setVisible(false); } void ElementWidget::setPartitionKey(PartitionKey *elem) { createElement(elem); setWindowTitle(trUtf8("Partition key properties")); collation_sel->setVisible(true); collation_lbl->setVisible(true); sorting_chk->setVisible(false); ascending_rb->setVisible(false); descending_rb->setVisible(false); nulls_first_chk->setVisible(false); warning_frame->setVisible(true); } Element *ElementWidget::getElement(void) { return(element); } void ElementWidget::applyConfiguration(void) { element->setSortingEnabled(sorting_chk->isChecked()); element->setSortingAttribute(IndexElement::NullsFirst, nulls_first_chk->isChecked()); element->setSortingAttribute(IndexElement::AscOrder, ascending_rb->isChecked()); element->setOperatorClass(dynamic_cast(op_class_sel->getSelectedObject())); element->setCollation(dynamic_cast(collation_sel->getSelectedObject())); element->setOperator(dynamic_cast(operator_sel->getSelectedObject())); if(expression_rb->isChecked()) element->setExpression(elem_expr_txt->toPlainText().toUtf8()); else element->setColumn(reinterpret_cast(column_cmb->itemData(column_cmb->currentIndex()).value())); } void ElementWidget::updateColumnsCombo(void) { Table *table = dynamic_cast
(parent_obj); Relationship *rel = dynamic_cast(parent_obj); Column *column=nullptr; unsigned i, col_count=0; try { column_cmb->clear(); column_cmb->setVisible(true); column_rb->setVisible(true); if(table) { col_count=table->getColumnCount(); for(i=0; i < col_count; i++) { column=table->getColumn(i); column_cmb->addItem(column->getName(), QVariant::fromValue(column)); } } else if(rel) { col_count=rel->getAttributeCount(); for(i=0; i < col_count; i++) { column=rel->getAttribute(i); column_cmb->addItem(column->getName(), QVariant::fromValue(column)); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ElementWidget::selectElementObject(void) { QObject *obj_sender=sender(); column_rb->blockSignals(true); expression_rb->blockSignals(true); if(obj_sender==column_rb) { elem_expr_txt->clear(); column_cmb->setEnabled(true); expression_rb->setChecked(false); column_rb->setChecked(true); elem_expr_txt->setEnabled(false); } else { column_cmb->setEnabled(false); column_rb->setChecked(false); expression_rb->setChecked(true); elem_expr_txt->setEnabled(true); } column_rb->blockSignals(false); expression_rb->blockSignals(false); } template void ElementWidget::createElement(Class *elem) { if(element && !dynamic_cast(element)) delete(element); if(!element) element = new Class; *element = *elem; } pgmodeler-0.9.2/libpgmodeler_ui/src/elementwidget.h000066400000000000000000000054171360462764600224640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ElementWidget \brief Implements the operations to create/edit constraints (exclude) and indexes elements, and partition keys via form. */ #ifndef ELEMENT_WIDGET_H #define ELEMENT_WIDGET_H #include #include "ui_elementwidget.h" #include "objectstablewidget.h" #include "objectselectorwidget.h" #include "partitionkey.h" class ElementWidget: public QWidget, public Ui::ElementWidget { private: Q_OBJECT QFrame *warning_frame; Element *element; //! \brief Parent object (table or relationship) from which the columns will be referenced on the elements BaseObject *parent_obj; //! \brief Syntax highlighter for element expression SyntaxHighlighter *elem_expr_hl; //! \brief Operator class selector ObjectSelectorWidget *op_class_sel, //! \brief Collation selector (only for index elements) *collation_sel, //! \brief Operator selector (only for exclude elements) *operator_sel; //! \brief Updates the column combobox with the existent columns on parent table void updateColumnsCombo(void); void setAttributes(DatabaseModel *model, BaseObject *parent_obj); //! \brief Enables the widget to handle index elements void setIndexElement(IndexElement *elem); //! \brief Enables the widget to handle exclude constraint elements void setExcludeElement(ExcludeElement *elem); //! \brief Enables the widget to handle partition key elements void setPartitionKey(PartitionKey *elem); //! \brief Allocates the handled element based upon the provided Class (should be child of Element) template void createElement(Class *elem); public: ElementWidget(QWidget *parent = nullptr); //! \brief Configures the widget to handle the element considering its type (IndexElement, ExcludeElement, PartitionKey) void setAttributes(DatabaseModel *model, BaseObject *parent_obj, Element *elem); //! \brief Returns the configured element Element *getElement(void); public slots: void applyConfiguration(void); private slots: void selectElementObject(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/eventtriggerwidget.cpp000066400000000000000000000113761360462764600240740ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "eventtriggerwidget.h" EventTriggerWidget::EventTriggerWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::EventTrigger) { map > fields_map; map > values_map; QFrame *frame=nullptr; Ui_EventTriggerWidget::setupUi(this); function_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); filter_tab=new ObjectsTableWidget(ObjectsTableWidget::AddButton | ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton | ObjectsTableWidget::RemoveButton | ObjectsTableWidget::RemoveAllButton | ObjectsTableWidget::MoveButtons, false, this); filter_tab->setColumnCount(1); filter_tab->setHeaderLabel(trUtf8("Tag command"), 0); eventtrigger_grid->addWidget(function_sel, 1, 1); filter_layout->addWidget(filter_tab); configureFormLayout(eventtrigger_grid, ObjectType::EventTrigger); setRequiredField(function_lbl); fields_map[BaseObjectWidget::generateVersionsInterval(BaseObjectWidget::AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(event_lbl); values_map[event_lbl].push_back(~EventTriggerType(EventTriggerType::TableRewrite)); frame=BaseObjectWidget::generateVersionWarningFrame(fields_map, &values_map); frame->setParent(this); eventtrigger_grid->addWidget(frame, eventtrigger_grid->count(), 0, 1, 2); configureTabOrder({ event_cmb, function_sel, tag_edt, filter_tab }); QStringList list; EventTriggerType::getTypes(list); event_cmb->addItems(list); connect(filter_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleTagValue(int))); connect(filter_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleTagValue(int))); connect(filter_tab, &ObjectsTableWidget::s_rowsRemoved, [&](){ filter_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, false); }); connect(filter_tab, &ObjectsTableWidget::s_rowEdited, [&](int row){ tag_edt->setText(filter_tab->getCellText(row, 0)); }); connect(tag_edt, &QLineEdit::textChanged, [&](){ filter_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, !tag_edt->text().isEmpty()); filter_tab->setButtonsEnabled(ObjectsTableWidget::UpdateButton, !tag_edt->text().isEmpty()); }); setMinimumSize(500, 440); } void EventTriggerWidget::setAttributes(DatabaseModel *model, OperationList *op_list, EventTrigger *event_trig) { BaseObjectWidget::setAttributes(model, op_list, event_trig); function_sel->setModel(model); if(event_trig) { event_cmb->setCurrentText(~event_trig->getEvent()); function_sel->setSelectedObject(event_trig->getFunction()); QStringList filter=event_trig->getFilter(Attributes::Tag.toUpper()); if(filter.isEmpty()) filter=event_trig->getFilter(Attributes::Tag); filter_tab->blockSignals(true); for(auto &flt : filter) { filter_tab->addRow(); filter_tab->setCellText(flt, filter_tab->getRowCount()-1, 0); } filter_tab->blockSignals(false); filter_tab->clearSelection(); } filter_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, false); } void EventTriggerWidget::applyConfiguration(void) { try { EventTrigger *event_trig=nullptr; startConfiguration(); event_trig=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); event_trig->setEvent(EventTriggerType(event_cmb->currentText())); event_trig->setFunction(dynamic_cast(function_sel->getSelectedObject())); event_trig->clearFilter(); for(unsigned row=0; row < filter_tab->getRowCount(); row++) event_trig->setFilter(Attributes::Tag.toUpper(), filter_tab->getCellText(row, 0)); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void EventTriggerWidget::handleTagValue(int row) { if(!tag_edt->text().isEmpty()) { filter_tab->setCellText(tag_edt->text().simplified(), row, 0); tag_edt->clear(); filter_tab->clearSelection(); filter_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, false); } else if(filter_tab->getCellText(row, 0).isEmpty()) filter_tab->removeRow(row); } pgmodeler-0.9.2/libpgmodeler_ui/src/eventtriggerwidget.h000066400000000000000000000026771360462764600235450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class EventTriggerWidget \brief Implements the operations to create/edit event triggers via form. */ #ifndef EVENT_TRIGGER_WIDGET_H #define EVENT_TRIGGER_WIDGET_H #include "baseobjectwidget.h" #include "objectstablewidget.h" #include "ui_eventtriggerwidget.h" class EventTriggerWidget: public BaseObjectWidget, public Ui::EventTriggerWidget { private: Q_OBJECT ObjectsTableWidget *filter_tab; ObjectSelectorWidget *function_sel; public: EventTriggerWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, EventTrigger *event_trig); public slots: void applyConfiguration(void); private slots: void handleTagValue(int row); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/extensionwidget.cpp000066400000000000000000000027061360462764600234000ustar00rootroot00000000000000#include "extensionwidget.h" ExtensionWidget::ExtensionWidget(QWidget * parent) : BaseObjectWidget(parent, ObjectType::Extension) { Ui_ExtensionWidget::setupUi(this); configureFormLayout(extension_grid, ObjectType::Extension); extension_grid->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding), extension_grid->count()+1, 0, 1, 0); configureTabOrder({ cur_ver_edt, old_ver_edt, handles_type_chk }); setMinimumSize(500, 180); } void ExtensionWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Extension *ext) { BaseObjectWidget::setAttributes(model, op_list, ext, schema); if(ext) { cur_ver_edt->setText(ext->getVersion(Extension::CurVersion)); old_ver_edt->setText(ext->getVersion(Extension::OldVersion)); handles_type_chk->setEnabled(false); handles_type_chk->setChecked(ext->handlesType()); } } void ExtensionWidget::applyConfiguration(void) { try { Extension *extension=nullptr; startConfiguration(); extension=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); extension->setHandlesType(handles_type_chk->isChecked()); extension->setVersion(Extension::CurVersion, cur_ver_edt->text()); extension->setVersion(Extension::OldVersion, old_ver_edt->text()); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/extensionwidget.h000066400000000000000000000024111360462764600230360ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SchemaWidget \brief Implements the operations to create/edit extensions via form. */ #ifndef EXTENSION_WIDGET_H #define EXTENSION_WIDGET_H #include "baseobjectwidget.h" #include "ui_extensionwidget.h" class ExtensionWidget: public BaseObjectWidget, public Ui::ExtensionWidget { private: Q_OBJECT public: ExtensionWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Extension *ext); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/findreplacewidget.cpp000066400000000000000000000104721360462764600236370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "findreplacewidget.h" FindReplaceWidget::FindReplaceWidget(QPlainTextEdit *txt_edit, QWidget *parent): QWidget(parent) { if(!txt_edit) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); setupUi(this); text_edt=txt_edit; next_tb->setToolTip(next_tb->toolTip() + QString(" (%1)").arg(next_tb->shortcut().toString())); previous_tb->setToolTip(previous_tb->toolTip() + QString(" (%1)").arg(previous_tb->shortcut().toString())); connect(replace_tb, SIGNAL(clicked()), this, SLOT(replaceText())); connect(replace_find_tb, SIGNAL(clicked()), this, SLOT(replaceFindText())); connect(replace_all_tb, SIGNAL(clicked()), this, SLOT(replaceAll())); connect(next_tb, &QToolButton::clicked, [&]() { findText(false, true); }); connect(previous_tb, &QToolButton::clicked, [&]() { findText(true, true); }); connect(find_edt, &QLineEdit::textChanged, [&]() { bool enable=!find_edt->text().isEmpty(); next_tb->setEnabled(enable); previous_tb->setEnabled(enable); replace_tb->setEnabled(enable); replace_all_tb->setEnabled(enable); replace_find_tb->setEnabled(enable); }); //Disabling the regular expression checkbox if the Qt version in use is lower than 5.3 #if (QT_VERSION < QT_VERSION_CHECK(5, 3, 0)) regexp_chk->setEnabled(false); regexp_chk->setChecked(false); regexp_chk->setVisible(false); #endif } void FindReplaceWidget::showEvent(QShowEvent *) { find_edt->setFocus(); replace_btns_parent->setVisible(!text_edt->isReadOnly()); replace_lbl->setVisible(!text_edt->isReadOnly()); replace_edt->setVisible(!text_edt->isReadOnly()); } void FindReplaceWidget::replaceText(void) { QTextCursor cursor=text_edt->textCursor(); if(cursor.hasSelection()) { cursor.removeSelectedText(); cursor.insertText(replace_edt->text()); } } void FindReplaceWidget::replaceAll(void) { QTextCursor orig_cursor, cursor=text_edt->textCursor(); orig_cursor=cursor; cursor.setPosition(0); text_edt->setTextCursor(cursor); while(findText(false, false)) text_edt->textCursor().insertText(replace_edt->text()); text_edt->setTextCursor(orig_cursor); } void FindReplaceWidget::replaceFindText(void) { if(text_edt->textCursor().hasSelection()) { replaceText(); findText(false, true); } } #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) bool FindReplaceWidget::findText(const QString &text, bool regexp, QTextDocument::FindFlags flags) #else bool FindReplaceWidget::findText(const QString &text, bool, QTextDocument::FindFlags flags) #endif { #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) if(regexp) return(text_edt->find(QRegExp(text, ((flags & QTextDocument::FindCaseSensitively)==QTextDocument::FindCaseSensitively ? Qt::CaseSensitive : Qt::CaseInsensitive)), flags)); else return(text_edt->find(text, flags)); #else #warning "Text find through regular expressions is available only in Qt 5.3 or above." return(text_edt->find(text, flags)); #endif } bool FindReplaceWidget::findText(bool backward, bool cyclic) { QTextDocument::FindFlags flags; QTextCursor cursor; bool found=false; if(backward) flags=QTextDocument::FindBackward; if(case_sensitive_chk->isChecked()) flags=flags | QTextDocument::FindCaseSensitively; if(all_words_chk->isChecked()) flags=flags | QTextDocument::FindWholeWords; found=findText(find_edt->text(), regexp_chk->isChecked(), flags); if(!found && cyclic) { cursor=text_edt->textCursor(); if(!backward) cursor.setPosition(0); else cursor.setPosition(text_edt->toPlainText().length()); text_edt->setTextCursor(cursor); found=findText(find_edt->text(), regexp_chk->isChecked(), flags); } return(found); } pgmodeler-0.9.2/libpgmodeler_ui/src/findreplacewidget.h000066400000000000000000000032721360462764600233040ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class FindReplaceWidget \brief Implements the operations to find and replace text on a QTextEdit */ #ifndef FIND_REPLACE_WIDGET_H #define FIND_REPLACE_WIDGET_H #include "ui_findreplacewidget.h" #include #include "exception.h" class FindReplaceWidget: public QWidget, public Ui::FindReplaceWidget { private: Q_OBJECT //! \brief QTextEdit instance that the finder is attached to QPlainTextEdit *text_edt; //! \brief Find the text in a backward and/or cyclic way bool findText(bool backward, bool cyclic); //! \brief Find the text using the specified flags. The regexp param is ignored on Qt versions below 5.3 bool findText(const QString &text, bool regexp, QTextDocument::FindFlags flags); void showEvent(QShowEvent *); public: FindReplaceWidget(QPlainTextEdit *txt_edit, QWidget * parent = nullptr); public slots: void replaceText(void); void replaceAll(void); void replaceFindText(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/foreigndatawrapperwidget.cpp000066400000000000000000000103731360462764600252470ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "foreigndatawrapperwidget.h" ForeignDataWrapperWidget::ForeignDataWrapperWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::ForeignDataWrapper) { try { QHBoxLayout *hbox = nullptr; Ui_ForeignDataWrapperWidget::setupUi(this); func_handler_sel=nullptr; func_validator_sel=nullptr; func_handler_ht = new HintTextWidget(func_handler_hint, this); func_handler_ht->setText(trUtf8("The handler function must have the following signature: fdw_handler function_name()")); func_validator_ht = new HintTextWidget(func_validator_hint, this); func_validator_ht->setText(trUtf8("The validator function must have the following signature: function_name(text[],oid). The return type of ths function is ignored.")); func_handler_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); func_validator_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); hbox = new QHBoxLayout; hbox->setContentsMargins(0,0,0,0); hbox->addWidget(func_handler_sel); func_handler_wgt->setLayout(hbox); hbox = new QHBoxLayout; hbox->setContentsMargins(0,0,0,0); hbox->addWidget(func_validator_sel); func_validator_wgt->setLayout(hbox); options_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton), true, this); options_tab->setCellsEditable(true); options_tab->setColumnCount(2); options_tab->setHeaderLabel(trUtf8("Option"), 0); options_tab->setHeaderLabel(trUtf8("Value"), 1); hbox = new QHBoxLayout; hbox->setContentsMargins(4,4,4,4); hbox->addWidget(options_tab); options_gb->setLayout(hbox); configureFormLayout(fdw_grid, ObjectType::ForeignDataWrapper); configureTabOrder({ func_handler_sel, func_handler_ht, func_validator_sel, func_validator_ht, options_tab }); setMinimumSize(600, 420); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ForeignDataWrapperWidget::setAttributes(DatabaseModel *model, OperationList *op_list, ForeignDataWrapper *fdw) { BaseObjectWidget::setAttributes(model, op_list, fdw); func_handler_sel->setModel(model); func_validator_sel->setModel(model); if(fdw) { func_handler_sel->setSelectedObject(fdw->getHandlerFunction()); func_validator_sel->setSelectedObject(fdw->getValidatorFunction()); options_tab->blockSignals(true); for(auto &itr : fdw->getOptions()) { options_tab->addRow(); options_tab->setCellText(itr.first, options_tab->getRowCount() - 1, 0); options_tab->setCellText(itr.second, options_tab->getRowCount() - 1, 1); } options_tab->clearSelection(); options_tab->blockSignals(false); } } void ForeignDataWrapperWidget::applyConfiguration(void) { try { ForeignDataWrapper *fdw=nullptr; startConfiguration(); fdw=dynamic_cast(this->object); fdw->setHandlerFunction(dynamic_cast(func_handler_sel->getSelectedObject())); fdw->setValidatorFunction(dynamic_cast(func_validator_sel->getSelectedObject())); fdw->removeOptions(); for(unsigned row = 0; row < options_tab->getRowCount(); row++) fdw->setOption(options_tab->getCellText(row, 0), options_tab->getCellText(row, 1)); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/foreigndatawrapperwidget.h000066400000000000000000000030501360462764600247060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ForeignDataWrapperWidget \brief Implements the operations to create/edit foreign data wrappers via form. */ #ifndef FOREIGN_DATA_WRAPPER_WIDGET_H #define FOREIGN_DATA_WRAPPER_WIDGET_H #include "baseobjectwidget.h" #include "ui_foreigndatawrapperwidget.h" #include "hinttextwidget.h" #include "objectstablewidget.h" class ForeignDataWrapperWidget: public BaseObjectWidget, public Ui::ForeignDataWrapperWidget { private: Q_OBJECT ObjectSelectorWidget *func_handler_sel, *func_validator_sel; HintTextWidget *func_handler_ht, *func_validator_ht; ObjectsTableWidget *options_tab; public: ForeignDataWrapperWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, ForeignDataWrapper *fdw); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/foreignserverwidget.cpp000066400000000000000000000066401360462764600242450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "foreignserverwidget.h" ForeignServerWidget::ForeignServerWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::ForeignServer) { try { QHBoxLayout *hbox = nullptr; Ui_ForeignServerWidget::setupUi(this); fdw_sel=nullptr; fdw_sel=new ObjectSelectorWidget(ObjectType::ForeignDataWrapper, true, this); hbox = new QHBoxLayout; hbox->setContentsMargins(0,0,0,0); hbox->addWidget(fdw_sel); fdw_wgt->setLayout(hbox); options_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton), true, this); options_tab->setCellsEditable(true); options_tab->setColumnCount(2); options_tab->setHeaderLabel(trUtf8("Option"), 0); options_tab->setHeaderLabel(trUtf8("Value"), 1); hbox = new QHBoxLayout; hbox->setContentsMargins(4,4,4,4); hbox->addWidget(options_tab); options_gb->setLayout(hbox); configureFormLayout(server_grid, ObjectType::ForeignServer); setRequiredField(fdw_sel); setRequiredField(fdw_lbl); configureTabOrder({ type_edt, version_edt, fdw_sel, options_tab }); setMinimumSize(600, 420); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ForeignServerWidget::setAttributes(DatabaseModel *model, OperationList *op_list, ForeignServer *server) { BaseObjectWidget::setAttributes(model, op_list, server); fdw_sel->setModel(model); if(server) { version_edt->setText(server->getVersion()); type_edt->setText(server->getType()); fdw_sel->setSelectedObject(server->getForeignDataWrapper()); options_tab->blockSignals(true); for(auto &itr : server->getOptions()) { options_tab->addRow(); options_tab->setCellText(itr.first, options_tab->getRowCount() - 1, 0); options_tab->setCellText(itr.second, options_tab->getRowCount() - 1, 1); } options_tab->clearSelection(); options_tab->blockSignals(false); } } void ForeignServerWidget::applyConfiguration(void) { try { ForeignServer *server = nullptr; startConfiguration(); server = dynamic_cast(this->object); server->setForeignDataWrapper(dynamic_cast(fdw_sel->getSelectedObject())); server->removeOptions(); for(unsigned row = 0; row < options_tab->getRowCount(); row++) server->setOption(options_tab->getCellText(row, 0), options_tab->getCellText(row, 1)); server->setVersion(version_edt->text()); server->setType(type_edt->text()); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/foreignserverwidget.h000066400000000000000000000026051360462764600237070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ForeignServerWidget \brief Implements the operations to create/edit foreign servers via form. */ #ifndef FOREIGN_SERVER_WIDGET_H #define FOREIGN_SERVER_WIDGET_H #include "baseobjectwidget.h" #include "ui_foreignserverwidget.h" #include "objectstablewidget.h" class ForeignServerWidget: public BaseObjectWidget, public Ui::ForeignServerWidget { private: Q_OBJECT ObjectSelectorWidget *fdw_sel; ObjectsTableWidget *options_tab; public: ForeignServerWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, ForeignServer *server); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/functionwidget.cpp000066400000000000000000000410221360462764600232030ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "functionwidget.h" #include "baseform.h" FunctionWidget::FunctionWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Function) { try { QStringList types; QGridLayout *grid=nullptr, *grid1=nullptr; QVBoxLayout *vlayout=nullptr; QSpacerItem *spacer=nullptr; map > fields_map; map > value_map; QFrame *frame=nullptr; Ui_FunctionWidget::setupUi(this); configureFormLayout(function_grid, ObjectType::Function); source_code_txt=new NumberedTextEditor(this, true); dynamic_cast(source_code_frm->layout())->addWidget(source_code_txt, 1, 0, 1, 2); source_code_hl=new SyntaxHighlighter(source_code_txt); source_code_cp=new CodeCompletionWidget(source_code_txt, true); ret_type=new PgSQLTypeWidget(this); vlayout=new QVBoxLayout; spacer=new QSpacerItem(5,5,QSizePolicy::Preferred,QSizePolicy::Expanding); vlayout->addWidget(ret_type); vlayout->addSpacerItem(spacer); return_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::UpdateButton, true, this); return_tab->setColumnCount(2); return_tab->setHeaderLabel(trUtf8("Column"), 0); return_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); return_tab->setHeaderLabel(trUtf8("Type"), 1); return_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); parameters_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::UpdateButton, true, this); parameters_tab->setColumnCount(4); parameters_tab->setHeaderLabel(trUtf8("Name"),0); parameters_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("parameter")),0); parameters_tab->setHeaderLabel(trUtf8("Type"),1); parameters_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); parameters_tab->setHeaderLabel(trUtf8("Mode"),2); parameters_tab->setHeaderLabel(trUtf8("Default Value"),3); grid=new QGridLayout; grid->addWidget(parameters_tab,0,0,1,1); grid->setContentsMargins(4,4,4,4); func_config_twg->widget(1)->setLayout(grid); grid=dynamic_cast(func_config_twg->widget(0)->layout()); grid->addLayout(vlayout, grid->count(), 0, 1, 5); grid->addWidget(ret_table_gb, grid->count()-1, 0, 1, 5); grid1=new QGridLayout; grid1->addWidget(return_tab, 0, 0, 1, 1); grid1->setContentsMargins(2,2,2,2); ret_table_gb->setLayout(grid1); ret_table_gb->setVisible(false); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion92)].push_back(leakproof_chk); frame=generateVersionWarningFrame(fields_map, &value_map); grid->addWidget(frame, grid->count()+1, 0, 1, 5); frame->setParent(func_config_twg->widget(0)); SecurityType::getTypes(types); security_cmb->addItems(types); FunctionType::getTypes(types); func_type_cmb->addItems(types); BehaviorType::getTypes(types); behavior_cmb->addItems(types); connect(simple_rb, SIGNAL(clicked(bool)), this, SLOT(alternateReturnTypes(void))); connect(set_rb, SIGNAL(clicked(bool)), this, SLOT(alternateReturnTypes(void))); connect(table_rb, SIGNAL(clicked(bool)), this, SLOT(alternateReturnTypes(void))); connect(language_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(selectLanguage(void))); connect(parameters_tab, SIGNAL(s_rowAdded(int)), this, SLOT(showParameterForm())); connect(parameters_tab, SIGNAL(s_rowEdited(int)), this, SLOT(showParameterForm())); connect(parameters_tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateParameter(int,int))); connect(return_tab, SIGNAL(s_rowAdded(int)), this, SLOT(showParameterForm())); connect(return_tab, SIGNAL(s_rowEdited(int)), this, SLOT(showParameterForm())); connect(return_tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateParameter(int,int))); setRequiredField(language_lbl); setRequiredField(ret_method_lbl); setRequiredField(symbol_lbl); setRequiredField(library_lbl); setRequiredField(sourc_code_lbl); configureTabOrder(); setMinimumSize(650, 700); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void FunctionWidget::handleParameter(Parameter param, int result) { int lin_cnt, lin; ObjectsTableWidget *table=nullptr; //Selects the table to be handled according to its visibility if(parameters_tab->isVisible()) table=parameters_tab; else table=return_tab; lin_cnt=table->getRowCount(); //Case the user applied the configuration on the parameter editing form if(result==QDialog::Accepted) { lin=table->getSelectedRow(); /* If the row index is negative indicates the line in question is empty, e.g., the user is not editingan existing line, but adding a new, so the line to be considered in the table will always be the last recently included */ if(lin < 0) lin=lin_cnt-1; showParameterData(param, table, lin); } else if(result==QDialog::Rejected) { //Removes the last line from table if(lin_cnt > 0 && table->getCellText(lin_cnt-1,0).isEmpty()) table->removeRow(lin_cnt-1); } } void FunctionWidget::duplicateParameter(int curr_row, int new_row) { Parameter new_param; ObjectsTableWidget *table=nullptr; //Selects the table to be handled according to its visibility if(parameters_tab->isVisible()) table=parameters_tab; else table=return_tab; new_param = getParameter(table, curr_row); showParameterData(new_param, table, new_row); } void FunctionWidget::showParameterForm(void) { QObject *obj_sender=sender(); ObjectsTableWidget *table=nullptr; Parameter aux_param; int lin_idx; ParameterWidget *parameter_wgt=new ParameterWidget; BaseForm parent_form; if(obj_sender==parameters_tab || obj_sender==return_tab) { table=dynamic_cast(obj_sender); parameter_wgt->param_in_chk->setEnabled(obj_sender==parameters_tab); parameter_wgt->param_out_chk->setEnabled(obj_sender==parameters_tab); parameter_wgt->param_variadic_chk->setEnabled(obj_sender==parameters_tab); parameter_wgt->default_value_edt->setEnabled(obj_sender==parameters_tab); lin_idx=table->getSelectedRow(); if(lin_idx >= 0 && !table->getCellText(lin_idx, 0).isEmpty()) aux_param=getParameter(table, lin_idx); parameter_wgt->setAttributes(aux_param, model); parent_form.setMainWidget(parameter_wgt); parent_form.exec(); aux_param=parameter_wgt->getParameter(); handleParameter(aux_param, parent_form.result()); } } Parameter FunctionWidget::getParameter(ObjectsTableWidget *tab, unsigned row) { Parameter param; QString str_aux; if(tab) { try { param.setName(tab->getCellText(row,0)); param.setType(tab->getRowData(row).value()); if(tab==parameters_tab) { str_aux=tab->getCellText(row, 2); param.setIn(str_aux.contains(QString("IN"))); param.setOut(str_aux.contains(QString("OUT"))); param.setVariadic(str_aux==QString("VARIADIC")); param.setDefaultValue(tab->getCellText(row,3)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } return(param); } void FunctionWidget::showParameterData(Parameter param, ObjectsTableWidget *tab, unsigned row) { if(tab) { QString str_aux; tab->setCellText(param.getName(),row,0); tab->setCellText(*param.getType(),row,1); tab->setRowData(QVariant::fromValue(param.getType()), row); if(tab==parameters_tab) { if(param.isVariadic()) str_aux=QString("VARIADIC"); else { if(param.isIn()) str_aux=QString("IN"); if(param.isOut()) str_aux+=QString("OUT"); } tab->setCellText(str_aux,row,2); tab->setCellText(param.getDefaultValue(),row,3); } } } void FunctionWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Function *func) { vector languages; Language *lang=nullptr; QStringList list; unsigned count=0, i; Parameter param; PgSqlType aux_type; BaseObjectWidget::setAttributes(model, op_list, func, schema); languages=model->getObjects(ObjectType::Language); while(!languages.empty()) { lang=dynamic_cast(languages.back()); languages.pop_back(); list.append(lang->getName()); } list.sort(); language_cmb->addItems(list); language_cmb->setCurrentText(~LanguageType(LanguageType::Sql)); if(func) { aux_type=func->getReturnType(); language_cmb->setCurrentIndex(language_cmb->findText(func->getLanguage()->getName())); func_type_cmb->setCurrentIndex(func_type_cmb->findText(~func->getFunctionType())); window_func_chk->setChecked(func->isWindowFunction()); leakproof_chk->setChecked(func->isLeakProof()); exec_cost_spb->setValue(func->getExecutionCost()); rows_ret_spb->setValue(func->getRowAmount()); behavior_cmb->setCurrentIndex(behavior_cmb->findText(~func->getBehaviorType())); security_cmb->setCurrentIndex(security_cmb->findText(~func->getSecurityType())); if(func->isReturnSetOf()) set_rb->setChecked(true); else if(func->isReturnTable()) table_rb->setChecked(true); else simple_rb->setChecked(true); count=func->getParameterCount(); parameters_tab->blockSignals(true); return_tab->blockSignals(true); for(i=0; i < count; i++) { parameters_tab->addRow(); param=func->getParameter(i); showParameterData(param,parameters_tab,i); } parameters_tab->clearSelection(); count=func->getReturnedTableColumnCount(); if(count > 0) { ret_table_gb->setVisible(true); ret_type->setVisible(false); for(i=0; i < count; i++) { return_tab->addRow(); param=func->getReturnedTableColumn(i); showParameterData(param,return_tab,i); } } return_tab->clearSelection(); if(!func->getLibrary().isEmpty()) { symbol_edt->setText(func->getSymbol()); library_edt->setText(func->getLibrary()); } else { source_code_txt->setPlainText(func->getSourceCode()); } parameters_tab->blockSignals(false); return_tab->blockSignals(false); } ret_type->setAttributes(aux_type, model); } void FunctionWidget::alternateReturnTypes(void) { QObject *obj_sender=sender(); ret_table_gb->setVisible(obj_sender==table_rb); ret_type->setVisible(!ret_table_gb->isVisible()); } void FunctionWidget::selectLanguage(void) { bool c_lang; c_lang=(language_cmb->currentText()==~LanguageType(LanguageType::C)); source_code_frm->setVisible(!c_lang); library_frm->setVisible(c_lang); if(!c_lang) { try { source_code_hl->loadConfiguration(GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + language_cmb->currentText() + GlobalAttributes::HighlightFileSuffix + GlobalAttributes::ConfigurationExt); } catch(Exception &) { source_code_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); } source_code_hl->rehighlight(); source_code_cp->configureCompletion(this->model, source_code_hl); } } void FunctionWidget::validateConfiguredFunction(void) { vector::iterator itr, itr_end; vector obj_list; Conversion *conv=nullptr; Cast *cast=nullptr; Aggregate *aggr=nullptr; Language *lang=nullptr; Operator *oper=nullptr; Type *type=nullptr; Function *func=nullptr; BaseObject *object=nullptr; ObjectType obj_type; unsigned i1=0; func=dynamic_cast(this->object); try { model->getObjectReferences(func, obj_list); itr=obj_list.begin(); itr_end=obj_list.end(); while(itr!=itr_end) { object=(*itr); obj_type=object->getObjectType(); itr++; /* The validation of the function happens as follows: For each type of object in vector 'types' is obtained the list of objects. If there are elements in this list, the function is assigned for each element and these elements internally validates the function according to required by the each class rules. If the function is invalid the instances raises exceptions accusing the error that is enough to check the validity of the function in relation to objects that reference it. */ if(obj_type==ObjectType::Conversion) { conv=dynamic_cast(object); if(conv->getConversionFunction()==func) conv->setConversionFunction(func); } else if(obj_type==ObjectType::Cast) { cast=dynamic_cast(object); if(cast->getCastFunction()==func) cast->setCastFunction(func); } else if(obj_type==ObjectType::Aggregate) { aggr=dynamic_cast(object); if(aggr->getFunction(Aggregate::FinalFunc)==func) aggr->setFunction(Aggregate::FinalFunc, func); else if(aggr->getFunction(Aggregate::TransitionFunc)==func) aggr->setFunction(Aggregate::TransitionFunc, func); } else if(obj_type==ObjectType::Trigger) { dynamic_cast(object)->setFunction(func); } else if(obj_type==ObjectType::Language) { lang=dynamic_cast(object); for(i1=Language::ValidatorFunc; i1 <= Language::InlineFunc; i1++) { if(lang->getFunction(i1)==func) lang->setFunction(func, i1); } } else if(obj_type==ObjectType::Operator) { oper=dynamic_cast(object); for(i1=Operator::FuncOperator; i1 <= Operator::FuncRestrict; i1++) { if(oper->getFunction(i1)==func) oper->setFunction(func, i1); } } else if(obj_type==ObjectType::Type) { type=dynamic_cast(object); if(type->getConfiguration()==Type::BaseType) { for(i1=Type::InputFunc; i1 <=Type::AnalyzeFunc; i1++) { if(type->getFunction(i1)==func) type->setFunction(i1, func); } } } else if(obj_type==ObjectType::EventTrigger) { dynamic_cast(object)->setFunction(func); } } } catch(Exception &e) { throw Exception(Exception::getErrorMessage(ErrorCode::InvFuncConfigInvalidatesObject) .arg(object->getName(true)) .arg(object->getTypeName()), ErrorCode::InvFuncConfigInvalidatesObject, __PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void FunctionWidget::applyConfiguration(void) { try { Function *func=nullptr; unsigned count, i; Parameter param; QString str_aux; startConfiguration(); func=dynamic_cast(this->object); func->setLanguage(model->getObject(language_cmb->currentText(), ObjectType::Language)); func->setFunctionType(func_type_cmb->currentText()); func->setWindowFunction(window_func_chk->isChecked()); func->setLeakProof(leakproof_chk->isChecked()); func->setExecutionCost(exec_cost_spb->value()); func->setRowAmount(rows_ret_spb->value()); func->setBehaviorType(behavior_cmb->currentText()); func->setSecurityType(security_cmb->currentText()); func->removeParameters(); count=parameters_tab->getRowCount(); for(i=0; i < count; i++) { param.setName(parameters_tab->getCellText(i,0)); param.setType(parameters_tab->getRowData(i).value()); str_aux=parameters_tab->getCellText(i,2); param.setIn(str_aux.indexOf(QString("IN")) >= 0); param.setOut(str_aux.indexOf(QString("OUT")) >= 0); param.setVariadic(str_aux.indexOf(QString("VARIADIC")) >= 0); param.setDefaultValue(parameters_tab->getCellText(i,3)); func->addParameter(param); } if(language_cmb->currentText()==~LanguageType(LanguageType::C)) { func->setLibrary(library_edt->text()); func->setSymbol(symbol_edt->text()); } else func->setSourceCode(source_code_txt->toPlainText().toUtf8()); if(simple_rb->isChecked() || set_rb->isChecked()) { func->setReturnType(ret_type->getPgSQLType()); func->setReturnSetOf(set_rb->isChecked()); } else { func->removeReturnedTableColumns(); count=return_tab->getRowCount(); for(i=0; iaddReturnedTableColumn(return_tab->getCellText(i,0), return_tab->getRowData(i).value()); } } BaseObjectWidget::applyConfiguration(); validateConfiguredFunction(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/functionwidget.h000066400000000000000000000056271360462764600226630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class FunctionWidget \brief Implements the operations to create/edit functions via form. */ #ifndef FUNCTION_WIDGET_H #define FUNCTION_WIDGET_H #include "baseobjectwidget.h" #include "ui_functionwidget.h" #include "pgsqltypewidget.h" #include "objectstablewidget.h" #include "codecompletionwidget.h" #include "parameterwidget.h" #include "numberedtexteditor.h" class FunctionWidget: public BaseObjectWidget, public Ui::FunctionWidget { private: Q_OBJECT NumberedTextEditor *source_code_txt; //! \brief Function's source code highlighter SyntaxHighlighter *source_code_hl; //! \brief Function's source code completion CodeCompletionWidget *source_code_cp; //! \brief Widget used to configure the function's return type PgSQLTypeWidget *ret_type; //! \brief Table that represents the table returned by the function ObjectsTableWidget *return_tab, //! \brief Table used to store the function's parameters *parameters_tab; //! \brief Returns a parameter configured based upon the specified table and line Parameter getParameter(ObjectsTableWidget *tab, unsigned row); //! \brief Shows the parameter data on the specified table at the specified line void showParameterData(Parameter param, ObjectsTableWidget *tab, unsigned row); //! \brief Validates the new function configuration in relation to the other objects that references it. void validateConfiguredFunction(void); public: FunctionWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Function *func); private slots: void alternateReturnTypes(void); /*! \brief Selects the language used by the function and if available loads the syntax highlight configuration for the selected language. */ void selectLanguage(void); //! \brief Shows the parameter configuration form void showParameterForm(void); //! \brief Shows the configured parameter on the table that called the form void handleParameter(Parameter param, int result); //! brief Duplicates the parameter in the curr_row placing it in new_row void duplicateParameter(int curr_row, int new_row); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/generalconfigwidget.cpp000066400000000000000000001144741360462764600241750ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "generalconfigwidget.h" #include "objectsscene.h" #include "modelwidget.h" #include "operationlist.h" #include "syntaxhighlighter.h" #include "mainwindow.h" #include "numberedtexteditor.h" #include "linenumberswidget.h" #include "sqlexecutionwidget.h" #include "modeldatabasediffform.h" #include "databaseimportform.h" #include "modelexportform.h" map GeneralConfigWidget::config_params; map GeneralConfigWidget::widgets_geom; GeneralConfigWidget::GeneralConfigWidget(QWidget * parent) : BaseConfigWidget(parent) { QPrinter::PaperSize paper_ids[]={QPrinter::A0, QPrinter::A1, QPrinter::A2, QPrinter::A3, QPrinter::A4, QPrinter::A5, QPrinter::A6, QPrinter::A7, QPrinter::A8, QPrinter::A9, QPrinter::B0, QPrinter::B1, QPrinter::B10, QPrinter::B2, QPrinter::B3, QPrinter::B4, QPrinter::B5, QPrinter::B6, QPrinter::B7, QPrinter::B8, QPrinter::B9, QPrinter::C5E, QPrinter::Comm10E, QPrinter::DLE, QPrinter::Executive, QPrinter::Folio, QPrinter::Ledger, QPrinter::Legal, QPrinter::Letter, QPrinter::Tabloid, QPrinter::Custom }; int count=sizeof(paper_ids)/sizeof(QPrinter::PaperSize); Ui_GeneralConfigWidget::setupUi(this); line_numbers_cp=new ColorPickerWidget(1, this); line_numbers_cp->setButtonToolTip(0, trUtf8("Line numbers' font color")); line_numbers_bg_cp=new ColorPickerWidget(1, this); line_numbers_bg_cp->setButtonToolTip(0, trUtf8("Line numbers' background color")); line_highlight_cp=new ColorPickerWidget(1, this); line_highlight_cp->setButtonToolTip(0, trUtf8("Highlighted line color")); font_preview_txt=new NumberedTextEditor(this); font_preview_txt->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); font_preview_txt->setPlainText(trUtf8("The little brown fox jumps over the lazy dog") + QString("\n\ttext with tab «") + QString("\n0123456789\n.()[]{};")); QBoxLayout *layout=new QBoxLayout(QBoxLayout::LeftToRight); QGridLayout *grid=dynamic_cast(code_font_gb->layout()); layout->addWidget(line_numbers_cp); layout->addWidget(line_numbers_bg_cp); layout->addWidget(line_highlight_cp); layout->addItem(new QSpacerItem(1000,20, QSizePolicy::Expanding)); grid->addLayout(layout, 2, 1); grid->addWidget(font_preview_txt,grid->count(),0,1,5); for(int i=0; i < count; i++) paper_cmb->setItemData(i, QVariant(paper_ids[i])); connect(unity_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(convertMarginUnity(void))); connect(autosave_interv_chk, SIGNAL(toggled(bool)), autosave_interv_spb, SLOT(setEnabled(bool))); connect(paper_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(selectPaperSize(void))); connect(font_size_spb, SIGNAL(valueChanged(double)), this, SLOT(updateFontPreview())); connect(font_cmb, SIGNAL(currentFontChanged(QFont)), this, SLOT(updateFontPreview())); connect(line_numbers_cp, SIGNAL(s_colorChanged(unsigned, QColor)), this, SLOT(updateFontPreview())); connect(line_numbers_cp, SIGNAL(s_colorsChanged(void)), this, SLOT(updateFontPreview())); connect(line_numbers_bg_cp, SIGNAL(s_colorChanged(unsigned, QColor)), this, SLOT(updateFontPreview())); connect(line_numbers_bg_cp, SIGNAL(s_colorsChanged(void)), this, SLOT(updateFontPreview())); connect(line_highlight_cp, SIGNAL(s_colorChanged(unsigned, QColor)), this, SLOT(updateFontPreview())); connect(line_highlight_cp, SIGNAL(s_colorsChanged(void)), this, SLOT(updateFontPreview())); connect(disp_line_numbers_chk, SIGNAL(toggled(bool)), this, SLOT(updateFontPreview())); connect(hightlight_lines_chk, SIGNAL(toggled(bool)), this, SLOT(updateFontPreview())); connect(tab_width_spb, SIGNAL(valueChanged(int)), this, SLOT(updateFontPreview())); connect(tab_width_chk, SIGNAL(toggled(bool)), tab_width_spb, SLOT(setEnabled(bool))); connect(tab_width_chk, SIGNAL(toggled(bool)), this, SLOT(updateFontPreview())); connect(font_preview_txt, SIGNAL(cursorPositionChanged()), this, SLOT(updateFontPreview())); connect(select_editor_btn, SIGNAL(clicked(bool)), this, SLOT(selectSourceEditor())); connect(save_restore_geometry_chk, SIGNAL(toggled(bool)), reset_sizes_tb, SLOT(setEnabled(bool))); connect(reset_sizes_tb, SIGNAL(clicked(bool)), this, SLOT(resetDialogsSizes())); config_params[Attributes::Configuration][Attributes::GridSize]=QString(); config_params[Attributes::Configuration][Attributes::OpListSize]=QString(); config_params[Attributes::Configuration][Attributes::AutoSaveInterval]=QString(); config_params[Attributes::Configuration][Attributes::PaperType]=QString(); config_params[Attributes::Configuration][Attributes::PaperOrientation]=QString(); config_params[Attributes::Configuration][Attributes::PaperMargin]=QString(); config_params[Attributes::Configuration][Attributes::PaperCustomSize]=QString(); config_params[Attributes::Configuration][Attributes::File]=QString(); config_params[Attributes::Configuration][Attributes::RecentModels]=QString(); config_params[Attributes::Configuration][Attributes::PrintPgNum]=QString(); config_params[Attributes::Configuration][Attributes::PrintGrid]=QString(); config_params[Attributes::Configuration][Attributes::HideRelName]=QString(); config_params[Attributes::Configuration][Attributes::HideExtAttribs]=QString(); config_params[Attributes::Configuration][Attributes::HideTableTags]=QString(); config_params[Attributes::Configuration][Attributes::FileAssociated]=QString(); config_params[Attributes::Configuration][Attributes::CodeFont]=QString(); config_params[Attributes::Configuration][Attributes::CodeFontSize]=QString(); config_params[Attributes::Configuration][Attributes::CanvasCornerMove]=QString(); config_params[Attributes::Configuration][Attributes::InvertRangeSelTrigger]=QString(); config_params[Attributes::Configuration][Attributes::CheckUpdate]=QString(); config_params[Attributes::Configuration][Attributes::SaveLastPosition]=QString(); config_params[Attributes::Configuration][Attributes::ShowMainMenu]=QString(); config_params[Attributes::Configuration][Attributes::DisableSmoothness]=QString(); config_params[Attributes::Configuration][Attributes::SimplifiedObjCreation]=QString(); config_params[Attributes::Configuration][Attributes::ConfirmValidation]=QString(); config_params[Attributes::Configuration][Attributes::ShowMainMenu]=QString(); config_params[Attributes::Configuration][Attributes::CodeCompletion]=QString(); config_params[Attributes::Configuration][Attributes::DisplayLineNumbers]=QString(); config_params[Attributes::Configuration][Attributes::LineNumbersColor]=QString(); config_params[Attributes::Configuration][Attributes::LineNumbersBgColor]=QString(); config_params[Attributes::Configuration][Attributes::LineHighlightColor]=QString(); config_params[Attributes::Configuration][Attributes::HighlightLines]=QString(); config_params[Attributes::Configuration][Attributes::UsePlaceholders]=QString(); config_params[Attributes::Configuration][Attributes::MinObjectOpacity]=QString(); config_params[Attributes::Configuration][Attributes::HistoryMaxLength]=QString(); config_params[Attributes::Configuration][Attributes::SourceEditorApp]=QString(); config_params[Attributes::Configuration][Attributes::UiLanguage]=QString(); config_params[Attributes::Configuration][Attributes::UseCurvedLines]=QString(); config_params[Attributes::Configuration][Attributes::SaveRestoreGeometry]=QString(); config_params[Attributes::Configuration][Attributes::AttribsPerPage]=QString(); config_params[Attributes::Configuration][Attributes::ExtAttribsPerPage]=QString(); config_params[Attributes::Configuration][Attributes::LowVerbosity]=QString(); simp_obj_creation_ht=new HintTextWidget(simp_obj_creation_hint, this); simp_obj_creation_ht->setText(simple_obj_creation_chk->statusTip()); confirm_validation_ht=new HintTextWidget(confirm_validation_hint, this); confirm_validation_ht->setText(confirm_validation_chk->statusTip()); corner_move_ht=new HintTextWidget(corner_move_hint, this); corner_move_ht->setText(corner_move_chk->statusTip()); save_last_pos_ht=new HintTextWidget(save_last_pos_hint, this); save_last_pos_ht->setText(save_last_pos_chk->statusTip()); invert_rangesel_ht=new HintTextWidget(invert_rangesel_hint, this); invert_rangesel_ht->setText(invert_rangesel_chk->statusTip()); disable_smooth_ht=new HintTextWidget(disable_smooth_hint, this); disable_smooth_ht->setText(disable_smooth_chk->statusTip()); hide_ext_attribs_ht=new HintTextWidget(hide_ext_attribs_hint, this); hide_ext_attribs_ht->setText(hide_ext_attribs_chk->statusTip()); hide_table_tags_ht=new HintTextWidget(hide_table_tags_hint, this); hide_table_tags_ht->setText(hide_table_tags_chk->statusTip()); hide_rel_name_ht=new HintTextWidget(hide_rel_name_hint, this); hide_rel_name_ht->setText(hide_rel_name_chk->statusTip()); code_completion_ht=new HintTextWidget(code_completion_hint, this); code_completion_ht->setText(code_completion_chk->statusTip()); use_placeholders_ht=new HintTextWidget(use_placeholders_hint, this); use_placeholders_ht->setText(use_placeholders_chk->statusTip()); min_obj_opacity_ht=new HintTextWidget(min_obj_opacity_hint, this); min_obj_opacity_ht->setText(min_obj_opacity_spb->statusTip()); autosave_ht=new HintTextWidget(autosave_hint, this); autosave_ht->setText(autosave_interv_chk->statusTip()); op_history_ht=new HintTextWidget(op_history_hint, this); op_history_ht->setText(oplist_size_spb->statusTip()); ui_language_ht=new HintTextWidget(ui_language_hint, this); ui_language_ht->setText(ui_language_cmb->statusTip()); grid_size_ht=new HintTextWidget(grid_size_hint, this); grid_size_ht->setText(grid_size_spb->statusTip()); use_curved_lines_ht=new HintTextWidget(use_curved_lines_hint, this); use_curved_lines_ht->setText(use_curved_lines_chk->statusTip()); attribs_per_page_ht=new HintTextWidget(attributes_per_page_hint, this); attribs_per_page_ht->setText(attribs_per_page_spb->statusTip()); reduce_verbosity_ht = new HintTextWidget(low_verbosity_hint, this); reduce_verbosity_ht->setText(low_verbosity_chk->statusTip()); escape_comments_ht = new HintTextWidget(escape_comments_hint, this); escape_comments_ht->setText(escape_comments_chk->statusTip()); selectPaperSize(); QList chk_boxes=this->findChildren(); QList spin_boxes=this->findChildren(); QList dspin_boxes=this->findChildren(); QList combos=this->findChildren(); QList radios=this->findChildren(); for(QCheckBox *chk : chk_boxes) { child_wgts.push_back(chk); connect(chk, SIGNAL(clicked()), this, SLOT(setConfigurationChanged())); } for(QSpinBox *spin : spin_boxes) { child_wgts.push_back(spin); connect(spin, SIGNAL(valueChanged(QString)), this, SLOT(setConfigurationChanged())); } for(QDoubleSpinBox *dspin : dspin_boxes) { child_wgts.push_back(dspin); connect(dspin, SIGNAL(valueChanged(QString)), this, SLOT(setConfigurationChanged())); } for(QComboBox *cmb : combos) { child_wgts.push_back(cmb); connect(cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigurationChanged())); } for(QRadioButton *radio : radios) { child_wgts.push_back(radio); connect(radio, SIGNAL(clicked()), this, SLOT(setConfigurationChanged())); } confs_dir_edt->setText(GlobalAttributes::ConfigurationsDir); connect(open_dir_tb, &QToolButton::clicked, [&](){ QDesktopServices::openUrl(QUrl(QString("file://") + confs_dir_edt->text())); }); connect(clear_sql_history_tb, &QToolButton::clicked, [](){ SQLExecutionWidget::destroySQLHistory(); }); #ifdef NO_UPDATE_CHECK check_upd_chk->setChecked(false); check_upd_chk->setVisible(false); #endif //Retrieving the available UI dictionaries QStringList langs = QDir(GlobalAttributes::LanguagesDir + GlobalAttributes::DirSeparator, QString("*.qm"), QDir::Name, QDir::AllEntries | QDir::NoDotAndDotDot).entryList(); langs.replaceInStrings(QString(".qm"), QString()); ui_language_cmb->addItem(trUtf8("System default")); QString native_lang; for(QString lang : langs) { native_lang = QLocale(lang).nativeLanguageName(); native_lang[0] = native_lang[0].toUpper(); ui_language_cmb->addItem(QString("%1 (%2 : %3)") .arg(native_lang) .arg(QLocale::languageToString(QLocale(lang).language())) .arg(lang), lang); } } void GeneralConfigWidget::loadConfiguration(void) { try { QStringList margin, custom_size; vector key_attribs; unsigned interv=0; int tab_width=0, x=0, y=0, w=0, h=0; for(QWidget *wgt : child_wgts) wgt->blockSignals(true); key_attribs.push_back(Attributes::Id); BaseConfigWidget::loadConfiguration(GlobalAttributes::GeneralConf, config_params, key_attribs); grid_size_spb->setValue((config_params[Attributes::Configuration][Attributes::GridSize]).toUInt()); oplist_size_spb->setValue((config_params[Attributes::Configuration][Attributes::OpListSize]).toUInt()); history_max_length_spb->setValue(config_params[Attributes::Configuration][Attributes::HistoryMaxLength].toUInt()); interv=(config_params[Attributes::Configuration][Attributes::AutoSaveInterval]).toUInt(); tab_width=(config_params[Attributes::Configuration][Attributes::CodeTabWidth]).toInt(); autosave_interv_chk->setChecked(interv > 0); autosave_interv_spb->setValue(interv); autosave_interv_spb->setEnabled(autosave_interv_chk->isChecked()); tab_width_chk->setChecked(tab_width > 0); tab_width_spb->setEnabled(tab_width_chk->isChecked()); tab_width_spb->setValue(tab_width); corner_move_chk->setChecked(config_params[Attributes::Configuration][Attributes::CanvasCornerMove]==Attributes::True); invert_rangesel_chk->setChecked(config_params[Attributes::Configuration][Attributes::InvertRangeSelTrigger]==Attributes::True); check_upd_chk->setChecked(config_params[Attributes::Configuration][Attributes::CheckUpdate]==Attributes::True); save_last_pos_chk->setChecked(config_params[Attributes::Configuration][Attributes::SaveLastPosition]==Attributes::True); disable_smooth_chk->setChecked(config_params[Attributes::Configuration][Attributes::DisableSmoothness]==Attributes::True); simple_obj_creation_chk->setChecked(config_params[Attributes::Configuration][Attributes::SimplifiedObjCreation]==Attributes::True); confirm_validation_chk->setChecked(config_params[Attributes::Configuration][Attributes::ConfirmValidation]==Attributes::True); code_completion_chk->setChecked(config_params[Attributes::Configuration][Attributes::CodeCompletion]==Attributes::True); use_placeholders_chk->setChecked(config_params[Attributes::Configuration][Attributes::UsePlaceholders]==Attributes::True); use_curved_lines_chk->setChecked(config_params[Attributes::Configuration][Attributes::UseCurvedLines]==Attributes::True); print_grid_chk->setChecked(config_params[Attributes::Configuration][Attributes::PrintGrid]==Attributes::True); print_pg_num_chk->setChecked(config_params[Attributes::Configuration][Attributes::PrintPgNum]==Attributes::True); paper_cmb->setCurrentIndex((config_params[Attributes::Configuration][Attributes::PaperType]).toUInt()); portrait_rb->setChecked(config_params[Attributes::Configuration][Attributes::PaperOrientation]==Attributes::Portrait); landscape_rb->setChecked(config_params[Attributes::Configuration][Attributes::PaperOrientation]==Attributes::Landscape); min_obj_opacity_spb->setValue(config_params[Attributes::Configuration][Attributes::MinObjectOpacity].toUInt()); attribs_per_page_spb->setValue(config_params[Attributes::Configuration][Attributes::AttribsPerPage].toUInt()); ext_attribs_per_page_spb->setValue(config_params[Attributes::Configuration][Attributes::ExtAttribsPerPage].toUInt()); margin=config_params[Attributes::Configuration][Attributes::PaperMargin].split(','); custom_size=config_params[Attributes::Configuration][Attributes::PaperCustomSize].split(','); left_marg->setValue((margin.count() >= 4 ? margin[0].toDouble() : 2)); top_marg->setValue((margin.count()>= 4 ? margin[1].toDouble() : 2)); right_marg->setValue((margin.count() >= 4 ? margin[2].toDouble() : 2)); bottom_marg->setValue((margin.count() >= 4 ? margin[3].toDouble() : 2)); width_spb->setValue((custom_size.count() >= 2 ? custom_size[0].toDouble() : 500)); height_spb->setValue((custom_size.count() >= 2 ? custom_size[1].toDouble() : 500)); hide_ext_attribs_chk->setChecked(config_params[Attributes::Configuration][Attributes::HideExtAttribs]==Attributes::True); hide_rel_name_chk->setChecked(config_params[Attributes::Configuration][Attributes::HideRelName]==Attributes::True); hide_table_tags_chk->setChecked(config_params[Attributes::Configuration][Attributes::HideTableTags]==Attributes::True); font_cmb->setCurrentFont(QFont(config_params[Attributes::Configuration][Attributes::CodeFont])); font_size_spb->setValue(config_params[Attributes::Configuration][Attributes::CodeFontSize].toDouble()); disp_line_numbers_chk->setChecked(config_params[Attributes::Configuration][Attributes::DisplayLineNumbers]==Attributes::True); hightlight_lines_chk->setChecked(config_params[Attributes::Configuration][Attributes::HighlightLines]==Attributes::True); line_numbers_cp->setColor(0, config_params[Attributes::Configuration][Attributes::LineNumbersColor]); line_numbers_bg_cp->setColor(0, config_params[Attributes::Configuration][Attributes::LineNumbersBgColor]); line_highlight_cp->setColor(0, config_params[Attributes::Configuration][Attributes::LineHighlightColor]); source_editor_edt->setText(config_params[Attributes::Configuration][Attributes::SourceEditorApp]); source_editor_args_edt->setText(config_params[Attributes::Configuration][Attributes::SourceEditorArgs]); save_restore_geometry_chk->setChecked(config_params[Attributes::Configuration][Attributes::SaveRestoreGeometry]==Attributes::True); reset_sizes_tb->setEnabled(save_restore_geometry_chk->isChecked()); low_verbosity_chk->setChecked(config_params[Attributes::Configuration][Attributes::LowVerbosity]==Attributes::True); escape_comments_chk->setChecked(config_params[Attributes::Configuration][Attributes::EscapeComment]==Attributes::True); int ui_idx = ui_language_cmb->findData(config_params[Attributes::Configuration][Attributes::UiLanguage]); ui_language_cmb->setCurrentIndex(ui_idx >= 0 ? ui_idx : 0); for(QWidget *wgt : child_wgts) wgt->blockSignals(false); widgets_geom.clear(); for(auto itr : config_params) { if(itr.second.count(Attributes::XPos)) { x = itr.second[Attributes::XPos].toInt(); y = itr.second[Attributes::YPos].toInt(); w = itr.second[Attributes::Width].toInt(); h = itr.second[Attributes::Height].toInt(); widgets_geom[itr.first].geometry = QRect(QPoint(x,y), QSize(w, h)); widgets_geom[itr.first].maximized = itr.second[Attributes::Maximized] == Attributes::True; } } updateFontPreview(); this->applyConfiguration(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo()); } } void GeneralConfigWidget::addConfigurationParam(const QString ¶m, const attribs_map &attribs) { BaseConfigWidget::addConfigurationParam(config_params, param, attribs); } void GeneralConfigWidget::removeConfigurationParam(const QRegExp ¶m_reg) { map::iterator itr, itr_end; itr=config_params.begin(); itr_end=config_params.end(); while(itr!=itr_end) { if(param_reg.exactMatch(itr->first)) { config_params.erase(itr); itr=config_params.begin(); itr_end=config_params.end(); } itr++; } } map GeneralConfigWidget::getConfigurationParams(void) { return(config_params); } QString GeneralConfigWidget::getConfigurationParam(const QString §ion_id, const QString ¶m_name) { if(config_params.count(section_id) && config_params[section_id].count(param_name)) return(config_params[section_id][param_name]); else return(QString()); } void GeneralConfigWidget::saveWidgetGeometry(QWidget *widget, const QString &custom_wgt_name) { if(!widget || config_params[Attributes::Configuration][Attributes::SaveRestoreGeometry] != Attributes::True) return; QString dlg_name = custom_wgt_name.isEmpty() ? widget->metaObject()->className() : custom_wgt_name; widgets_geom[dlg_name.toLower()].geometry = widget->geometry(); widgets_geom[dlg_name.toLower()].maximized = widget->isMaximized(); } bool GeneralConfigWidget::restoreWidgetGeometry(QWidget *widget, const QString &custom_wgt_name) { if(!widget || config_params[Attributes::Configuration][Attributes::SaveRestoreGeometry] != Attributes::True) return(false); QString dlg_name = custom_wgt_name.isEmpty() ? widget->metaObject()->className() : custom_wgt_name; dlg_name = dlg_name.toLower(); if(widgets_geom.count(dlg_name) && (widgets_geom[dlg_name].maximized || (widgets_geom[dlg_name].geometry.width() > 0 && widgets_geom[dlg_name].geometry.height() > 0))) { QList screens = qApp->screens(); WidgetState wgt_st = widgets_geom[dlg_name]; bool scr_contains_geom = false; QRect scr_geom; // Validating the widget geometry against the available screens sizes for(auto &scr : screens) { scr_geom = scr->geometry(); scr_contains_geom = ((wgt_st.maximized && scr_geom.contains(wgt_st.geometry.topLeft())) || (scr_geom.contains(wgt_st.geometry))); if(scr_contains_geom) break; } /* If the current window geometry doesn't fit the screen(s) geometry * the default geometry of the window is used */ if(!scr_contains_geom) return(false); if(wgt_st.maximized) { widget->move(wgt_st.geometry.topLeft()); widget->setWindowState(Qt::WindowMaximized); } else widget->setGeometry(wgt_st.geometry); return(true); } return(false); } void GeneralConfigWidget::saveConfiguration(void) { try { attribs_map attribs; map::iterator itr, itr_end; QString file_sch, root_dir, widget_sch; int recent_mdl_idx = 0; root_dir=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator; file_sch=root_dir + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + Attributes::File + GlobalAttributes::SchemaExt; widget_sch=root_dir + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + Attributes::Widget + GlobalAttributes::SchemaExt; config_params[Attributes::Configuration][Attributes::GridSize]=QString::number(grid_size_spb->value()); config_params[Attributes::Configuration][Attributes::OpListSize]=QString::number(oplist_size_spb->value()); config_params[Attributes::Configuration][Attributes::AutoSaveInterval]=QString::number(autosave_interv_chk->isChecked() ? autosave_interv_spb->value() : 0); config_params[Attributes::Configuration][Attributes::PaperType]=QString::number(paper_cmb->currentIndex()); config_params[Attributes::Configuration][Attributes::PaperOrientation]=(portrait_rb->isChecked() ? Attributes::Portrait : Attributes::Landscape); config_params[Attributes::Configuration][Attributes::CanvasCornerMove]=(corner_move_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::InvertRangeSelTrigger]=(invert_rangesel_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::CheckUpdate]=(check_upd_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::SaveLastPosition]=(save_last_pos_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::DisableSmoothness]=(disable_smooth_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::SimplifiedObjCreation]=(simple_obj_creation_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::ConfirmValidation]=(confirm_validation_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::CodeCompletion]=(code_completion_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::CodeTabWidth]=QString::number(tab_width_chk->isChecked() ? tab_width_spb->value() : 0); config_params[Attributes::Configuration][Attributes::MinObjectOpacity]=QString::number(min_obj_opacity_spb->value()); config_params[Attributes::Configuration][Attributes::UsePlaceholders]=(use_placeholders_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::HistoryMaxLength]=QString::number(history_max_length_spb->value()); config_params[Attributes::Configuration][Attributes::UseCurvedLines]=(use_curved_lines_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::AttribsPerPage]=QString::number(attribs_per_page_spb->value()); config_params[Attributes::Configuration][Attributes::ExtAttribsPerPage]=QString::number(ext_attribs_per_page_spb->value()); config_params[Attributes::Configuration][Attributes::ShowCanvasGrid]=(ObjectsScene::isShowGrid() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::ShowPageDelimiters]=(ObjectsScene::isShowPageDelimiters() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::AlignObjsToGrid]=(ObjectsScene::isAlignObjectsToGrid() ? Attributes::True : QString()); unity_cmb->setCurrentIndex(UnitMilimeters); config_params[Attributes::Configuration][Attributes::PaperMargin]=QString("%1,%2,%3,%4").arg(left_marg->value()) .arg(top_marg->value()) .arg(right_marg->value()) .arg(bottom_marg->value()); if(paper_cmb->currentIndex()!=paper_cmb->count()-1) config_params[Attributes::Configuration][Attributes::PaperCustomSize]=QString(); else config_params[Attributes::Configuration][Attributes::PaperCustomSize]=QString("%1,%2").arg(width_spb->value()).arg(height_spb->value()); config_params[Attributes::Configuration][Attributes::PrintPgNum]=(print_pg_num_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::PrintGrid]=(print_grid_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::HideExtAttribs]=(hide_ext_attribs_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::HideRelName]=(hide_rel_name_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::HideTableTags]=(hide_table_tags_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::CodeFont]=font_cmb->currentText(); config_params[Attributes::Configuration][Attributes::CodeFontSize]=QString::number(font_size_spb->value()); config_params[Attributes::Configuration][Attributes::DisplayLineNumbers]=(disp_line_numbers_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::HighlightLines]=(hightlight_lines_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::LineNumbersColor]=line_numbers_cp->getColor(0).name(); config_params[Attributes::Configuration][Attributes::LineNumbersBgColor]=line_numbers_bg_cp->getColor(0).name(); config_params[Attributes::Configuration][Attributes::LineHighlightColor]=line_highlight_cp->getColor(0).name(); config_params[Attributes::Configuration][Attributes::SourceEditorApp]=source_editor_edt->text(); config_params[Attributes::Configuration][Attributes::SourceEditorArgs]=source_editor_args_edt->text(); config_params[Attributes::Configuration][Attributes::UiLanguage]=ui_language_cmb->currentData().toString(); config_params[Attributes::Configuration][Attributes::CompactView]=(BaseObjectView::isCompactViewEnabled() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::SaveRestoreGeometry]=(save_restore_geometry_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::LowVerbosity]=(low_verbosity_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::EscapeComment]=(escape_comments_chk->isChecked() ? Attributes::True : QString()); config_params[Attributes::Configuration][Attributes::File]=QString(); config_params[Attributes::Configuration][Attributes::RecentModels]=QString(); itr=config_params.begin(); itr_end=config_params.end(); config_params[Attributes::Configuration][Attributes::DockWidgets]=QString(); config_params[Attributes::Configuration][Attributes::WidgetsGeometry]=QString(); config_params[Attributes::Configuration][Attributes::RecentModels]=QString(); config_params[Attributes::Configuration][Attributes::File]=QString(); while(itr!=itr_end) { //Checking if the current attribute is a file to be stored in a tag if((itr->first).contains(QRegExp(QString("(") + Attributes::File + QString(")([0-9]+)")))) { config_params[Attributes::Configuration][Attributes::File]+= schparser.convertCharsToXMLEntities(schparser.getCodeDefinition(file_sch, itr->second)); } //Checking if the current attribute is a file to be stored in a tag else if(recent_mdl_idx < MaxRecentModels && (itr->first).contains(QRegExp(QString("(") + Attributes::Recent + QString(")([0-9]+)")))) { config_params[Attributes::Configuration][Attributes::RecentModels]+= schparser.convertCharsToXMLEntities(schparser.getCodeDefinition(file_sch, itr->second)); recent_mdl_idx++; } else if(itr->first==Attributes::Validator || itr->first==Attributes::ObjectFinder || itr->first==Attributes::SqlTool) { schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); config_params[Attributes::Configuration][Attributes::DockWidgets]+= schparser.getCodeDefinition(widget_sch, itr->second); schparser.ignoreUnkownAttributes(false); schparser.ignoreEmptyAttributes(false); } itr++; } if(save_restore_geometry_chk->isChecked()) { for(auto &itr : widgets_geom) { /* Ignoring the validator, objectfinder and sqltool widget ids * In order to avoid the saving of widget geometry of that objects */ if(itr.first==Attributes::Validator || itr.first==Attributes::ObjectFinder || itr.first==Attributes::SqlTool) continue; attribs[Attributes::Id] = itr.first; attribs[Attributes::XPos] = QString::number(itr.second.geometry.left()); attribs[Attributes::YPos] = QString::number(itr.second.geometry.top()); attribs[Attributes::Width] = QString::number(itr.second.geometry.width()); attribs[Attributes::Height] = QString::number(itr.second.geometry.height()); attribs[Attributes::Maximized] = itr.second.maximized ? Attributes::True : QString(); schparser.ignoreUnkownAttributes(true); config_params[Attributes::Configuration][Attributes::WidgetsGeometry]+= schparser.getCodeDefinition(widget_sch, attribs); schparser.ignoreUnkownAttributes(false); } } BaseConfigWidget::saveConfiguration(GlobalAttributes::GeneralConf, config_params); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void GeneralConfigWidget::applyConfiguration(void) { int unit=unity_cmb->currentIndex(); QFont fnt; double fnt_size=config_params[Attributes::Configuration][Attributes::CodeFontSize].toDouble(); if(fnt_size < 5.0) fnt_size=5.0; if(!save_restore_geometry_chk->isChecked()) widgets_geom.clear(); BaseObject::setEscapeComments(escape_comments_chk->isChecked()); unity_cmb->setCurrentIndex(UnitPoint); ObjectsScene::setPaperConfiguration(static_cast(paper_cmb->itemData(paper_cmb->currentIndex()).toInt()), (portrait_rb->isChecked() ? QPrinter::Portrait : QPrinter::Landscape), QRectF(left_marg->value(), top_marg->value(), right_marg->value(), bottom_marg->value()), QSizeF(width_spb->value(), height_spb->value())); unity_cmb->setCurrentIndex(unit); ObjectsScene::setEnableCornerMove(corner_move_chk->isChecked()); ObjectsScene::setInvertRangeSelectionTrigger(invert_rangesel_chk->isChecked()); ObjectsScene::setGridSize(grid_size_spb->value()); ObjectsScene::setGridOptions(config_params[Attributes::Configuration][Attributes::ShowCanvasGrid]==Attributes::True, config_params[Attributes::Configuration][Attributes::AlignObjsToGrid]==Attributes::True, config_params[Attributes::Configuration][Attributes::ShowPageDelimiters]==Attributes::True); OperationList::setMaximumSize(oplist_size_spb->value()); BaseTableView::setHideExtAttributes(hide_ext_attribs_chk->isChecked()); BaseTableView::setHideTags(hide_table_tags_chk->isChecked()); BaseTableView::setAttributesPerPage(BaseTable::AttribsSection, attribs_per_page_spb->value()); BaseTableView::setAttributesPerPage(BaseTable::ExtAttribsSection, ext_attribs_per_page_spb->value()); RelationshipView::setHideNameLabel(hide_rel_name_chk->isChecked()); RelationshipView::setCurvedLines(use_curved_lines_chk->isChecked()); ModelWidget::setSaveLastCanvasPosition(save_last_pos_chk->isChecked()); ModelWidget::setRenderSmoothnessDisabled(disable_smooth_chk->isChecked()); ModelWidget::setSimplifiedObjectCreation(simple_obj_creation_chk->isChecked()); ModelWidget::setMinimumObjectOpacity(min_obj_opacity_spb->value()); MainWindow::setConfirmValidation(confirm_validation_chk->isChecked()); BaseObjectView::setPlaceholderEnabled(use_placeholders_chk->isChecked()); SQLExecutionWidget::setSQLHistoryMaxLength(history_max_length_spb->value()); fnt.setFamily(config_params[Attributes::Configuration][Attributes::CodeFont]); fnt.setPointSizeF(fnt_size); NumberedTextEditor::setLineNumbersVisible(disp_line_numbers_chk->isChecked()); NumberedTextEditor::setLineHighlightColor(line_highlight_cp->getColor(0)); NumberedTextEditor::setHighlightLines(hightlight_lines_chk->isChecked()); NumberedTextEditor::setDefaultFont(fnt); NumberedTextEditor::setSourceEditorApp(source_editor_edt->text()); NumberedTextEditor::setSourceEditorAppArgs(source_editor_args_edt->text()); LineNumbersWidget::setColors(line_numbers_cp->getColor(0), line_numbers_bg_cp->getColor(0)); SyntaxHighlighter::setDefaultFont(fnt); ModelDatabaseDiffForm::setLowVerbosity(low_verbosity_chk->isChecked()); DatabaseImportForm::setLowVerbosity(low_verbosity_chk->isChecked()); ModelExportForm::setLowVerbosity(low_verbosity_chk->isChecked()); } void GeneralConfigWidget::restoreDefaults(void) { try { BaseConfigWidget::restoreDefaults(GlobalAttributes::GeneralConf, false); BaseConfigWidget::restoreDefaults(GlobalAttributes::XMLHighlightConf, true); BaseConfigWidget::restoreDefaults(GlobalAttributes::SQLHighlightConf, true); BaseConfigWidget::restoreDefaults(GlobalAttributes::UiStyleConf, true); this->loadConfiguration(); this->applyConfiguration(); setConfigurationChanged(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void GeneralConfigWidget::convertMarginUnity(void) { static int prev_unity=UnitMilimeters; double conv_factor[]={1.0, 2.83, 0.04, 0.1}, left, right, top, bottom, width, height; left=left_marg->value() / conv_factor[prev_unity]; right=right_marg->value() / conv_factor[prev_unity]; bottom=bottom_marg->value() / conv_factor[prev_unity]; top=top_marg->value() / conv_factor[prev_unity]; width=width_spb->value() / conv_factor[prev_unity]; height=height_spb->value() / conv_factor[prev_unity]; left_marg->setValue(left * conv_factor[unity_cmb->currentIndex()]); right_marg->setValue(right * conv_factor[unity_cmb->currentIndex()]); bottom_marg->setValue(bottom * conv_factor[unity_cmb->currentIndex()]); top_marg->setValue(top * conv_factor[unity_cmb->currentIndex()]); width_spb->setValue(width * conv_factor[unity_cmb->currentIndex()]); height_spb->setValue(height * conv_factor[unity_cmb->currentIndex()]); prev_unity=unity_cmb->currentIndex(); } void GeneralConfigWidget::updateFontPreview(void) { QFont fnt; fnt=font_cmb->currentFont(); fnt.setPointSizeF(font_size_spb->value()); NumberedTextEditor::setDefaultFont(fnt); NumberedTextEditor::setLineNumbersVisible(disp_line_numbers_chk->isChecked()); NumberedTextEditor::setLineHighlightColor(line_highlight_cp->getColor(0)); NumberedTextEditor::setHighlightLines(hightlight_lines_chk->isChecked()); NumberedTextEditor::setTabWidth(tab_width_chk->isChecked() ? tab_width_spb->value() : 0); LineNumbersWidget::setColors(line_numbers_cp->getColor(0), line_numbers_bg_cp->getColor(0)); font_preview_txt->setReadOnly(false); font_preview_txt->updateLineNumbersSize(); font_preview_txt->updateLineNumbers(); font_preview_txt->highlightCurrentLine(); font_preview_txt->setReadOnly(true); setConfigurationChanged(true); } void GeneralConfigWidget::selectPaperSize(void) { bool visible=paper_cmb->currentIndex()==paper_cmb->count()-1; custom_lbl->setVisible(visible); width_lbl->setVisible(visible); height_lbl->setVisible(visible); width_spb->setVisible(visible); height_spb->setVisible(visible); } void GeneralConfigWidget::selectSourceEditor(void) { QFileDialog sel_editor_dlg; sel_editor_dlg.setFileMode(QFileDialog::ExistingFile); sel_editor_dlg.setNameFilter(trUtf8("All files (*.*)")); sel_editor_dlg.setModal(true); sel_editor_dlg.setWindowTitle(trUtf8("Load file")); sel_editor_dlg.setAcceptMode(QFileDialog::AcceptOpen); sel_editor_dlg.exec(); if(sel_editor_dlg.result()==QDialog::Accepted) source_editor_edt->setText(sel_editor_dlg.selectedFiles().at(0)); } void GeneralConfigWidget::resetDialogsSizes(void) { Messagebox msg_box; msg_box.show(trUtf8("This action will reset all dialogs to their default size and positions on the screen! Do you really want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result() == QDialog::Accepted) widgets_geom.clear(); } pgmodeler-0.9.2/libpgmodeler_ui/src/generalconfigwidget.h000066400000000000000000000066531360462764600236410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class GeneralConfigWidget \brief Implements the operations to manage general configurations. */ #ifndef GENERAL_CONFIG_WIDGET_H #define GENERAL_CONFIG_WIDGET_H #include "ui_generalconfigwidget.h" #include "baseconfigwidget.h" #include "messagebox.h" #include "hinttextwidget.h" #include "colorpickerwidget.h" #include "numberedtexteditor.h" class GeneralConfigWidget: public BaseConfigWidget, public Ui::GeneralConfigWidget { private: Q_OBJECT /* This simple struct is used to store the widgets geometry and maximized state * in order to save this info to configuration file being possible to restore * it when reloading the application */ struct WidgetState { QRect geometry; bool maximized; WidgetState() { maximized = false; } }; QWidgetList child_wgts; NumberedTextEditor *font_preview_txt; static map widgets_geom; static map config_params; static constexpr unsigned UnitMilimeters=0, UnitPoint=1, UnitInches=2, UnitCentimeters=3; HintTextWidget *simp_obj_creation_ht, *confirm_validation_ht, *corner_move_ht, *save_last_pos_ht, *invert_rangesel_ht, *disable_smooth_ht, *hide_ext_attribs_ht, *hide_table_tags_ht, *hide_rel_name_ht, *code_completion_ht, *use_placeholders_ht, *min_obj_opacity_ht, *autosave_ht, *op_history_ht, *ui_language_ht, *grid_size_ht, *use_curved_lines_ht, *max_result_rows_ht, *attribs_per_page_ht, *reduce_verbosity_ht, *escape_comments_ht; ColorPickerWidget *line_numbers_cp, *line_numbers_bg_cp, *line_highlight_cp; public: //! \brief Maximum number of files listed as recent models static constexpr int MaxRecentModels=15; GeneralConfigWidget(QWidget * parent = nullptr); void saveConfiguration(void); void loadConfiguration(void); static void addConfigurationParam(const QString ¶m, const attribs_map &attribs); static void removeConfigurationParam(const QRegExp ¶m_reg); static map getConfigurationParams(void); /*! \brief Returns a single value of a configuration param in the specified section id. Section id can be , , or */ static QString getConfigurationParam(const QString §ion_id, const QString ¶m_name); static void saveWidgetGeometry(QWidget *widget, const QString &custom_wgt_name = QString()); static bool restoreWidgetGeometry(QWidget *widget, const QString &custom_wgt_name = QString()); public slots: void applyConfiguration(void); void restoreDefaults(void); void selectPaperSize(void); void selectSourceEditor(void); private slots: void convertMarginUnity(void); void updateFontPreview(void); void resetDialogsSizes(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/genericsqlwidget.cpp000066400000000000000000000220571360462764600235210ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "genericsqlwidget.h" const QRegExp GenericSQLWidget::AttrDelimRegexp = QRegExp(QString("(\\%1)+|(\\%2)+") .arg(SchemaParser::CharIniAttribute) .arg(SchemaParser::CharEndAttribute)); GenericSQLWidget::GenericSQLWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::GenericSql) { vector types; Ui_GenericSQLWidget::setupUi(this); configureFormLayout(genericsql_grid, ObjectType::GenericSql); ref_name_ht = new HintTextWidget(ref_name_hint, this); ref_name_ht->setText(ref_name_edt->statusTip()); use_signature_ht = new HintTextWidget(use_signature_hint, this); use_signature_ht->setText(use_signature_chk->statusTip()); format_name_ht = new HintTextWidget(format_name_hint, this); format_name_ht->setText(format_name_chk->statusTip()); definition_txt = PgModelerUiNs::createNumberedTextEditor(attribs_tbw->widget(0), true); definition_hl = new SyntaxHighlighter(definition_txt); definition_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); definition_cp=new CodeCompletionWidget(definition_txt, true); comment_edt->setVisible(false); comment_lbl->setVisible(false); preview_txt = PgModelerUiNs::createNumberedTextEditor(attribs_tbw->widget(2), false); preview_txt->setReadOnly(true); preview_hl = new SyntaxHighlighter(preview_txt); preview_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); attribs_tbw->widget(0)->layout()->setContentsMargins(4,4,4,4); attribs_tbw->widget(0)->layout()->addWidget(definition_txt); attribs_tbw->widget(2)->layout()->setContentsMargins(4,4,4,4); attribs_tbw->widget(2)->layout()->addWidget(preview_txt); // Configuring the object types accepted by object references types = BaseObject::getObjectTypes(false, { ObjectType::Database, ObjectType::GenericSql, ObjectType::Permission, ObjectType::Relationship, ObjectType::Tag, ObjectType::Textbox }); types.push_back(ObjectType::Column); object_sel = new ObjectSelectorWidget(types, true, this); objects_refs_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons, true, this); references_grid->addWidget(object_sel, 0, 1, 1, 1); references_grid->addWidget(objects_refs_tab, 2, 0, 1, 2); objects_refs_tab->setColumnCount(5); objects_refs_tab->setHeaderLabel(trUtf8("Ref. name"), 0); objects_refs_tab->setHeaderIcon(QIcon(PgModelerUiNs::getIconPath("uid")), 0); objects_refs_tab->setHeaderLabel(trUtf8("Object"), 1); objects_refs_tab->setHeaderIcon(QIcon(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(ObjectType::Table))), 1); objects_refs_tab->setHeaderLabel(trUtf8("Type"), 2); objects_refs_tab->setHeaderIcon(QIcon(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(ObjectType::Type))), 2); objects_refs_tab->setHeaderLabel(trUtf8("Signature"), 3); objects_refs_tab->setHeaderLabel(trUtf8("Format name"), 4); setMinimumSize(700, 500); connect(object_sel, &ObjectSelectorWidget::s_selectorChanged, [&](bool selected){ sel_obj_icon_lbl->setPixmap(selected ? PgModelerUiNs::getIconPath(object_sel->getSelectedObject()->getSchemaName()) : QPixmap()); sel_obj_icon_lbl->setToolTip(selected ? object_sel->getSelectedObject()->getTypeName() : QString()); }); connect(objects_refs_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addObjectReference(int))); connect(objects_refs_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editObjectReference(int))); connect(objects_refs_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(updateObjectReference(int))); connect(objects_refs_tab, &ObjectsTableWidget::s_rowAboutToRemove, [&](int row){ QString ref_name = objects_refs_tab->getCellText(row, 0); dummy_gsql.removeObjectReference(ref_name); }); connect(objects_refs_tab, &ObjectsTableWidget::s_rowsRemoved, [&](){ dummy_gsql.removeObjectReferences(); }); connect(attribs_tbw, &QTabWidget::currentChanged, [&](int idx){ if(idx == attribs_tbw->count() - 1) updateCodePreview(); }); } void GenericSQLWidget::setAttributes(DatabaseModel *model, OperationList *op_list, GenericSQL *genericsql) { BaseObjectWidget::setAttributes(model, op_list, genericsql); if(genericsql) { dummy_gsql = *genericsql; definition_txt->setPlainText(genericsql->getDefinition()); objects_refs_tab->blockSignals(true); for(auto &ref : genericsql->getObjectsReferences()) { objects_refs_tab->addRow(); showObjectReferenceData(objects_refs_tab->getRowCount() - 1, ref.object, ref.ref_name, ref.use_signature, ref.format_name); } objects_refs_tab->blockSignals(false); } object_sel->setModel(model); definition_cp->configureCompletion(model, definition_hl); } void GenericSQLWidget::addObjectReference(int row) { try { QString ref_name = ref_name_edt->text().remove(AttrDelimRegexp); BaseObject *object = object_sel->getSelectedObject(); bool use_signature = use_signature_chk->isChecked(), format_name = format_name_chk->isChecked(); dummy_gsql.addObjectReference(object, ref_name, use_signature, format_name); showObjectReferenceData(row, object, ref_name, use_signature, format_name); clearObjectReferenceForm(); } catch(Exception &e) { objects_refs_tab->blockSignals(true); objects_refs_tab->removeRow(row); objects_refs_tab->blockSignals(false); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void GenericSQLWidget::editObjectReference(int row) { ref_name_edt->setText(objects_refs_tab->getCellText(row, 0)); use_signature_chk->setChecked(objects_refs_tab->getCellText(row, 3) == trUtf8("Yes")); format_name_chk->setChecked(objects_refs_tab->getCellText(row, 4) == trUtf8("Yes")); object_sel->setSelectedObject(reinterpret_cast(objects_refs_tab->getRowData(row).value())); } void GenericSQLWidget::updateObjectReference(int row) { QString ref_name = objects_refs_tab->getCellText(row, 0), new_ref_name = ref_name_edt->text().remove(AttrDelimRegexp); BaseObject *object = object_sel->getSelectedObject(); bool use_signature = use_signature_chk->isChecked(), format_name = format_name_chk->isChecked(); try { dummy_gsql.updateObjectReference(ref_name, object, new_ref_name, use_signature, format_name); showObjectReferenceData(row, object, new_ref_name, use_signature, format_name); clearObjectReferenceForm(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void GenericSQLWidget::clearObjectReferenceForm(void) { object_sel->clearSelector(); ref_name_edt->clear(); use_signature_chk->setChecked(false); format_name_chk->setChecked(false); objects_refs_tab->clearSelection(); } void GenericSQLWidget::updateCodePreview(void) { try { if(!name_edt->text().isEmpty() && !definition_txt->toPlainText().isEmpty()) { if(!name_edt->text().isEmpty()) dummy_gsql.setName(name_edt->text()); dummy_gsql.setDefinition(definition_txt->toPlainText()); dummy_gsql.setCodeInvalidated(true); preview_txt->setPlainText(dummy_gsql.getCodeDefinition(SchemaParser::SqlDefinition)); } else preview_txt->setPlainText(QString("-- %1 --").arg(trUtf8("No object name, SQL code or references defined! Preview unavailable."))); } catch(Exception &e) { preview_txt->setPlainText(QString("/* %1 */").arg(e.getExceptionsText())); } } void GenericSQLWidget::showObjectReferenceData(int row, BaseObject *object, const QString &ref_name, bool use_signature, bool format_name) { objects_refs_tab->setCellText(ref_name, row, 0); objects_refs_tab->setCellText(use_signature ? object->getSignature(format_name) : object->getName(format_name), row, 1); objects_refs_tab->setCellText(object->getTypeName(), row, 2); objects_refs_tab->setCellText(use_signature ? trUtf8("Yes") : trUtf8("No"), row, 3); objects_refs_tab->setCellText(format_name ? trUtf8("Yes") : trUtf8("No"), row, 4); objects_refs_tab->setRowData(QVariant::fromValue(reinterpret_cast(object)), row); } void GenericSQLWidget::applyConfiguration(void) { try { GenericSQL *genericsql=nullptr; startConfiguration(); genericsql=dynamic_cast(this->object); dummy_gsql.setDefinition(definition_txt->toPlainText()); *genericsql = dummy_gsql; BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/genericsqlwidget.h000066400000000000000000000046301360462764600231630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class GenericSQLWidget \brief Implements the operations to create/edit generic sql objects via form. */ #ifndef GENERIC_SQL_WIDGET_H #define GENERIC_SQL_WIDGET_H #include "ui_genericsqlwidget.h" #include "baseobjectwidget.h" #include "codecompletionwidget.h" #include "objectstablewidget.h" #include "objectselectorwidget.h" #include "hinttextwidget.h" class GenericSQLWidget: public BaseObjectWidget, public Ui::GenericSQLWidget { private: Q_OBJECT HintTextWidget *ref_name_ht, *use_signature_ht, *format_name_ht; NumberedTextEditor *definition_txt, *preview_txt; SyntaxHighlighter *definition_hl, *preview_hl; CodeCompletionWidget *definition_cp; ObjectsTableWidget *objects_refs_tab; ObjectSelectorWidget *object_sel; /*! \brief This dummy object is used to generated the code preview while the user changes the fields * in form. Once the dummy is configure it is copied to the real object being handled by the form (this->object) */ GenericSQL dummy_gsql; //! \brief A regular expression used to remove attribute/reference delimiters {} from the names of configured references static const QRegExp AttrDelimRegexp; void showObjectReferenceData(int row, BaseObject *object, const QString &ref_name, bool use_signature, bool format_name); public: GenericSQLWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, GenericSQL *genericsql=nullptr); public slots: void applyConfiguration(void); private slots: void updateCodePreview(void); void addObjectReference(int row); void editObjectReference(int row); void updateObjectReference(int row); void clearObjectReferenceForm(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/hinttextwidget.cpp000066400000000000000000000105751360462764600232360ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "hinttextwidget.h" #include #include #include "pgmodeleruins.h" HintTextWidget::HintTextWidget(QWidget *btn_parent, QWidget *parent): QWidget(parent) { if(!btn_parent) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); QHBoxLayout *layout=new QHBoxLayout(btn_parent); QGraphicsDropShadowEffect *shadow=nullptr; Ui_HintTextWidget::setupUi(this); this->setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); hint_tb=new QToolButton(this); hint_tb->setCheckable(true); hint_tb->setToolButtonStyle(Qt::ToolButtonIconOnly); hint_tb->setIcon(QPixmap(PgModelerUiNs::getIconPath("help"))); shadow=new QGraphicsDropShadowEffect(this); shadow->setOffset(5,5); shadow->setBlurRadius(30); this->setGraphicsEffect(shadow); layout->setContentsMargins(0,0,0,0); layout->addWidget(hint_tb); btn_parent->setLayout(layout); this->setVisible(false); text_lbl->installEventFilter(this); PgModelerUiNs::configureWidgetFont(text_lbl, PgModelerUiNs::MediumFontFactor); parent->installEventFilter(this); setIconSize(SmallIcon); connect(hint_tb, SIGNAL(toggled(bool)), this, SLOT(setVisible(bool))); } void HintTextWidget::setVisible(bool value) { if(value) { setWidgetPosition(); text_lbl->setFocus(); } QWidget::setVisible(value); } void HintTextWidget::setWidgetPosition(void) { QPoint pos=hint_tb->mapToGlobal(hint_tb->pos()), new_pos; QWidget *parent_wgt=qobject_cast(this->parent()); int right_pos=0, bottom_pos=0; pos.setX(pos.x() - 5); pos.setY(pos.y() + hint_tb->height() - 2); new_pos=parent_wgt->mapFromGlobal(pos); //Adjusting the hint position if the current pos extrapolates the parent's rect right_pos=new_pos.x() + this->width(); if(right_pos > parent_wgt->width()) new_pos.setX(new_pos.x() - (right_pos - parent_wgt->width()) - (hint_tb->width()/2)); bottom_pos=new_pos.y() + this->height(); if(bottom_pos > parent_wgt->height()) new_pos.setY(new_pos.y() - (hint_tb->height() + this->height())); this->move(new_pos); } void HintTextWidget::setText(const QString &text) { QFontMetrics f=text_lbl->fontMetrics(); QString txt=text; QRect ret; QSize txt_size, max_size; txt.replace(QRegExp(QString("(<)(br)(/)?(>)")), QString("\n")); txt.remove(QRegExp(QString("(<)(/)?([a-z]|[A-Z])+(>)"))); ret=f.boundingRect(0,0, this->maximumWidth(), this->maximumHeight(), Qt::TextWordWrap | Qt::AlignLeft | Qt::AlignTop , txt); txt_size=QSize(ret.size().width() + 15, ret.size().height() + 15); max_size=txt_size; max_size.setWidth(max_size.width() * 1.025); max_size.setHeight(max_size.height() * 1.05); text_lbl->setMargin(5); text_lbl->setText(text); text_lbl->setMaximumSize(max_size); text_lbl->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred); this->setMinimumSize(txt_size); this->adjustSize(); } void HintTextWidget::setIconSize(unsigned icon_sz) { if(icon_sz==0) icon_sz=SmallIcon; else if(icon_sz > LargeIcon) icon_sz=LargeIcon; hint_tb->setMaximumSize(icon_sz + 8, icon_sz + 8); hint_tb->setIconSize(QSize(icon_sz, icon_sz)); } QString HintTextWidget::getText(void) { return(text_lbl->text()); } bool HintTextWidget::eventFilter(QObject *object, QEvent *event) { //Close the hint when it text lost its focus if(object==text_lbl && (event->type()==QEvent::MouseButtonDblClick || event->type()==QEvent::FocusOut)) { hint_tb->setChecked(false); return(true); } //Reconfigures the popup position when the parent is resized else if(object==this->parent() && event->type()==QEvent::Resize) setWidgetPosition(); return(QWidget::eventFilter(object, event)); } void HintTextWidget::showEvent(QShowEvent *) { this->activateWindow(); this->raise(); } pgmodeler-0.9.2/libpgmodeler_ui/src/hinttextwidget.h000066400000000000000000000032431360462764600226750ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class HintTextWidget \brief Styled "what's this" widget. Since QWhatsThis can't be handled with style sheets this widget comes as a substitute to it. */ #ifndef HINT_TEXT_WIDGET_H #define HINT_TEXT_WIDGET_H #include #include #include #include "ui_hinttextwidget.h" #include "exception.h" class HintTextWidget: public QWidget, public Ui::HintTextWidget { private: Q_OBJECT //! \brief Tool button installed on the parent in order to trigger the hint popup QToolButton *hint_tb; bool eventFilter(QObject *object, QEvent *event); void showEvent(QShowEvent *); public: static constexpr unsigned SmallIcon=16, MediumIcon=24, LargeIcon=32; HintTextWidget(QWidget *btn_parent, QWidget *parent); public slots: void setVisible(bool value); void setWidgetPosition(void); void setText(const QString &text); void setIconSize(unsigned icon_sz); QString getText(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/htmlitemdelegate.cpp000066400000000000000000000043671360462764600235030ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "htmlitemdelegate.h" #include #include HtmlItemDelegate::HtmlItemDelegate(QObject *parent) : PlainTextItemDelegate(parent, true) { } HtmlItemDelegate::~HtmlItemDelegate(void) { } void HtmlItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QString text=index.data().toString(); painter->save(); QStyledItemDelegate::paint(painter, option, index); if(text.contains(QRegExp("(<)(\\/)?(.+)((>)|(\\/>))(\n)?"))) { static QTextDocument doc; static QRect rect; static QColor bg_color; static int dy = 0; text.replace(QString("\n"), QString("
")); rect.setTop(option.rect.top()); rect.setLeft(option.rect.left() + option.decorationSize.width() + 5); rect.setSize(option.rect.size()); //Painting the correct background color according to the item state if((option.state & QStyle::State_Selected) == QStyle::State_Selected) //Selected bg_color=option.palette.color(QPalette::Highlight); else if(option.features==QStyleOptionViewItem::Alternate) //Alternate color bg_color=option.palette.color(QPalette::AlternateBase); else //Base color bg_color=option.palette.color(QPalette::Base); //Repaint the text area painter->fillRect(rect, bg_color); //Set the text to a html document instance and draw it to the painter doc.setHtml(text); dy = abs(option.rect.height() - option.decorationSize.height()) / 2; painter->translate(rect.topLeft() - QPoint(0, dy)); doc.drawContents(painter); } painter->restore(); } pgmodeler-0.9.2/libpgmodeler_ui/src/htmlitemdelegate.h000066400000000000000000000024431360462764600231410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class HtmlItemDelegate \brief Implements a custom item delegate used in treewidget to paint items that contains html as text */ #ifndef HTML_ITEM_DELEGATE_H #define HTML_ITEM_DELEGATE_H #include #include #include "plaintextitemdelegate.h" class HtmlItemDelegate : public PlainTextItemDelegate { private: Q_OBJECT public: HtmlItemDelegate(QObject * parent = nullptr); ~HtmlItemDelegate(void); protected: virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/indexwidget.cpp000066400000000000000000000130541360462764600224710ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "indexwidget.h" IndexWidget::IndexWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Index) { try { QStringList list; QGridLayout *grid=nullptr; map > fields_map; map > values_map; QFrame *frame=nullptr; Ui_IndexWidget::setupUi(this); predicate_hl=new SyntaxHighlighter(predicate_txt, false, true); predicate_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); elements_tab = new ElementsTableWidget(this); grid=new QGridLayout; grid->setContentsMargins(4,4,4,4); grid->addWidget(elements_tab,0,0); tabWidget->widget(1)->setLayout(grid); configureFormLayout(index_grid, ObjectType::Index); IndexingType::getTypes(list); indexing_cmb->addItems(list); fields_map[BaseObjectWidget::generateVersionsInterval(BaseObjectWidget::AfterVersion, PgSqlVersions::PgSqlVersion92)].push_back(buffering_chk); fields_map[BaseObjectWidget::generateVersionsInterval(BaseObjectWidget::AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(indexing_lbl); values_map[indexing_lbl].push_back(~IndexingType(IndexingType::Brin)); frame=BaseObjectWidget::generateVersionWarningFrame(fields_map, &values_map); frame->setParent(this); grid=dynamic_cast(tabWidget->widget(0)->layout()); grid->addWidget(frame, grid->count(), 0, 1, 5); connect(indexing_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(selectIndexingType(void))); connect(fill_factor_chk, SIGNAL(toggled(bool)), fill_factor_sb, SLOT(setEnabled(bool))); //connect(elements_tab, SIGNAL(s_elementHandled(int)), this, SLOT(enableSortingOptions())); configureTabOrder(); selectIndexingType(); setMinimumSize(570, 550); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void IndexWidget::selectIndexingType(void) { fast_update_chk->setEnabled(IndexingType(indexing_cmb->currentText())==IndexingType::Gin); buffering_chk->setEnabled(IndexingType(indexing_cmb->currentText())==IndexingType::Gist); fill_factor_sb->setEnabled(fill_factor_chk->isChecked() && fill_factor_chk->isEnabled()); } /*void IndexWidget::enableSortingOptions(void) { elements_tab->sorting_chk->setEnabled(IndexingType(indexing_cmb->currentText())==IndexingType::btree); elements_tab->ascending_rb->setEnabled(elements_tab->sorting_chk->isEnabled()); elements_tab->descending_rb->setEnabled(elements_tab->sorting_chk->isEnabled()); elements_tab->nulls_first_chk->setEnabled(elements_tab->sorting_chk->isEnabled()); if(!elements_tab->sorting_chk->isEnabled()) { elements_tab->sorting_chk->setChecked(false); elements_tab->nulls_first_chk->setChecked(false); } }*/ void IndexWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseTable *parent_obj, Index *index) { vector idx_elems; if(!parent_obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, index, parent_obj); if(index) { idx_elems = index->getIndexElements(); indexing_cmb->setCurrentIndex(indexing_cmb->findText(~index->getIndexingType())); fill_factor_chk->setChecked(index->getFillFactor() >= 10); if(fill_factor_chk->isChecked()) fill_factor_sb->setValue(index->getFillFactor()); else fill_factor_sb->setValue(90); concurrent_chk->setChecked(index->getIndexAttribute(Index::Concurrent)); fast_update_chk->setChecked(index->getIndexAttribute(Index::FastUpdate)); unique_chk->setChecked(index->getIndexAttribute(Index::Unique)); buffering_chk->setChecked(index->getIndexAttribute(Index::Buffering)); predicate_txt->setPlainText(index->getPredicate()); selectIndexingType(); } elements_tab->setAttributes(model, parent_obj); elements_tab->setElements(idx_elems); } void IndexWidget::applyConfiguration(void) { try { Index *index=nullptr; vector idx_elems; startConfiguration(); index=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); index->setIndexAttribute(Index::FastUpdate, fast_update_chk->isChecked()); index->setIndexAttribute(Index::Concurrent, concurrent_chk->isChecked()); index->setIndexAttribute(Index::Unique, unique_chk->isChecked()); index->setIndexAttribute(Index::Buffering, buffering_chk->isChecked()); index->setPredicate(predicate_txt->toPlainText().toUtf8()); index->setIndexingType(IndexingType(indexing_cmb->currentText())); if(fill_factor_chk->isChecked()) index->setFillFactor(fill_factor_sb->value()); else index->setFillFactor(0); elements_tab->getElements(idx_elems); index->addIndexElements(idx_elems); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/indexwidget.h000066400000000000000000000030361360462764600221350ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class IndexWidget \brief Implements the operations to create/edit indexes via form. */ #ifndef INDEX_WIDGET_H #define INDEX_WIDGET_H #include "baseobjectwidget.h" #include "ui_indexwidget.h" //#include "objectstablewidget.h" #include "elementstablewidget.h" class IndexWidget: public BaseObjectWidget, public Ui::IndexWidget { private: Q_OBJECT //! \brief Syntax highlighter for predicate SyntaxHighlighter *predicate_hl; //ElementWidget *elements_wgt; ElementsTableWidget *elements_tab; public: IndexWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseTable *parent_obj, Index *index); private slots: void selectIndexingType(void); //void enableSortingOptions(void); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/languagewidget.cpp000066400000000000000000000072071360462764600231500ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "languagewidget.h" LanguageWidget::LanguageWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Language) { try { QFrame *frame=nullptr; Ui_LanguageWidget::setupUi(this); func_handler_sel=nullptr; func_validator_sel=nullptr; func_inline_sel=nullptr; func_handler_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); func_validator_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); func_inline_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); language_grid->addWidget(func_handler_sel,1,1,1,2); language_grid->addWidget(func_validator_sel,2,1,1,2); language_grid->addWidget(func_inline_sel,3,1,1,2); configureFormLayout(language_grid, ObjectType::Language); frame=generateInformationFrame(trUtf8("The functions to be assigned to the language should have, respectively, the following signatures:

Handler Function: language_handler function()
Validator Function: void function(oid)
Inline Function: void function(internal)")); language_grid->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding), language_grid->count()+1, 0, 1, 0); language_grid->addWidget(frame, language_grid->count()+1, 0, 1, 0); frame->setParent(this); configureTabOrder({ trusted_chk, func_handler_sel, func_validator_sel, func_inline_sel }); setMinimumSize(600, 420); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void LanguageWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Language *language) { BaseObjectWidget::setAttributes(model, op_list, language); func_handler_sel->setModel(model); func_validator_sel->setModel(model); func_inline_sel->setModel(model); if(language) { trusted_chk->setChecked(language->isTrusted()); func_handler_sel->setSelectedObject(language->getFunction(Language::HandlerFunc)); func_validator_sel->setSelectedObject(language->getFunction(Language::ValidatorFunc)); func_inline_sel->setSelectedObject(language->getFunction(Language::InlineFunc)); } } void LanguageWidget::applyConfiguration(void) { try { Language *language=nullptr; startConfiguration(); language=dynamic_cast(this->object); language->setTrusted(trusted_chk->isChecked()); language->setFunction(dynamic_cast(func_handler_sel->getSelectedObject()), Language::HandlerFunc); language->setFunction(dynamic_cast(func_validator_sel->getSelectedObject()), Language::ValidatorFunc); language->setFunction(dynamic_cast(func_inline_sel->getSelectedObject()), Language::InlineFunc); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/languagewidget.h000066400000000000000000000025101360462764600226050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class LanguageWidget \brief Implements the operations to create/edit languages via form. */ #ifndef LANGUAGE_WIDGET_H #define LANGUAGE_WIDGET_H #include "baseobjectwidget.h" #include "ui_languagewidget.h" class LanguageWidget: public BaseObjectWidget, public Ui::LanguageWidget { private: Q_OBJECT ObjectSelectorWidget *func_handler_sel, *func_validator_sel, *func_inline_sel; public: LanguageWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Language *language); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/layerswidget.cpp000066400000000000000000000131131360462764600226550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "layerswidget.h" LayersWidget::LayersWidget(QWidget *parent) : QWidget(parent) { setupUi(this); setModel(nullptr); curr_item = nullptr; curr_row = -1; layers_lst->installEventFilter(this); connect(hide_tb, SIGNAL(clicked(bool)), this, SIGNAL(s_visibilityChanged(bool))); connect(layers_lst, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(startLayerRenaming(QListWidgetItem*))); connect(layers_lst, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(updateActiveLayers())); connect(layers_lst, SIGNAL(itemSelectionChanged()), this, SLOT(finishLayerRenaming())); connect(layers_lst, SIGNAL(itemSelectionChanged()), this, SLOT(enableButtons())); connect(add_tb, SIGNAL(clicked(bool)), this, SLOT(addLayer())); connect(remove_tb, SIGNAL(clicked(bool)), this, SLOT(removeLayer(bool))); connect(remove_all_tb, &QToolButton::clicked, [&](){ removeLayer(true); }); } void LayersWidget::updateLayers(void) { QListWidgetItem *item = nullptr; for(auto &layer : model->scene->getLayers()) { item = new QListWidgetItem(layer); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(model->scene->isLayerActive(layer) ? Qt::Checked : Qt::Unchecked); layers_lst->addItem(item); } } bool LayersWidget::eventFilter(QObject *watched, QEvent *event) { if(watched == layers_lst && event->type() == QEvent::KeyPress) { QKeyEvent *k_event = dynamic_cast(event); if(curr_item && (k_event->key() == Qt::Key_Enter || k_event->key() == Qt::Key_Return)) finishLayerRenaming(); else if(!curr_item && k_event->key() == Qt::Key_F2 && layers_lst->currentRow() > 0) startLayerRenaming(layers_lst->currentItem()); } return(false); } void LayersWidget::updateActiveLayers(void) { QStringList active_layers; QListWidgetItem *item = nullptr; for(int row = 0; row < layers_lst->count(); row++) { item = layers_lst->item(row); if(item->checkState() == Qt::Checked) active_layers.push_back(item->text()); } model->scene->setActiveLayers(active_layers); emit s_activeLayersChanged(); } void LayersWidget::removeLayer(bool clear) { QListWidgetItem *item = nullptr; Messagebox msg_box; if(clear) msg_box.show(trUtf8("This action will delete all layers (except the default one) and the objects in them will be moved to the default layer. Do you want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); else msg_box.show(trUtf8("Delete the selected layer will cause objects in it to be moved to the default layer. Do you want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result() == QDialog::Accepted) { if(clear) { model->scene->removeLayers(); while(layers_lst->count() > 1) { item = layers_lst->takeItem(layers_lst->count() - 1); delete(item); } } else if(layers_lst->currentRow() > 0) { item = layers_lst->currentItem(); model->scene->removeLayer(item->text()); layers_lst->takeItem(layers_lst->currentRow()); delete(item); } layers_lst->setCurrentRow(-1); enableButtons(); } } void LayersWidget::enableButtons(void) { remove_tb->setEnabled(layers_lst->currentRow() > 0); remove_all_tb->setEnabled(layers_lst->count() > 1); } void LayersWidget::setVisible(bool value) { QWidget::setVisible(value); emit s_visibilityChanged(value); } void LayersWidget::setModel(ModelWidget *model) { bool enable = model != nullptr; this->model = model; layers_lst->clear(); add_tb->setEnabled(enable); if(model) updateLayers(); } QListWidgetItem *LayersWidget::addLayer(const QString &name) { QListWidgetItem *item = nullptr; QString aux_name = name.isEmpty() ? trUtf8("New layer") : name; aux_name = model->scene->addLayer(aux_name); item = new QListWidgetItem(aux_name); item->setFlags((item->flags() | Qt::ItemIsUserCheckable) ^ Qt::ItemIsEditable); item->setCheckState(Qt::Unchecked); layers_lst->addItem(item); /* Reconfigure the model's menu if we have selected items so the new layer can * appear in the "Move to layer" quick action */ if(!model->scene->selectedItems().isEmpty()) model->configureObjectSelection(); enableButtons(); return(item); } void LayersWidget::startLayerRenaming(QListWidgetItem *item) { if(layers_lst->item(0) != item) { curr_item = item; curr_text = item->text(); curr_row = layers_lst->currentRow(); layers_lst->openPersistentEditor(item); } } void LayersWidget::finishLayerRenaming(void) { if(curr_item) { layers_lst->closePersistentEditor(curr_item); if(curr_item->text().isEmpty()) curr_item->setText(curr_text); else curr_item->setText(model->scene->renameLayer(curr_row, curr_item->text())); curr_item = nullptr; curr_text.clear(); curr_row = -1; /* Reconfigure the model's menu if we have selected items so the renamed layer can * appear in the "Move to layer" quick action */ if(!model->scene->selectedItems().isEmpty()) model->configureObjectSelection(); } } pgmodeler-0.9.2/libpgmodeler_ui/src/layerswidget.h000066400000000000000000000054061360462764600223300ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class LayersWidget \brief Implements the widget that allows the user to handle scene layers */ #ifndef LAYERS_WIDGET_H #define LAYERS_WIDGET_H #include #include "ui_layerswidget.h" #include "modelwidget.h" class LayersWidget : public QWidget, Ui::LayersWidget { private: Q_OBJECT //! \brief Model in which the layer widget will operate on ModelWidget *model; /*! \brief The current selected item in the layers list. We need to store it in a separated attribute * for renaming purposes */ QListWidgetItem *curr_item; //! \brief Stores the current's item text (layer name) to revert the renaming if the user aborts it QString curr_text; //! \brief Stores the current's item row int curr_row; //! \brief Configures the layers listing void updateLayers(void); bool eventFilter(QObject *watched, QEvent *event); public: explicit LayersWidget(QWidget *parent = nullptr); //! \brief Defines the model in which the widget will work void setModel(ModelWidget *model); private slots: //! \brief Add a new item (layer) to the listing. If the provided name is empty a default name is assigned QListWidgetItem *addLayer(const QString &name = QString()); //! \brief Triggers the renaming operation over a item void startLayerRenaming(QListWidgetItem *item); //! \brief Finishes the renaming operation over a item void finishLayerRenaming(void); //! \brief Updates the active layeres on the scene causing a redraw of the items void updateActiveLayers(void); //! \brief Remove a layer from the listing. If 'clear' is true them all layers (except the default) are removed void removeLayer(bool clear = false); //! \brief Enables the control buttons according to the selection on the list void enableButtons(void); public slots: void setVisible(bool value); signals: //! \brief Signal emitted whenever the widget changes its visibility void s_visibilityChanged(bool); //! \brief Signal emitted whenever the current active layers change void s_activeLayersChanged(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/linenumberswidget.cpp000066400000000000000000000110771360462764600237100ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "linenumberswidget.h" #include #include #include "exception.h" QColor LineNumbersWidget::font_color=Qt::lightGray; QColor LineNumbersWidget::bg_color=Qt::black; LineNumbersWidget::LineNumbersWidget(QPlainTextEdit * parent) : QWidget(parent) { if(!parent) throw Exception(ErrorCode::AsgNotAllocattedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); parent_edt = qobject_cast(parent); first_line=line_count=start_sel_pos=0; dy=0; has_selection = false; start_sel_line = -1; connect(parent_edt, SIGNAL(selectionChanged()), this, SLOT(update())); } void LineNumbersWidget::drawLineNumbers(unsigned first_line, unsigned line_count, int dy) { bool update=(first_line!=this->first_line || line_count != this->line_count); if(update) { this->first_line=first_line; this->line_count=line_count; this->dy=dy; this->update(); } } void LineNumbersWidget::setColors(const QColor &font_color, const QColor &bg_color) { LineNumbersWidget::font_color=font_color; LineNumbersWidget::bg_color=bg_color; } void LineNumbersWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); int y = dy, height = 0; unsigned last_line=first_line + line_count; QFont font = painter.font(); unsigned fs_line = 0, ls_line = 0; QTextCursor cursor = parent_edt->textCursor(); if(cursor.hasSelection()) { QTextCursor start = cursor, end = cursor; start.setPosition(cursor.selectionStart(), QTextCursor::MoveAnchor); fs_line = start.blockNumber(); end.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor); ls_line = end.blockNumber(); } //Repaint the widget to clear previous drawn numbers painter.fillRect(event->rect(), bg_color); painter.setPen(font_color); //Draw line numbers for(unsigned lin=first_line; lin < last_line; lin++) { font.setBold(cursor.hasSelection() && lin-1 >= fs_line && lin-1 <= ls_line); height = QFontMetrics(font).height(); painter.setFont(font); if(font.bold()) { painter.setBrush(bg_color.dark(150)); painter.setPen(Qt::transparent); painter.drawRect(QRect(-1, y, this->width() + 1, height)); painter.setPen(font_color.light(180)); } else painter.setPen(font_color); painter.drawText(0, y, this->width(), height, Qt::AlignHCenter, QString::number(lin)); y+=height; } } void LineNumbersWidget::mousePressEvent(QMouseEvent *event) { if(event->buttons() == Qt::LeftButton && !has_selection) { QTextCursor cursor = parent_edt->cursorForPosition(QPoint(0, event->pos().y())); has_selection = true; cursor.select(QTextCursor::LineUnderCursor); parent_edt->setTextCursor(cursor); start_sel_line = cursor.blockNumber(); start_sel_pos = cursor.position(); } } void LineNumbersWidget::mouseMoveEvent(QMouseEvent *event) { if(event->buttons() == Qt::LeftButton && has_selection) { QTextCursor cursor = parent_edt->cursorForPosition(QPoint(0, event->pos().y())), curr_cursor = parent_edt->textCursor(); //If the user wants selects lines below the first if(start_sel_line < cursor.blockNumber()) { cursor.movePosition(QTextCursor::EndOfLine); curr_cursor.setPosition(cursor.position(), QTextCursor::KeepAnchor); parent_edt->setTextCursor(curr_cursor); } //If the user wants selects lines above the first else if(start_sel_line > cursor.blockNumber()) { curr_cursor.setPosition(start_sel_pos); curr_cursor.movePosition(QTextCursor::EndOfLine); curr_cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, curr_cursor.position() - cursor.position()); parent_edt->setTextCursor(curr_cursor); } else { cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); parent_edt->setTextCursor(cursor); } this->update(); } } void LineNumbersWidget::mouseReleaseEvent(QMouseEvent *) { has_selection = false; } QColor LineNumbersWidget::getBackgroundColor(void) { return(LineNumbersWidget::bg_color); } pgmodeler-0.9.2/libpgmodeler_ui/src/linenumberswidget.h000066400000000000000000000042101360462764600233440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class LineNumbersWidget \brief Implements a simple line number widget that expose the current highlighted line in a text editor */ #ifndef LINE_NUMBERS_WIDGET_H #define LINE_NUMBERS_WIDGET_H #include #include class LineNumbersWidget : public QWidget { private: Q_OBJECT QPlainTextEdit *parent_edt; bool has_selection; //! \brief The first line number that must be drawn unsigned first_line, //! \brief The amount of lines to be drawn line_count; //! \brief The y axis increment to start drawn the line number int dy; int start_sel_line, start_sel_pos; //! \brief Font color for drawn line numbers static QColor font_color, //! \brief Widget's background color bg_color; protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *); public: explicit LineNumbersWidget(QPlainTextEdit *parent); /*! \brief Draw the lines starting from 'first_line' and stoping at fisrt_line + line_count -1. The dy param. defines an initial Y translation before drawn lines */ void drawLineNumbers(unsigned first_line, unsigned line_count, int dy); //! \brief Configures the lines for both font and widget's background static void setColors(const QColor &font_color, const QColor &bg_color); static QColor getBackgroundColor(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/mainwindow.cpp000066400000000000000000002170751360462764600223430ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "mainwindow.h" #include "pgmodeleruins.h" #include "bugreportform.h" #include "metadatahandlingform.h" #include "sqlexecutionwidget.h" bool MainWindow::confirm_validation=true; MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) { setupUi(this); mapconfs; map::iterator itr, itr_end; attribs_map attribs; PluginsConfigWidget *plugins_conf_wgt=nullptr; QGridLayout *grid=nullptr; pending_op=NoPendingOp; central_wgt=nullptr; layers_wgt = new LayersWidget(this); layers_wgt->setVisible(false); scene_info_wgt = new SceneInfoWidget(this); QHBoxLayout *hbox = new QHBoxLayout(scene_info_parent); hbox->addWidget(scene_info_wgt); hbox->setContentsMargins(4,4,4,4); scene_info_parent->setLayout(hbox); QToolButton *tool_btn = qobject_cast(control_tb->widgetForAction(action_arrange_objects)); tool_btn->setMenu(&arrange_menu); tool_btn->setPopupMode(QToolButton::InstantPopup); arrange_menu.addAction(trUtf8("Grid"), this, SLOT(arrangeObjects())); arrange_menu.addAction(trUtf8("Hierarchical"), this, SLOT(arrangeObjects())); arrange_menu.addAction(trUtf8("Scattered"), this, SLOT(arrangeObjects())); try { models_tbw->tabBar()->setVisible(false); general_tb->layout()->setContentsMargins(0,0,0,0); central_wgt=new WelcomeWidget(views_stw); grid=new QGridLayout; grid->setContentsMargins(0,0,0,0); grid->setSpacing(0); grid->addWidget(central_wgt, 0, 0); views_stw->widget(WelcomeView)->setLayout(grid); action_welcome->setData(WelcomeView); action_design->setData(DesignView); action_manage->setData(ManageView); sql_tool_wgt=new SQLToolWidget; grid=new QGridLayout; grid->setContentsMargins(0,0,0,0); grid->setSpacing(0); grid->addWidget(sql_tool_wgt, 0, 0); views_stw->widget(ManageView)->setLayout(grid); configuration_form=new ConfigurationForm(nullptr, Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); PgModelerUiNs::resizeDialog(configuration_form); configuration_form->loadConfiguration(); plugins_conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::PluginsConfWgt)); plugins_conf_wgt->installPluginsActions(plugins_menu, this, SLOT(executePlugin(void))); plugins_conf_wgt->initPlugins(this); plugins_menu->setEnabled(!plugins_menu->isEmpty()); action_plugins->setEnabled(!plugins_menu->isEmpty()); action_plugins->setMenu(plugins_menu); action_other_actions->setMenu(&more_actions_menu); confs=GeneralConfigWidget::getConfigurationParams(); itr=confs.begin(); itr_end=confs.end(); //Configuring the widget visibility according to the configurations while(itr!=itr_end) { attribs=itr->second; if(attribs.count(Attributes::Path)!=0) { try { //Storing the file of a previous session if(itr->first.contains(Attributes::File) && !attribs[Attributes::Path].isEmpty()) prev_session_files.push_back(attribs[Attributes::Path]); //Creating the recent models menu else if(itr->first.contains(Attributes::Recent) && !attribs[Attributes::Path].isEmpty()) recent_models.push_back(attribs[Attributes::Path]); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } itr++; } //Enables the action to restore session when there are registered session files action_restore_session->setEnabled(!prev_session_files.isEmpty()); central_wgt->last_session_tb->setEnabled(action_restore_session->isEnabled()); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } try { this->setFocusPolicy(Qt::WheelFocus); model_nav_wgt=new ModelNavigationWidget(this); control_tb->addWidget(model_nav_wgt); control_tb->addSeparator(); control_tb->addAction(action_plugins); dynamic_cast(control_tb->widgetForAction(action_plugins))->setPopupMode(QToolButton::InstantPopup); control_tb->addAction(action_bug_report); control_tb->addAction(action_donate); control_tb->addAction(action_support); control_tb->addAction(action_about); control_tb->addAction(action_update_found); about_wgt=new AboutWidget(this); donate_wgt=new DonateWidget(this); restoration_form=new ModelRestorationForm(nullptr, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); #ifdef NO_UPDATE_CHECK update_notifier_wgt=nullptr; #else update_notifier_wgt=new UpdateNotifierWidget(this); update_notifier_wgt->setVisible(false); #endif oper_list_wgt=new OperationListWidget; model_objs_wgt=new ModelObjectsWidget; overview_wgt=new ModelOverviewWidget; model_valid_wgt=new ModelValidationWidget; obj_finder_wgt=new ObjectFinderWidget; } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } connect(central_wgt->new_tb, SIGNAL(clicked()), this, SLOT(addModel())); connect(central_wgt->open_tb, SIGNAL(clicked()), this, SLOT(loadModel())); connect(central_wgt->last_session_tb, SIGNAL(clicked()), this, SLOT(restoreLastSession())); connect(central_wgt->support_tb, SIGNAL(clicked()), this, SLOT(openSupport())); #ifndef NO_UPDATE_CHECK connect(update_notifier_wgt, SIGNAL(s_updateAvailable(bool)), action_update_found, SLOT(setVisible(bool))); connect(update_notifier_wgt, SIGNAL(s_updateAvailable(bool)), action_update_found, SLOT(setChecked(bool))); connect(update_notifier_wgt, SIGNAL(s_visibilityChanged(bool)), action_update_found, SLOT(setChecked(bool))); connect(action_update_found,SIGNAL(toggled(bool)),this,SLOT(toggleUpdateNotifier(bool))); connect(action_check_update,SIGNAL(triggered()), update_notifier_wgt, SLOT(checkForUpdate())); #endif connect(action_about,SIGNAL(toggled(bool)),this,SLOT(toggleAboutWidget(bool))); connect(about_wgt, SIGNAL(s_visibilityChanged(bool)), action_about, SLOT(setChecked(bool))); connect(action_donate, SIGNAL(toggled(bool)),this,SLOT(toggleDonateWidget(bool))); connect(donate_wgt, SIGNAL(s_visibilityChanged(bool)), action_donate, SLOT(setChecked(bool))); connect(action_restore_session,SIGNAL(triggered(bool)),this,SLOT(restoreLastSession())); connect(action_exit,SIGNAL(triggered(bool)),this,SLOT(close())); connect(action_new_model,SIGNAL(triggered(bool)),this,SLOT(addModel())); connect(action_close_model,SIGNAL(triggered(bool)),this,SLOT(closeModel())); connect(action_fix_model, SIGNAL(triggered(bool)), this, SLOT(fixModel())); connect(action_support,SIGNAL(triggered(bool)),this,SLOT(openSupport())); connect(action_inc_zoom,SIGNAL(triggered(bool)),this,SLOT(applyZoom())); connect(action_dec_zoom,SIGNAL(triggered(bool)),this,SLOT(applyZoom())); connect(action_normal_zoom,SIGNAL(triggered(bool)),this,SLOT(applyZoom())); connect(action_load_model,SIGNAL(triggered(bool)),this,SLOT(loadModel())); connect(action_save_model,SIGNAL(triggered(bool)),this,SLOT(saveModel())); connect(action_save_as,SIGNAL(triggered(bool)),this,SLOT(saveModel())); connect(action_save_all,SIGNAL(triggered(bool)),this,SLOT(saveAllModels())); connect(oper_list_wgt, SIGNAL(s_operationExecuted(void)), this, SLOT(updateDockWidgets(void))); connect(oper_list_wgt, SIGNAL(s_operationListUpdated(void)), this, SLOT(__updateToolsState(void))); connect(action_undo,SIGNAL(triggered(bool)),oper_list_wgt,SLOT(undoOperation(void))); connect(action_redo,SIGNAL(triggered(bool)),oper_list_wgt,SLOT(redoOperation(void))); connect(model_nav_wgt, SIGNAL(s_modelCloseRequested(int)), this, SLOT(closeModel(int))); connect(model_nav_wgt, SIGNAL(s_currentModelChanged(int)), this, SLOT(setCurrentModel())); connect(action_print, SIGNAL(triggered(bool)), this, SLOT(printModel(void))); connect(action_configuration, &QAction::triggered, [&](){ GeneralConfigWidget::restoreWidgetGeometry(configuration_form); configuration_form->exec(); GeneralConfigWidget::saveWidgetGeometry(configuration_form); }); connect(oper_list_wgt, SIGNAL(s_operationExecuted(void)), overview_wgt, SLOT(updateOverview(void))); connect(layers_wgt, SIGNAL(s_activeLayersChanged(void)), overview_wgt, SLOT(updateOverview(void))); connect(configuration_form, SIGNAL(finished(int)), this, SLOT(applyConfigurations(void))); connect(configuration_form, SIGNAL(rejected()), this, SLOT(updateConnections())); connect(configuration_form, &ConfigurationForm::s_invalidateModelsRequested, [&](){ //Forcing the models code invalidation if the user changes the escape comments option for(int idx = 0; idx < models_tbw->count(); idx++) dynamic_cast(models_tbw->widget(idx))->getDatabaseModel()->setCodesInvalidated(); }); connect(&model_save_timer, SIGNAL(timeout(void)), this, SLOT(saveAllModels(void))); connect(action_export, SIGNAL(triggered(bool)), this, SLOT(exportModel(void))); connect(action_import, SIGNAL(triggered(bool)), this, SLOT(importDatabase(void))); connect(action_diff, SIGNAL(triggered(bool)), this, SLOT(diffModelDatabase(void))); connect(action_welcome, SIGNAL(toggled(bool)), this, SLOT(changeCurrentView(bool))); connect(action_design, SIGNAL(toggled(bool)), this, SLOT(changeCurrentView(bool))); connect(action_manage, SIGNAL(toggled(bool)), this, SLOT(changeCurrentView(bool))); connect(action_bug_report, SIGNAL(triggered()), this, SLOT(reportBug())); connect(action_handle_metadata, SIGNAL(triggered(bool)), this, SLOT(handleObjectsMetadata())); connect(model_valid_wgt, &ModelValidationWidget::s_connectionsUpdateRequest, [&](){ updateConnections(true); }); connect(sql_tool_wgt, &SQLToolWidget::s_connectionsUpdateRequest, [&](){ updateConnections(true); }); connect(action_compact_view, SIGNAL(toggled(bool)), this, SLOT(toggleCompactView())); window_title=this->windowTitle() + QString(" ") + GlobalAttributes::PgModelerVersion; #ifdef DEMO_VERSION window_title+=trUtf8(" (Demo)"); #endif this->setWindowTitle(window_title); current_model=nullptr; models_tbw->setVisible(false); model_objs_parent->setVisible(false); oper_list_parent->setVisible(false); obj_finder_parent->setVisible(false); model_valid_parent->setVisible(false); bg_saving_wgt->setVisible(false); about_wgt->setVisible(false); donate_wgt->setVisible(false); models_tbw_parent->lower(); central_wgt->lower(); v_splitter1->lower(); QVBoxLayout *vlayout=new QVBoxLayout; vlayout->setContentsMargins(0,0,0,0); vlayout->addWidget(model_objs_wgt); model_objs_parent->setLayout(vlayout); vlayout=new QVBoxLayout; vlayout->setContentsMargins(0,0,0,0); vlayout->addWidget(oper_list_wgt); oper_list_parent->setLayout(vlayout); QHBoxLayout * hlayout=new QHBoxLayout; hlayout->setContentsMargins(0,0,0,0); hlayout->addWidget(model_valid_wgt); model_valid_parent->setLayout(hlayout); hlayout=new QHBoxLayout; hlayout->setContentsMargins(0,0,0,0); hlayout->addWidget(obj_finder_wgt); obj_finder_parent->setLayout(hlayout); connect(objects_btn, SIGNAL(toggled(bool)), model_objs_parent, SLOT(setVisible(bool))); connect(objects_btn, SIGNAL(toggled(bool)), model_objs_wgt, SLOT(setVisible(bool))); connect(objects_btn, SIGNAL(toggled(bool)), this, SLOT(showRightWidgetsBar(void))); connect(model_objs_wgt, SIGNAL(s_visibilityChanged(bool)), objects_btn, SLOT(setChecked(bool))); connect(model_objs_wgt, SIGNAL(s_visibilityChanged(bool)), this, SLOT(showRightWidgetsBar())); connect(operations_btn, SIGNAL(toggled(bool)), oper_list_parent, SLOT(setVisible(bool))); connect(operations_btn, SIGNAL(toggled(bool)), oper_list_wgt, SLOT(setVisible(bool))); connect(operations_btn, SIGNAL(toggled(bool)), this, SLOT(showRightWidgetsBar(void))); connect(oper_list_wgt, SIGNAL(s_visibilityChanged(bool)), operations_btn, SLOT(setChecked(bool))); connect(oper_list_wgt, SIGNAL(s_visibilityChanged(bool)), this, SLOT(showRightWidgetsBar())); connect(validation_btn, SIGNAL(toggled(bool)), model_valid_parent, SLOT(setVisible(bool))); connect(validation_btn, SIGNAL(toggled(bool)), model_valid_wgt, SLOT(setVisible(bool))); connect(validation_btn, SIGNAL(toggled(bool)), this, SLOT(showBottomWidgetsBar(void))); connect(model_valid_wgt, SIGNAL(s_visibilityChanged(bool)), validation_btn, SLOT(setChecked(bool))); connect(model_valid_wgt, SIGNAL(s_visibilityChanged(bool)), this, SLOT(showBottomWidgetsBar())); connect(find_obj_btn, SIGNAL(toggled(bool)), obj_finder_parent, SLOT(setVisible(bool))); connect(find_obj_btn, SIGNAL(toggled(bool)), obj_finder_wgt, SLOT(setVisible(bool))); connect(find_obj_btn, SIGNAL(toggled(bool)), this, SLOT(showBottomWidgetsBar(void))); connect(obj_finder_wgt, SIGNAL(s_visibilityChanged(bool)), find_obj_btn, SLOT(setChecked(bool))); connect(obj_finder_wgt, SIGNAL(s_visibilityChanged(bool)), this, SLOT(showBottomWidgetsBar())); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), this->main_menu_mb, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), control_tb, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), general_tb, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), models_tbw, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), oper_list_wgt, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), model_objs_wgt, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), obj_finder_wgt, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), models_tbw, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), this, SLOT(stopTimers(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), layers_btn, SLOT(setDisabled(bool))); connect(model_valid_wgt, SIGNAL(s_validationInProgress(bool)), layers_wgt, SLOT(close())); connect(model_valid_wgt, &ModelValidationWidget::s_validationCanceled, [&](){ pending_op=NoPendingOp; }); connect(model_valid_wgt, SIGNAL(s_validationFinished(bool)), this, SLOT(executePendingOperation(bool))); connect(model_valid_wgt, SIGNAL(s_fixApplied()), this, SLOT(removeOperations()), Qt::QueuedConnection); connect(model_valid_wgt, SIGNAL(s_graphicalObjectsUpdated()), model_objs_wgt, SLOT(updateObjectsView()), Qt::QueuedConnection); connect(layers_btn, SIGNAL(toggled(bool)), this, SLOT(toggleLayersWidget(bool))); connect(layers_wgt, SIGNAL(s_visibilityChanged(bool)), layers_btn, SLOT(setChecked(bool))); connect(&tmpmodel_save_timer, SIGNAL(timeout()), this, SLOT(saveTemporaryModels())); models_tbw_parent->resize(QSize(models_tbw_parent->maximumWidth(), models_tbw_parent->height())); //Forcing the splitter that handles the bottom widgets to resize its children to their minimum size v_splitter1->setSizes({500, 250, 500}); showRightWidgetsBar(); showBottomWidgetsBar(); GeneralConfigWidget *conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); confs=conf_wgt->getConfigurationParams(); //If a previous session was restored save the temp models updateConnections(); updateRecentModelsMenu(); configureSamplesMenu(); applyConfigurations(); QList actions=general_tb->actions(); QToolButton *btn=nullptr; QFont font; for(auto &act : actions) { btn=qobject_cast(general_tb->widgetForAction(act)); if(btn) { PgModelerUiNs::configureWidgetFont(btn, static_cast(PgModelerUiNs::MediumFontFactor)); font = btn->font(); font.setBold(true); btn->setFont(font); PgModelerUiNs::createDropShadow(btn); } } #ifdef Q_OS_MAC control_tb->removeAction(action_main_menu); action_main_menu->setEnabled(false); #else plugins_menu->menuAction()->setIconVisibleInMenu(false); main_menu.addMenu(file_menu); main_menu.addMenu(edit_menu); main_menu.addMenu(show_menu); main_menu.addMenu(plugins_menu); main_menu.addMenu(about_menu); main_menu.addSeparator(); main_menu.addAction(action_show_main_menu); action_main_menu->setMenu(&main_menu); dynamic_cast(control_tb->widgetForAction(action_main_menu))->setPopupMode(QToolButton::InstantPopup); connect(action_show_main_menu, SIGNAL(triggered()), this, SLOT(showMainMenu())); connect(action_hide_main_menu, SIGNAL(triggered()), this, SLOT(showMainMenu())); #endif actions=control_tb->actions(); actions.append(general_tb->actions()); for(QAction *act : actions) { if(!act->shortcut().toString().isEmpty()) act->setToolTip(act->toolTip() + QString(" (%1)").arg(act->shortcut().toString())); } try { SQLExecutionWidget::loadSQLHistory(); } catch(Exception &){} #ifndef Q_OS_MAC //Restoring the canvas grid options action_show_grid->setChecked(confs[Attributes::Configuration][Attributes::ShowCanvasGrid]==Attributes::True); action_alin_objs_grade->setChecked(confs[Attributes::Configuration][Attributes::AlignObjsToGrid]==Attributes::True); action_show_delimiters->setChecked(confs[Attributes::Configuration][Attributes::ShowPageDelimiters]==Attributes::True); action_compact_view->setChecked(confs[Attributes::Configuration][Attributes::CompactView]==Attributes::True); ObjectsScene::setGridOptions(action_show_grid->isChecked(), action_alin_objs_grade->isChecked(), action_show_delimiters->isChecked()); //Hiding/showing the main menu bar depending on the retrieved conf main_menu_mb->setVisible(confs[Attributes::Configuration][Attributes::ShowMainMenu]==Attributes::True); if(main_menu_mb->isVisible()) file_menu->addAction(action_hide_main_menu); action_main_menu->setVisible(!main_menu_mb->isVisible()); #endif restoreDockWidgetsSettings(); //Positioning the update notifier widget before showing it (if there is an update) setFloatingWidgetPos(update_notifier_wgt, action_update_found, control_tb, false); action_update_found->setVisible(false); QTimer::singleShot(1000, this, SLOT(restoreTemporaryModels())); //If there's no previuos geometry registered for the mainwindow display it maximized if(!GeneralConfigWidget::restoreWidgetGeometry(this)) this->setWindowState(Qt::WindowMaximized); #ifdef NO_UPDATE_CHECK #warning "NO UPDATE CHECK: Update checking is disabled." #else //Enabling update check at startup if(confs[Attributes::Configuration][Attributes::CheckUpdate]==Attributes::True) QTimer::singleShot(10000, update_notifier_wgt, SLOT(checkForUpdate())); #endif #ifdef DEMO_VERSION #warning "DEMO VERSION: demonstration version startup alert." QTimer::singleShot(5000, this, SLOT(showDemoVersionWarning())); #endif } MainWindow::~MainWindow(void) { ModelWidget *model = nullptr; int idx = 0; /* Destroying models from the last to the first in order * to destroy other objects inside the models in the proper order */ while(models_tbw->count() > 0) { idx = models_tbw->count() - 1; model = dynamic_cast(models_tbw->widget(idx)); models_tbw->removeTab(idx); delete(model); } //This fix the crash on exit at Mac OSX system (but not sure why) (???) file_menu->clear(); delete(restoration_form); delete(overview_wgt); delete(configuration_form); } void MainWindow::restoreTemporaryModels(void) { PgModelerUiNs::resizeDialog(restoration_form); //Restore temporary models (if exists) if(restoration_form->hasTemporaryModels()) { restoration_form->exec(); if(restoration_form->result()==QDialog::Accepted) { ModelWidget *model=nullptr; QString model_file; QStringList tmp_models=restoration_form->getSelectedModels(); while(!tmp_models.isEmpty()) { try { model_file=tmp_models.front(); tmp_models.pop_front(); this->addModel(model_file); //Get the model widget generated from file model=dynamic_cast(models_tbw->widget(models_tbw->count()-1)); //Set the model as modified forcing the user to save when the autosave timer ends model->setModified(true); model->filename.clear(); restoration_form->removeTemporaryModel(model_file); } catch(Exception &e) { //Destroy the temp file if the "keep models" isn't checked if(!restoration_form->keep_models_chk->isChecked()) restoration_form->removeTemporaryModel(model_file); Messagebox msg_box; msg_box.show(e); } } } } } bool MainWindow::isToolButtonsChecked(QHBoxLayout *layout) { int i = 0; bool show = false; QToolButton * btn = nullptr; //This is currently the only way to enumerate widgets inside a layout. //See https://stackoverflow.com/a/27225570/7359123 while(layout && layout->itemAt(i) && !show) { btn = dynamic_cast(layout->itemAt(i)->widget()); if(btn && btn->isChecked()) return(true); i++; } return(false); } void MainWindow::showRightWidgetsBar(void) { right_wgt_bar->setVisible(isToolButtonsChecked(vert_wgts_btns_layout)); } void MainWindow::showBottomWidgetsBar(void) { bottom_wgt_bar->setVisible(isToolButtonsChecked(horiz_wgts_btns_layout)); } void MainWindow::restoreLastSession(void) { /* Loading the files from the previous session. The session will be restored only if pgModeler is not on model restore mode or pgModeler is not opening a model clicked by user o the file manager */ if(QApplication::arguments().size() <= 1 && !prev_session_files.isEmpty() && restoration_form->result()==QDialog::Rejected) { try { qApp->setOverrideCursor(Qt::WaitCursor); while(!prev_session_files.isEmpty()) { this->addModel(prev_session_files.front()); prev_session_files.pop_front(); } action_restore_session->setEnabled(false); central_wgt->last_session_tb->setEnabled(false); qApp->restoreOverrideCursor(); } catch(Exception &e) { qApp->restoreOverrideCursor(); Messagebox msg_box; msg_box.show(e); } } } void MainWindow::stopTimers(bool value) { if(value) { tmpmodel_save_timer.stop(); model_save_timer.stop(); } else { tmpmodel_save_timer.start(); if(model_save_timer.interval() < InfinityInterval) model_save_timer.start(); } } void MainWindow::fixModel(const QString &filename) { ModelFixForm model_fix_form(nullptr, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); connect(&model_fix_form, SIGNAL(s_modelLoadRequested(QString)), this, SLOT(loadModel(QString))); if(!filename.isEmpty()) { QFileInfo fi(filename); model_fix_form.input_file_edt->setText(fi.absoluteFilePath()); model_fix_form.output_file_edt->setText(fi.absolutePath() + GlobalAttributes::DirSeparator + fi.baseName() + QString("_fixed.") + fi.suffix()); } PgModelerUiNs::resizeDialog(&model_fix_form); GeneralConfigWidget::restoreWidgetGeometry(&model_fix_form); model_fix_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&model_fix_form); disconnect(&model_fix_form, nullptr, this, nullptr); } void MainWindow::resizeEvent(QResizeEvent *) { if(central_wgt) { central_wgt->move(bg_widget->width()/2 - central_wgt->width()/2 , bg_widget->height()/2 - central_wgt->height()/2); } action_about->setChecked(false); action_donate->setChecked(false); action_update_found->setChecked(false); toggleLayersWidget(layers_wgt->isVisible()); } void MainWindow::closeEvent(QCloseEvent *event) { //pgModeler will not close when the validation thread is still running if(model_valid_wgt->isValidationRunning()) event->ignore(); else { GeneralConfigWidget *conf_wgt=nullptr; map confs; GeneralConfigWidget::saveWidgetGeometry(this); //Stops the saving timers as well the temp. model saving thread before close pgmodeler model_save_timer.stop(); tmpmodel_save_timer.stop(); plugins_menu->clear(); //If not in demo version there is no confirmation before close the software #ifndef DEMO_VERSION int i=0; QStringList model_names; ModelWidget *model=nullptr; //Checking if there is modified models and ask the user to save them before close the application if(models_tbw->count() > 0) { i=0; while(i < models_tbw->count()) { model=dynamic_cast(models_tbw->widget(i++)); if(model->isModified()) model_names.push_back(QString("%1").arg(model->getDatabaseModel()->getName())); } if(!model_names.isEmpty()) { Messagebox msg_box; msg_box.show(trUtf8("Save modified model(s)"), trUtf8("The following models were modified but not saved: %1. Do you really want to quit pgModeler?").arg(model_names.join(", ")), Messagebox::ConfirmIcon,Messagebox::YesNoButtons); /* If the user rejects the message box the close event will be aborted causing pgModeler not to be finished */ if(msg_box.result()==QDialog::Rejected) event->ignore(); } } #endif if(event->isAccepted()) { int i, count; ModelWidget *model=nullptr; QString param_id; attribs_map attribs; this->overview_wgt->close(); conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); confs=conf_wgt->getConfigurationParams(); attribs[Attributes::CompactView]=action_compact_view->isChecked() ? Attributes::True : QString(); attribs[Attributes::ShowMainMenu]=main_menu_mb->isVisible() ? Attributes::True : QString(); conf_wgt->addConfigurationParam(Attributes::Configuration, attribs); attribs.clear(); count=models_tbw->count(); //Remove the references to old session conf_wgt->removeConfigurationParam(QRegExp(QString("(%1)([0-9])+").arg(Attributes::File))); //Saving the session for(i=0; i < count; i++) { model=dynamic_cast(models_tbw->widget(i)); if(!model->getFilename().isEmpty()) { param_id=QString("%1%2").arg(Attributes::File).arg(i); attribs[Attributes::Id]=param_id; attribs[Attributes::Path]=model->getFilename(); conf_wgt->addConfigurationParam(param_id, attribs); attribs.clear(); } } //Saving recent models list if(!recent_models.isEmpty()) { int i=0; QString param_id; attribs_map attribs; while(!recent_models.isEmpty()) { param_id=QString("%1%2").arg(Attributes::Recent).arg(QString::number(i++).rightJustified(2, '0')); attribs[Attributes::Id]=param_id; attribs[Attributes::Path]=recent_models.front(); conf_wgt->addConfigurationParam(param_id, attribs); attribs.clear(); recent_models.pop_front(); } recent_mdls_menu.clear(); } //Saving dock widgets settings storeDockWidgetsSettings(); conf_wgt->saveConfiguration(); restoration_form->removeTemporaryFiles(); SQLExecutionWidget::saveSQLHistory(); qApp->quit(); } } } void MainWindow::updateConnections(bool force) { ConnectionsConfigWidget *conn_cfg_wgt= dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::ConnectionsConfWgt)); if(force || (!force && (conn_cfg_wgt->isConfigurationChanged() || model_valid_wgt->connections_cmb->count()==0 || sql_tool_wgt->connections_cmb->count()==0))) { if(sender()!=sql_tool_wgt) { ConnectionsConfigWidget::fillConnectionsComboBox(sql_tool_wgt->connections_cmb, true); sql_tool_wgt->clearDatabases(); } if(sender()!=model_valid_wgt) ConnectionsConfigWidget::fillConnectionsComboBox(model_valid_wgt->connections_cmb, true, Connection::OpValidation); } } void MainWindow::saveTemporaryModels(void) { #ifdef DEMO_VERSION #warning "DEMO VERSION: temporary model saving disabled." #else try { ModelWidget *model=nullptr; int count=models_tbw->count(); if(count > 0) { QApplication::setOverrideCursor(Qt::WaitCursor); scene_info_parent->setVisible(false); bg_saving_wgt->setVisible(true); bg_saving_pb->setValue(0); bg_saving_wgt->repaint(); for(int i=0; i < count; i++) { model=dynamic_cast(models_tbw->widget(i)); bg_saving_pb->setValue(((i+1)/static_cast(count)) * 100); if(model->isModified()) model->getDatabaseModel()->saveModel(model->getTempFilename(), SchemaParser::XmlDefinition); } bg_saving_pb->setValue(100); bg_saving_wgt->setVisible(false); scene_info_parent->setVisible(true); QApplication::restoreOverrideCursor(); } tmpmodel_save_timer.start(); } catch(Exception &e) { QApplication::restoreOverrideCursor(); Messagebox msg_box; msg_box.show(e); tmpmodel_save_timer.start(); } #endif } void MainWindow::updateRecentModelsMenu(void) { QAction *act=nullptr; recent_mdls_menu.clear(); recent_models.removeDuplicates(); for(int i=0; i < recent_models.size() && i < GeneralConfigWidget::MaxRecentModels; i++) { act=recent_mdls_menu.addAction(QFileInfo(recent_models[i]).fileName(),this,SLOT(loadModelFromAction(void))); act->setToolTip(recent_models[i]); act->setData(recent_models[i]); } if(!recent_mdls_menu.isEmpty()) { recent_mdls_menu.addSeparator(); recent_mdls_menu.addAction(trUtf8("Clear Menu"), this, SLOT(clearRecentModelsMenu(void))); action_recent_models->setMenu(&recent_mdls_menu); dynamic_cast(control_tb->widgetForAction(action_recent_models))->setPopupMode(QToolButton::InstantPopup); } action_recent_models->setEnabled(!recent_mdls_menu.isEmpty()); central_wgt->recent_tb->setEnabled(action_recent_models->isEnabled()); central_wgt->recent_tb->setMenu(recent_mdls_menu.isEmpty() ? nullptr : &recent_mdls_menu); } void MainWindow::loadModelFromAction(void) { QAction *act=dynamic_cast(sender()); if(act) { QString filename=act->data().toString(); try { qApp->setOverrideCursor(Qt::WaitCursor); addModel(filename); recent_models.push_back(act->data().toString()); updateRecentModelsMenu(); qApp->restoreOverrideCursor(); } catch(Exception &e) { qApp->restoreOverrideCursor(); if(QFileInfo(filename).exists()) showFixMessage(e, filename); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } } void MainWindow::clearRecentModelsMenu(void) { recent_models.clear(); updateRecentModelsMenu(); } void MainWindow::addModel(const QString &filename) { #ifdef DEMO_VERSION #warning "DEMO VERSION: database model creation limit." if(models_tbw->count()==1) throw Exception(trUtf8("The demonstration version can create only `one' instance of database model!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); #endif try { ModelWidget *model_tab=nullptr; QString obj_name, tab_name, str_aux; Schema *public_sch=nullptr; bool start_timers=(models_tbw->count() == 0); //Set a name for the tab widget str_aux=QString("%1").arg(models_tbw->count()); obj_name=QString("model_"); obj_name+=str_aux; tab_name=obj_name; model_tab=new ModelWidget; model_tab->setObjectName(obj_name); //Add the tab to the tab widget obj_name=model_tab->db_model->getName(); models_tbw->blockSignals(true); models_tbw->setUpdatesEnabled(false); models_tbw->addTab(model_tab, obj_name); models_tbw->setCurrentIndex(models_tbw->count()-1); models_tbw->blockSignals(false); models_tbw->currentWidget()->layout()->setContentsMargins(3,3,0,3); //Creating the system objects (public schema and languages C, SQL and pgpgsql) model_tab->db_model->createSystemObjects(filename.isEmpty()); if(!filename.isEmpty()) { try { model_tab->loadModel(filename); models_tbw->setTabToolTip(models_tbw->currentIndex(), filename); //Get the "public" schema and set as system object public_sch=dynamic_cast(model_tab->db_model->getObject(QString("public"), ObjectType::Schema)); if(public_sch) public_sch->setSystemObject(true); model_tab->db_model->setInvalidated(false); model_tab->restoreLastCanvasPosition(); //Making a copy of the loaded database model file as the first version of the temp. model QFile::copy(filename, model_tab->getTempFilename()); } catch(Exception &e) { models_tbw->setUpdatesEnabled(true); central_wgt->update(); models_tbw->removeTab(models_tbw->indexOf(model_tab)); model_tab->setParent(nullptr); //Destroy the temp file generated by allocating a new model widget restoration_form->removeTemporaryModel(model_tab->getTempFilename()); //delete(model_tab); updateToolsState(true); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } model_nav_wgt->addModel(model_tab); models_tbw->setUpdatesEnabled(true); models_tbw->setVisible(true); setCurrentModel(); if(start_timers) { if(model_save_timer.interval() > 0) model_save_timer.start(); tmpmodel_save_timer.start(); } model_tab->setModified(false); action_save_model->setEnabled(false); if(action_alin_objs_grade->isChecked()) current_model->scene->alignObjectsToGrid(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void MainWindow::addModel(ModelWidget *model_wgt) { try { if(!model_wgt) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(model_wgt->parent()) throw Exception(ErrorCode::AsgWidgetAlreadyHasParent,__PRETTY_FUNCTION__,__FILE__,__LINE__); model_nav_wgt->addModel(model_wgt); models_tbw->blockSignals(true); models_tbw->addTab(model_wgt, model_wgt->getDatabaseModel()->getName()); models_tbw->setCurrentIndex(models_tbw->count()-1); models_tbw->blockSignals(false); setCurrentModel(); models_tbw->currentWidget()->layout()->setContentsMargins(3,3,0,3); if(action_alin_objs_grade->isChecked()) current_model->scene->alignObjectsToGrid(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } int MainWindow::getModelCount(void) { return(models_tbw->count()); } ModelWidget *MainWindow::getModel(int idx) { if(idx < 0 || idx > models_tbw->count()) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(dynamic_cast(models_tbw->widget(idx))); } void MainWindow::showMainMenu(void) { action_main_menu->setVisible(sender()!=action_show_main_menu); main_menu_mb->setVisible(sender()==action_show_main_menu); if(sender()!=action_show_main_menu) file_menu->removeAction(action_hide_main_menu); else file_menu->addAction(action_hide_main_menu); } void MainWindow::setCurrentModel(void) { layers_wgt->setVisible(false); models_tbw->setVisible(models_tbw->count() > 0); action_design->setEnabled(models_tbw->count() > 0); if(models_tbw->count() > 0) action_design->setChecked(true); else action_welcome->setChecked(true); removeModelActions(); edit_menu->clear(); edit_menu->addAction(action_undo); edit_menu->addAction(action_redo); edit_menu->addSeparator(); //Avoids the tree state saving in order to restore the current model tree state model_objs_wgt->saveTreeState(false); //Restore the tree state if(current_model) model_objs_wgt->saveTreeState(model_tree_states[current_model]); models_tbw->setCurrentIndex(model_nav_wgt->getCurrentIndex()); current_model=dynamic_cast(models_tbw->currentWidget()); action_arrange_objects->setEnabled(current_model != nullptr); if(current_model) { QToolButton *tool_btn=nullptr; QList btns; QFont font; layers_wgt->setModel(current_model); current_model->setFocus(Qt::OtherFocusReason); current_model->cancelObjectAddition(); general_tb->addSeparator(); general_tb->addAction(current_model->action_new_object); tool_btn=qobject_cast(general_tb->widgetForAction(current_model->action_new_object)); tool_btn->setPopupMode(QToolButton::InstantPopup); btns.push_back(tool_btn); general_tb->addAction(current_model->action_quick_actions); tool_btn=qobject_cast(general_tb->widgetForAction(current_model->action_quick_actions)); tool_btn->setPopupMode(QToolButton::InstantPopup); btns.push_back(tool_btn); general_tb->addAction(current_model->action_edit); tool_btn=qobject_cast(general_tb->widgetForAction(current_model->action_edit)); btns.push_back(tool_btn); general_tb->addAction(current_model->action_source_code); tool_btn=qobject_cast(general_tb->widgetForAction(current_model->action_source_code)); btns.push_back(tool_btn); more_actions_menu.clear(); more_actions_menu.addAction(current_model->action_select_all); more_actions_menu.addAction(current_model->action_fade); more_actions_menu.addAction(current_model->action_collapse_mode); more_actions_menu.addAction(current_model->action_edit_creation_order); general_tb->addAction(action_other_actions); tool_btn = qobject_cast(general_tb->widgetForAction(action_other_actions)); tool_btn->setPopupMode(QToolButton::InstantPopup); btns.push_back(tool_btn); for(QToolButton *btn : btns) { PgModelerUiNs::configureWidgetFont(btn, static_cast(PgModelerUiNs::MediumFontFactor)); font = btn->font(); font.setBold(true); btn->setFont(font); PgModelerUiNs::createDropShadow(btn); } edit_menu->addAction(current_model->action_copy); edit_menu->addAction(current_model->action_cut); edit_menu->addAction(current_model->action_duplicate); edit_menu->addAction(current_model->action_paste); edit_menu->addAction(current_model->action_remove); edit_menu->addAction(current_model->action_cascade_del); if(current_model->getFilename().isEmpty()) this->setWindowTitle(window_title); else this->setWindowTitle(window_title + QString(" - ") + QDir::toNativeSeparators(current_model->getFilename())); //connect(current_model, SIGNAL(s_manipulationCanceled(void)),this, SLOT(updateDockWidgets(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_manipulationCanceled(void)),oper_list_wgt, SLOT(updateOperationList(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectsMoved(void)),oper_list_wgt, SLOT(updateOperationList(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectModified(void)),this, SLOT(updateDockWidgets(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectCreated(void)),this, SLOT(updateDockWidgets(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectRemoved(void)),this, SLOT(updateDockWidgets(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectManipulated(void)),this, SLOT(updateDockWidgets(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectManipulated(void)), this, SLOT(updateModelTabName(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_zoomModified(double)), this, SLOT(updateToolsState(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_objectModified(void)), this, SLOT(updateModelTabName(void)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_sceneInteracted(BaseObjectView*)), scene_info_wgt, SLOT(updateSelectedObject(BaseObjectView*)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_sceneInteracted(int,QRectF)), scene_info_wgt, SLOT(updateSelectedObjects(int,QRectF)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_sceneInteracted(QPointF)), scene_info_wgt, SLOT(updateMousePosition(QPointF)), Qt::UniqueConnection); connect(current_model, SIGNAL(s_zoomModified(double)), scene_info_wgt, SLOT(updateSceneZoom(double)), Qt::UniqueConnection); connect(action_alin_objs_grade, SIGNAL(triggered(bool)), this, SLOT(setGridOptions(void)), Qt::UniqueConnection); connect(action_show_grid, SIGNAL(triggered(bool)), this, SLOT(setGridOptions(void)), Qt::UniqueConnection); connect(action_show_delimiters, SIGNAL(triggered(bool)), this, SLOT(setGridOptions(void)), Qt::UniqueConnection); connect(action_overview, SIGNAL(toggled(bool)), this, SLOT(showOverview(bool)), Qt::UniqueConnection); connect(overview_wgt, SIGNAL(s_overviewVisible(bool)), action_overview, SLOT(setChecked(bool)), Qt::UniqueConnection); if(action_overview->isChecked()) overview_wgt->show(current_model); scene_info_wgt->updateMousePosition(QPointF(0,0)); scene_info_wgt->updateSceneZoom(current_model->getCurrentZoom()); current_model->emitSceneInteracted(); } else this->setWindowTitle(window_title); edit_menu->addSeparator(); edit_menu->addAction(action_configuration); updateToolsState(); oper_list_wgt->setModel(current_model); model_objs_wgt->setModel(current_model); model_valid_wgt->setModel(current_model); obj_finder_wgt->setModel(current_model); if(current_model) model_objs_wgt->restoreTreeState(model_tree_states[current_model]); model_objs_wgt->saveTreeState(true); emit s_currentModelChanged(current_model); } void MainWindow::setGridOptions(void) { GeneralConfigWidget *conf_wgt = dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); map attribs = conf_wgt->getConfigurationParams(); //Configures the global settings for the scene grid ObjectsScene::setGridOptions(action_show_grid->isChecked(), action_alin_objs_grade->isChecked(), action_show_delimiters->isChecked()); attribs[Attributes::Configuration][Attributes::AlignObjsToGrid] = (action_alin_objs_grade->isChecked() ? Attributes::True : Attributes::False); attribs[Attributes::Configuration][Attributes::ShowCanvasGrid] = (action_show_grid->isChecked() ? Attributes::True : Attributes::False); attribs[Attributes::Configuration][Attributes::ShowPageDelimiters] = (action_show_delimiters->isChecked() ? Attributes::True : Attributes::False); if(current_model) { //Align the object to grid is the option is checked if(action_alin_objs_grade->isChecked()) { current_model->scene->alignObjectsToGrid(); //Forcing the relationship updating to fit the new position of the tables current_model->getDatabaseModel()->setObjectsModified({ ObjectType::Relationship, ObjectType::BaseRelationship }); } //Redraw the scene to apply the new grid options current_model->scene->update(); } conf_wgt->addConfigurationParam(Attributes::Configuration, attribs[Attributes::Configuration]); } void MainWindow::applyZoom(void) { if(current_model) { double zoom=current_model->getCurrentZoom(); if(sender()==action_normal_zoom) zoom=1; else if(sender()==action_inc_zoom && zoom < ModelWidget::MaximumZoom) zoom+=ModelWidget::ZoomIncrement; else if(sender()==action_dec_zoom && zoom > ModelWidget::MinimumZoom) zoom-=ModelWidget::ZoomIncrement; current_model->applyZoom(zoom); } } void MainWindow::removeModelActions(void) { QList act_list; act_list=general_tb->actions(); while(act_list.size() > GeneralActionsCount) { general_tb->removeAction(act_list.back()); act_list.pop_back(); } } void MainWindow::closeModel(int model_id) { QWidget *tab=nullptr; overview_wgt->close(); if(model_id >= 0) tab=models_tbw->widget(model_id); else tab=models_tbw->currentWidget(); if(tab) { ModelWidget *model=dynamic_cast(tab); Messagebox msg_box; #ifdef DEMO_VERSION msg_box.setResult(QDialog::Accepted); #else //Ask the user to save the model if its modified if(model->isModified()) { msg_box.show(trUtf8("Save model"), trUtf8("The model %1 was modified! Do you really want to close without save it?").arg(model->getDatabaseModel()->getName()), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); } #endif if(!model->isModified() || (model->isModified() && msg_box.result()==QDialog::Accepted)) { QApplication::setOverrideCursor(Qt::WaitCursor); model_nav_wgt->removeModel(model_id); model_tree_states.erase(model); disconnect(tab, nullptr, oper_list_wgt, nullptr); disconnect(tab, nullptr, model_objs_wgt, nullptr); disconnect(tab, nullptr, this, nullptr); disconnect(action_alin_objs_grade, nullptr, this, nullptr); disconnect(action_show_grid, nullptr, this, nullptr); disconnect(action_show_delimiters, nullptr, this, nullptr); //Remove the temporary file related to the closed model QDir arq_tmp; arq_tmp.remove(model->getTempFilename()); //Removing model specific actions from general toolbar removeModelActions(); if(model_id >= 0) models_tbw->removeTab(model_id); else models_tbw->removeTab(models_tbw->currentIndex()); delete(model); QApplication::restoreOverrideCursor(); } } if(models_tbw->count()==0) { current_model=nullptr; setCurrentModel(); model_save_timer.stop(); tmpmodel_save_timer.stop(); models_tbw->setVisible(false); } else { setCurrentModel(); } } void MainWindow::updateModelTabName(void) { if(current_model && current_model->db_model->getName()!=models_tbw->tabText(models_tbw->currentIndex())) model_nav_wgt->updateModelText(models_tbw->currentIndex(), current_model->db_model->getName(), current_model->getFilename()); } void MainWindow::applyConfigurations(void) { if(!sender() || (sender()==configuration_form && configuration_form->result()==QDialog::Accepted)) { GeneralConfigWidget *conf_wgt=nullptr; int count, i; ModelWidget *model=nullptr; conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); //Disable the auto save if the option is not checked if(!conf_wgt->autosave_interv_chk->isChecked()) { //Stop the save timer model_save_timer.setInterval(InfinityInterval); model_save_timer.stop(); } else { model_save_timer.setInterval(conf_wgt->autosave_interv_spb->value() * 60000); model_save_timer.start(); } //Temporary models are saved every five minutes tmpmodel_save_timer.setInterval(model_save_timer.interval() < InfinityInterval ? model_save_timer.interval()/2 : 300000); tmpmodel_save_timer.start(); QApplication::setOverrideCursor(Qt::WaitCursor); //Force the update of all opened models count=models_tbw->count(); for(i=0; i < count; i++) { model=dynamic_cast(models_tbw->widget(i)); model->updateObjectsOpacity(); model->db_model->setObjectsModified(); } if(current_model) current_model->update(); updateConnections(); sql_tool_wgt->configureSnippets(); QApplication::restoreOverrideCursor(); } sql_tool_wgt->updateTabs(); } void MainWindow::saveAllModels(void) { if(models_tbw->count() > 0 && ((sender()==action_save_all) || (sender()==&model_save_timer && this->isActiveWindow()))) { int i, count; count=models_tbw->count(); for(i=0; i < count; i++) this->saveModel(dynamic_cast(models_tbw->widget(i))); } } void MainWindow::saveModel(ModelWidget *model) { #ifdef DEMO_VERSION #warning "DEMO VERSION: model saving disabled." Messagebox msg_box; msg_box.show(trUtf8("Warning"), trUtf8("You're running a demonstration version! The model saving feature is available only in the full version!"), Messagebox::AlertIcon, Messagebox::OkButton); #else try { if(!model) model=current_model; if(model) { Messagebox msg_box; DatabaseModel *db_model=model->getDatabaseModel(); if(confirm_validation && db_model->isInvalidated()) { msg_box.show(trUtf8("Confirmation"), trUtf8(" WARNING: The model %1 is invalidated! It's recommended to validate it before save in order to create a consistent model otherwise the generated file will be broken demanding manual fixes to be loadable again!").arg(db_model->getName()), Messagebox::AlertIcon, Messagebox::AllButtons, trUtf8("Validate"), trUtf8("Save anyway"), QString(), PgModelerUiNs::getIconPath("validation"), PgModelerUiNs::getIconPath("salvar")); //If the user cancel the saving force the stopping of autosave timer to give user the chance to validate the model if(msg_box.isCancelled()) { model_save_timer.stop(); //The autosave timer will be reactivated in 5 minutes QTimer::singleShot(300000, &model_save_timer, SLOT(start())); } else if(msg_box.result()==QDialog::Accepted) { validation_btn->setChecked(true); this->pending_op=(sender()==action_save_as ? PendingSaveAsOp : PendingSaveOp); action_design->setChecked(true); model_valid_wgt->validateModel(); } } stopTimers(true); if((!confirm_validation || (!db_model->isInvalidated() || (confirm_validation && db_model->isInvalidated() && !msg_box.isCancelled() && msg_box.result()==QDialog::Rejected))) && (model->isModified() || sender()==action_save_as)) { //If the action that calls the slot were the 'save as' or the model filename isn't set if(sender()==action_save_as || model->filename.isEmpty() || pending_op==PendingSaveAsOp) { QFileDialog file_dlg; file_dlg.setDefaultSuffix(QString("dbm")); file_dlg.setWindowTitle(trUtf8("Save '%1' as...").arg(model->db_model->getName())); file_dlg.setNameFilter(trUtf8("Database model (*.dbm);;All files (*.*)")); file_dlg.setFileMode(QFileDialog::AnyFile); file_dlg.setAcceptMode(QFileDialog::AcceptSave); file_dlg.setModal(true); if(file_dlg.exec()==QFileDialog::Accepted && !file_dlg.selectedFiles().isEmpty()) { model->saveModel(file_dlg.selectedFiles().at(0)); recent_models.push_front(file_dlg.selectedFiles().at(0)); updateRecentModelsMenu(); model_nav_wgt->updateModelText(models_tbw->indexOf(model), model->getDatabaseModel()->getName(), file_dlg.selectedFiles().at(0)); } } else model->saveModel(); this->setWindowTitle(window_title + QString(" - ") + QDir::toNativeSeparators(model->getFilename())); model_valid_wgt->clearOutput(); } stopTimers(false); action_save_model->setEnabled(model->isModified()); } } catch(Exception &e) { stopTimers(false); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } #endif } void MainWindow::exportModel(void) { ModelExportForm model_export_form(nullptr, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); Messagebox msg_box; DatabaseModel *db_model=current_model->getDatabaseModel(); action_design->setChecked(true); if(confirm_validation && db_model->isInvalidated()) { msg_box.show(trUtf8("Confirmation"), trUtf8(" WARNING: The model %1 is invalidated! Before run the export process it's recommended to validate in order to correctly create the objects on database server!").arg(db_model->getName()), Messagebox::AlertIcon, Messagebox::AllButtons, trUtf8("Validate"), trUtf8("Export anyway"), QString(), PgModelerUiNs::getIconPath("validation"), PgModelerUiNs::getIconPath("exportar")); if(msg_box.result()==QDialog::Accepted) { validation_btn->setChecked(true); this->pending_op=PendingExportOp; model_valid_wgt->validateModel(); } } if(!confirm_validation || (!db_model->isInvalidated() || (confirm_validation && !msg_box.isCancelled() && msg_box.result()==QDialog::Rejected))) { stopTimers(true); connect(&model_export_form, &ModelExportForm::s_connectionsUpdateRequest, [&](){ updateConnections(true); }); PgModelerUiNs::resizeDialog(&model_export_form); GeneralConfigWidget::restoreWidgetGeometry(&model_export_form); model_export_form.exec(current_model); GeneralConfigWidget::saveWidgetGeometry(&model_export_form); stopTimers(false); } } void MainWindow::importDatabase(void) { DatabaseImportForm db_import_form(nullptr, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); stopTimers(true); connect(&db_import_form, &DatabaseImportForm::s_connectionsUpdateRequest, [&](){ updateConnections(true); }); db_import_form.setModelWidget(current_model); PgModelerUiNs::resizeDialog(&db_import_form); GeneralConfigWidget::restoreWidgetGeometry(&db_import_form); db_import_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&db_import_form); stopTimers(false); if(db_import_form.result()==QDialog::Accepted && db_import_form.getModelWidget()) this->addModel(db_import_form.getModelWidget()); else if(current_model) updateDockWidgets(); } void MainWindow::diffModelDatabase(void) { ModelDatabaseDiffForm modeldb_diff_frm(nullptr, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); Messagebox msg_box; DatabaseModel *db_model=(current_model ? current_model->getDatabaseModel() : nullptr); if(current_model) action_design->setChecked(true); if(confirm_validation && db_model && db_model->isInvalidated()) { msg_box.show(trUtf8("Confirmation"), trUtf8(" WARNING: The model %1 is invalidated! Before run the diff process it's recommended to validate in order to correctly analyze and generate the difference between the model and a database!").arg(db_model->getName()), Messagebox::AlertIcon, Messagebox::AllButtons, trUtf8("Validate"), trUtf8("Diff anyway"), QString(), PgModelerUiNs::getIconPath("validation"), PgModelerUiNs::getIconPath("diff")); if(msg_box.result()==QDialog::Accepted) { validation_btn->setChecked(true); this->pending_op=PendingDiffOp; model_valid_wgt->validateModel(); } } if(!confirm_validation || !db_model || ((db_model && !db_model->isInvalidated()) || (confirm_validation && !msg_box.isCancelled() && msg_box.result()==QDialog::Rejected))) { modeldb_diff_frm.setModelWidget(current_model); stopTimers(true); connect(&modeldb_diff_frm, &ModelDatabaseDiffForm::s_connectionsUpdateRequest, [&](){ updateConnections(true); }); connect(&modeldb_diff_frm, &ModelDatabaseDiffForm::s_loadDiffInSQLTool, [&](QString conn_id, QString database, QString filename){ action_manage->toggle(); sql_tool_wgt->addSQLExecutionTab(conn_id, database, filename); }); //PgModelerUiNs::resizeDialog(&modeldb_diff_frm); GeneralConfigWidget::restoreWidgetGeometry(&modeldb_diff_frm); modeldb_diff_frm.exec(); GeneralConfigWidget::saveWidgetGeometry(&modeldb_diff_frm); stopTimers(false); } } void MainWindow::printModel(void) { if(current_model) { QPrintDialog print_dlg; QPrinter *printer=nullptr; QPrinter::PageSize paper_size, curr_paper_size; QPrinter::Orientation orientation, curr_orientation; QRectF margins; QSizeF custom_size; qreal ml,mt,mr,mb, ml1, mt1, mr1, mb1; GeneralConfigWidget *conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); print_dlg.setOption(QAbstractPrintDialog::PrintCurrentPage, false); print_dlg.setWindowTitle(trUtf8("Database model printing")); //Get the page configuration of the scene ObjectsScene::getPaperConfiguration(paper_size, orientation, margins, custom_size); //Get a reference to the printer printer=print_dlg.printer(); //Sets the printer options based upon the configurations from the scene ObjectsScene::configurePrinter(printer); printer->getPageMargins(&mt,&ml,&mb,&mr,QPrinter::Millimeter); print_dlg.exec(); //If the user confirms the printing if(print_dlg.result() == QDialog::Accepted) { Messagebox msg_box; //Checking If the user modified the default settings overriding the scene configurations printer->getPageMargins(&mt1,&ml1,&mb1,&mr1,QPrinter::Millimeter); curr_orientation=print_dlg.printer()->orientation(); curr_paper_size=print_dlg.printer()->paperSize(); if(ml!=ml1 || mr!=mr1 || mt!=mt1 || mb!=mb1 || orientation!=curr_orientation || curr_paper_size!=paper_size) { msg_box.show(trUtf8("Changes were detected in the definitions of paper/margin of the model which may cause the incorrect print of the objects. Do you want to continue printing using the new settings? To use the default settings click 'No' or 'Cancel' to abort printing."), Messagebox::AlertIcon, Messagebox::AllButtons); } if(!msg_box.isCancelled()) { if(msg_box.result()==QDialog::Rejected) ObjectsScene::configurePrinter(printer); current_model->printModel(printer, conf_wgt->print_grid_chk->isChecked(), conf_wgt->print_pg_num_chk->isChecked()); } } } } void MainWindow::loadModel(void) { QFileDialog file_dlg; try { file_dlg.setNameFilter(trUtf8("Database model (*.dbm);;All files (*.*)")); file_dlg.setWindowIcon(QPixmap(PgModelerUiNs::getIconPath("pgsqlModeler48x48"))); file_dlg.setWindowTitle(trUtf8("Load model")); file_dlg.setFileMode(QFileDialog::ExistingFiles); file_dlg.setAcceptMode(QFileDialog::AcceptOpen); if(file_dlg.exec()==QFileDialog::Accepted) loadModels(file_dlg.selectedFiles()); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } void MainWindow::loadModel(const QString &filename) { loadModels({ filename }); } void MainWindow::loadModels(const QStringList &list) { int i=0; try { qApp->setOverrideCursor(Qt::WaitCursor); for(i=0; i < list.count(); i++) { addModel(list[i]); recent_models.push_front(list[i]); } updateRecentModelsMenu(); qApp->restoreOverrideCursor(); } catch(Exception &e) { qApp->restoreOverrideCursor(); showFixMessage(e, list[i]); } } void MainWindow::showFixMessage(Exception &e, const QString &filename) { Messagebox msg_box; msg_box.show(Exception(Exception::getErrorMessage(ErrorCode::ModelFileNotLoaded).arg(filename), ErrorCode::ModelFileNotLoaded ,__PRETTY_FUNCTION__,__FILE__,__LINE__, &e), trUtf8("Could not load the database model file `%1'. Check the error stack to see details. You can try to fix it in order to make it loadable again.").arg(filename), Messagebox::ErrorIcon, Messagebox::YesNoButtons, trUtf8("Fix model"), trUtf8("Cancel"), QString(), PgModelerUiNs::getIconPath("fixobject"), PgModelerUiNs::getIconPath("msgbox_erro")); if(msg_box.result()==QDialog::Accepted) fixModel(filename); } void MainWindow::setConfirmValidation(bool value) { confirm_validation=value; } void MainWindow::__updateToolsState(void) { updateToolsState(false); } void MainWindow::updateToolsState(bool model_closed) { bool enabled=(!model_closed && current_model); action_print->setEnabled(enabled); action_save_as->setEnabled(enabled); action_save_model->setEnabled(!model_closed && current_model && current_model->isModified()); action_save_all->setEnabled(enabled); action_export->setEnabled(enabled); action_close_model->setEnabled(enabled); action_show_grid->setEnabled(enabled); action_show_delimiters->setEnabled(enabled); action_overview->setEnabled(enabled); action_normal_zoom->setEnabled(enabled); action_inc_zoom->setEnabled(enabled); action_dec_zoom->setEnabled(enabled); action_alin_objs_grade->setEnabled(enabled); action_undo->setEnabled(enabled); action_redo->setEnabled(enabled); action_compact_view->setEnabled(enabled); action_handle_metadata->setEnabled(enabled); if(!model_closed && current_model && models_tbw->count() > 0) { action_undo->setEnabled(current_model->op_list->isUndoAvailable()); action_redo->setEnabled(current_model->op_list->isRedoAvailable()); action_inc_zoom->setEnabled(current_model->getCurrentZoom() <= (ModelWidget::MaximumZoom - ModelWidget::ZoomIncrement)); action_normal_zoom->setEnabled(current_model->getCurrentZoom()!=0); action_dec_zoom->setEnabled(current_model->getCurrentZoom() >= ModelWidget::MinimumZoom); } } void MainWindow::updateDockWidgets(void) { oper_list_wgt->updateOperationList(); model_objs_wgt->updateObjectsView(); /* Any operation executed over the model will reset the validation and the finder will execute the search again */ model_valid_wgt->setModel(current_model); if(current_model && obj_finder_wgt->result_tbw->rowCount() > 0) obj_finder_wgt->findObjects(); } void MainWindow::executePlugin(void) { QAction *action=dynamic_cast(sender()); if(action) { PgModelerPlugin *plugin=reinterpret_cast(action->data().value()); if(plugin) plugin->executePlugin(current_model); } } void MainWindow::showOverview(bool show) { if(show && current_model && !overview_wgt->isVisible()) overview_wgt->show(current_model); else if(!show) overview_wgt->close(); } void MainWindow::openSupport(void) { QDesktopServices::openUrl(QUrl(GlobalAttributes::PgModelerSupport)); } void MainWindow::toggleUpdateNotifier(bool show) { #ifndef NO_UPDATE_CHECK if(show) { setFloatingWidgetPos(update_notifier_wgt, qobject_cast(sender()), control_tb, false); action_about->setChecked(false); action_donate->setChecked(false); } update_notifier_wgt->setVisible(show); #endif } void MainWindow::toggleAboutWidget(bool show) { if(show) { setFloatingWidgetPos(about_wgt, qobject_cast(sender()), control_tb, false); action_update_found->setChecked(false); action_donate->setChecked(false); } about_wgt->setVisible(show); } void MainWindow::toggleDonateWidget(bool show) { if(show) { setFloatingWidgetPos(donate_wgt, qobject_cast(sender()), control_tb, false); action_about->setChecked(false); action_update_found->setChecked(false); } donate_wgt->setVisible(show); } void MainWindow::setFloatingWidgetPos(QWidget *widget, QAction *act, QToolBar *toolbar, bool map_to_window) { if(widget && act && toolbar) { QWidget *wgt=toolbar->widgetForAction(act); QPoint pos_orig=(wgt ? wgt->pos() : QPoint(0,0)), pos; if(map_to_window) pos=wgt->mapTo(this, pos); pos.setX(pos_orig.x() - 10); pos.setY(toolbar->pos().y() + toolbar->height() - 10); if((pos.x() + widget->width()) > this->width()) pos.setX(pos_orig.x() - (widget->width() - 40)); widget->move(pos); } } void MainWindow::configureSamplesMenu(void) { QDir dir(GlobalAttributes::SamplesDir); QStringList files=dir.entryList({QString("*.dbm")}); QAction *act=nullptr; QString path; while(!files.isEmpty()) { act=sample_mdls_menu.addAction(files.front(),this,SLOT(loadModelFromAction(void))); path=QFileInfo(GlobalAttributes::SamplesDir + GlobalAttributes::DirSeparator + files.front()).absoluteFilePath(); act->setToolTip(path); act->setData(path); files.pop_front(); } if(sample_mdls_menu.isEmpty()) { act=sample_mdls_menu.addAction(trUtf8("(no samples found)")); act->setEnabled(false); } central_wgt->sample_tb->setMenu(&sample_mdls_menu); } void MainWindow::storeDockWidgetsSettings(void) { GeneralConfigWidget *conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); attribs_map params; params[Attributes::Validator]=Attributes::True; params[Attributes::SqlValidation]=(model_valid_wgt->sql_validation_chk->isChecked() ? Attributes::True : QString()); params[Attributes::UseUniqueNames]=(model_valid_wgt->use_tmp_names_chk->isChecked() ? Attributes::True : QString()); params[Attributes::Version]=model_valid_wgt->version_cmb->currentText(); conf_wgt->addConfigurationParam(Attributes::Validator, params); params.clear(); params[Attributes::ObjectFinder]=Attributes::True; params[Attributes::SelectObjects]=(obj_finder_wgt->select_btn->isChecked() ? Attributes::True : QString()); params[Attributes::FadeInObjects]=(obj_finder_wgt->fade_btn->isChecked() ? Attributes::True : QString()); params[Attributes::RegularExp]=(obj_finder_wgt->regexp_chk->isChecked() ? Attributes::True : QString()); params[Attributes::CaseSensitive]=(obj_finder_wgt->case_sensitive_chk->isChecked() ? Attributes::True : QString()); params[Attributes::ExactMatch]=(obj_finder_wgt->exact_match_chk->isChecked() ? Attributes::True : QString()); conf_wgt->addConfigurationParam(Attributes::ObjectFinder, params); params.clear(); params[Attributes::SqlTool]=Attributes::True; params[Attributes::ShowAttributesGrid]=(sql_tool_wgt->attributes_tb->isChecked() ? Attributes::True : QString()); params[Attributes::ShowSourcePane]=(sql_tool_wgt->source_pane_tb->isChecked() ? Attributes::True : QString()); conf_wgt->addConfigurationParam(Attributes::SqlTool, params); params.clear(); } void MainWindow::restoreDockWidgetsSettings(void) { GeneralConfigWidget *conf_wgt=dynamic_cast(configuration_form->getConfigurationWidget(ConfigurationForm::GeneralConfWgt)); map confs=conf_wgt->getConfigurationParams(); if(confs.count(Attributes::Validator)) { model_valid_wgt->sql_validation_chk->setChecked(confs[Attributes::Validator][Attributes::SqlValidation]==Attributes::True); model_valid_wgt->use_tmp_names_chk->setChecked(confs[Attributes::Validator][Attributes::UseUniqueNames]==Attributes::True); model_valid_wgt->version_cmb->setCurrentText(confs[Attributes::Validator][Attributes::Version]); } if(confs.count(Attributes::ObjectFinder)) { obj_finder_wgt->select_btn->setChecked(confs[Attributes::ObjectFinder][Attributes::SelectObjects]==Attributes::True); obj_finder_wgt->fade_btn->setChecked(confs[Attributes::ObjectFinder][Attributes::FadeInObjects]==Attributes::True); obj_finder_wgt->regexp_chk->setChecked(confs[Attributes::ObjectFinder][Attributes::RegularExp]==Attributes::True); obj_finder_wgt->case_sensitive_chk->setChecked(confs[Attributes::ObjectFinder][Attributes::CaseSensitive]==Attributes::True); obj_finder_wgt->exact_match_chk->setChecked(confs[Attributes::ObjectFinder][Attributes::ExactMatch]==Attributes::True); } if(confs.count(Attributes::SqlTool)) { sql_tool_wgt->attributes_tb->setChecked(confs[Attributes::SqlTool][Attributes::ShowAttributesGrid]==Attributes::True); sql_tool_wgt->source_pane_tb->setChecked(confs[Attributes::SqlTool][Attributes::ShowSourcePane]==Attributes::True); } } void MainWindow::showDemoVersionWarning(void) { #ifdef DEMO_VERSION Messagebox msg_box; msg_box.show(trUtf8("Warning"), trUtf8("You're running a demonstration version! Note that you'll be able to create only %1 instances \ of each type of object and some key features will be disabled or limited!

You can purchase a full binary copy or get the source code at https://pgmodeler.io.\ NOTE: pgModeler is an open source software, but purchasing binary copies or providing some donations will support the project and keep the development alive and at full speed!

\ HINT: in order to test all features it's recommended to use the demo.dbm model located in Sample models at Welcome view.



").arg(GlobalAttributes::MaxObjectCount), Messagebox::AlertIcon, Messagebox::OkButton); #endif } void MainWindow::executePendingOperation(bool valid_error) { if(!valid_error && pending_op!=NoPendingOp) { static const QString op_names[]={ QString(), QT_TR_NOOP("save"), QT_TR_NOOP("save"), QT_TR_NOOP("export"), QT_TR_NOOP("diff") }; PgModelerUiNs::createOutputTreeItem(model_valid_wgt->output_trw, trUtf8("Executing pending %1 operation...").arg(op_names[pending_op])); if(pending_op==PendingSaveOp || pending_op==PendingSaveAsOp) saveModel(); else if(pending_op==PendingExportOp) exportModel(); else if(pending_op==PendingDiffOp) diffModelDatabase(); pending_op=NoPendingOp; } } void MainWindow::changeCurrentView(bool checked) { QAction *curr_act=qobject_cast(sender()); layers_wgt->setVisible(false); if(checked) { bool enable=(curr_act==action_design); QList actions; action_welcome->blockSignals(true); action_manage->blockSignals(true); action_design->blockSignals(true); action_welcome->setChecked(false); action_manage->setChecked(false); action_design->setChecked(false); curr_act->setChecked(true); views_stw->setCurrentIndex(curr_act->data().toInt()); action_welcome->blockSignals(false); action_manage->blockSignals(false); action_design->blockSignals(false); actions=general_tb->actions(); for(int i=GeneralActionsCount; i < actions.count(); i++) { actions[i]->setEnabled(enable); if(actions[i]->menu()) { for(auto action : actions[i]->menu()->actions()) action->setEnabled(enable); } } if(!enable) overview_wgt->close(); actions=edit_menu->actions(); actions.removeOne(action_configuration); for(auto &act : actions) act->setEnabled(enable); actions=show_menu->actions(); for(auto &act : actions) act->setEnabled(enable); model_nav_wgt->setEnabled(enable); action_print->setEnabled(enable); action_close_model->setEnabled(enable); } else { curr_act->blockSignals(true); curr_act->setChecked(true); curr_act->blockSignals(false); } } void MainWindow::reportBug(void) { BugReportForm bugrep_frm; PgModelerUiNs::resizeDialog(&bugrep_frm); GeneralConfigWidget::restoreWidgetGeometry(&bugrep_frm); bugrep_frm.exec(); GeneralConfigWidget::saveWidgetGeometry(&bugrep_frm); } void MainWindow::removeOperations(void) { //Clears the operation list everytime a fix is applied to the model if(current_model && current_model->op_list->getCurrentSize()!=0) { current_model->op_list->removeOperations(); oper_list_wgt->updateOperationList(); } } void MainWindow::handleObjectsMetadata(void) { MetadataHandlingForm objs_meta_frm(nullptr, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); objs_meta_frm.setModelWidget(current_model); objs_meta_frm.setModelWidgets(model_nav_wgt->getModelWidgets()); connect(&objs_meta_frm, SIGNAL(s_metadataHandled()), model_objs_wgt, SLOT(updateObjectsView())); PgModelerUiNs::resizeDialog(&objs_meta_frm); GeneralConfigWidget::restoreWidgetGeometry(&objs_meta_frm); objs_meta_frm.exec(); GeneralConfigWidget::saveWidgetGeometry(&objs_meta_frm); } void MainWindow::arrangeObjects(void) { if(!current_model) return; Messagebox msgbox; msgbox.show(trUtf8("Rearrange objects over the canvas is an irreversible operation! Would like to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msgbox.result() == QDialog::Accepted) { QApplication::setOverrideCursor(Qt::WaitCursor); if(sender() == arrange_menu.actions().at(0)) current_model->rearrangeSchemasInGrid(); else if(sender() == arrange_menu.actions().at(1)) current_model->rearrangeTablesHierarchically(); else current_model->rearrangeTablesInSchemas(); QApplication::restoreOverrideCursor(); } } void MainWindow::toggleCompactView(void) { ModelWidget *model_wgt = nullptr; BaseObjectView::setCompactViewEnabled(action_compact_view->isChecked()); QApplication::setOverrideCursor(Qt::WaitCursor); for(int idx = 0; idx < models_tbw->count(); idx++) { model_wgt = dynamic_cast(models_tbw->widget(idx)); if(action_compact_view->isChecked()) model_wgt->setAllCollapseMode(CollapseMode::ExtAttribsCollapsed); else model_wgt->setAllCollapseMode(CollapseMode::NotCollapsed); model_wgt->getDatabaseModel()->setObjectsModified({ ObjectType::Table, ObjectType::ForeignTable, ObjectType::View, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Schema}); } if(current_model) current_model->update(); QApplication::restoreOverrideCursor(); } void MainWindow::toggleLayersWidget(bool show) { QPoint tb_pos = mapTo(this, tool_btns_bar_wgt->pos()), btn_pos = mapTo(this, layers_btn->pos()); layers_wgt->move(btn_pos.x() + general_tb->width(), tb_pos.y() - layers_wgt->height() * 0.80); layers_wgt->setVisible(show); } void MainWindow::switchView(int view) { switch(view) { case(ManageView): action_manage->toggle(); break; case(DesignView): action_design->toggle(); break; case(WelcomeView): action_welcome->toggle(); } } void MainWindow::addExecTabInSQLTool(const QString &sql_cmd) { try { if(sql_tool_wgt->hasDatabasesBrowsed()) sql_tool_wgt->addSQLExecutionTab(sql_cmd); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(), __PRETTY_FUNCTION__, __FILE__, __LINE__, &e); } } bool MainWindow::hasDbsListedInSQLTool(void) { return(sql_tool_wgt->hasDatabasesBrowsed()); } pgmodeler-0.9.2/libpgmodeler_ui/src/mainwindow.h000066400000000000000000000242421360462764600220000ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class MainWindow \brief Implements the pgModeler main window. Reuniting all the resources implemented by the libraries. */ #ifndef MAIN_WINDOW_H #define MAIN_WINDOW_H #include #include #include "ui_mainwindow.h" #include "modelwidget.h" #include "aboutwidget.h" #include "messagebox.h" #include "baseform.h" #include "modelrestorationform.h" #include "operationlistwidget.h" #include "modelobjectswidget.h" #include "pgmodelerplugin.h" #include "modeloverviewwidget.h" #include "modelvalidationwidget.h" #include "objectfinderwidget.h" #include "modelexportform.h" #include "databaseimportform.h" #include "modeldatabasediffform.h" #include "sqltoolwidget.h" #include "modelfixform.h" #include "updatenotifierwidget.h" #include "modelnavigationwidget.h" #include "welcomewidget.h" #include "configurationform.h" #include "donatewidget.h" #include "sceneinfowidget.h" #include "layerswidget.h" class MainWindow: public QMainWindow, public Ui::MainWindow { private: Q_OBJECT static constexpr int GeneralActionsCount=8; static constexpr int WelcomeView=0, DesignView=1, ManageView=2, InfinityInterval = INT_MAX; static bool confirm_validation; //! \brief Constants used to mark a pending operation to be executed after validate model static constexpr unsigned NoPendingOp=0, PendingSaveOp=1, PendingSaveAsOp=2, PendingExportOp=3, PendingDiffOp=4; unsigned pending_op; //! \brief Timer used for auto saving the model and temporary model. QTimer model_save_timer, tmpmodel_save_timer; AboutWidget *about_wgt; DonateWidget *donate_wgt; SceneInfoWidget *scene_info_wgt; //! \brief Layers management widget LayersWidget *layers_wgt; /*! \brief Widget positioned on the center of main window that contains some basic operations like create new model, open a file, restore session */ WelcomeWidget *central_wgt; //! \brief Model overview widget ModelOverviewWidget *overview_wgt; //! \brief Widget used to navigate through the opened models. ModelNavigationWidget *model_nav_wgt; //! \brief Model validation widget ModelValidationWidget *model_valid_wgt; //! \brief SQL tool widget widget SQLToolWidget *sql_tool_wgt; //! \brief Operation list dock widget OperationListWidget *oper_list_wgt; //! \brief Model objects dock widget ModelObjectsWidget *model_objs_wgt; //! \brief Temporary model restoration form ModelRestorationForm *restoration_form; //! \brief Object finder used as dock widget ObjectFinderWidget *obj_finder_wgt; //! \brief Update notifier popup widget UpdateNotifierWidget *update_notifier_wgt; //! \brief Configuration form ConfigurationForm *configuration_form; //! \brief Stores the currently focused model ModelWidget *current_model; //! \brief Stores the model objects tree state for each opened model map > model_tree_states; //! \brief Stores the defaul window title QString window_title; //! \brief Stores the recent models file names QStringList recent_models, //! \brief Stores the last session file names prev_session_files; //! \brief Stores the actions related to recent models QMenu recent_mdls_menu, main_menu, sample_mdls_menu, arrange_menu, more_actions_menu; //! \brief QMainWindow::closeEvent() overload: Saves the configurations before close the application void closeEvent(QCloseEvent *event); void resizeEvent(QResizeEvent *); //! \brief Set the postion of a floating widget based upon an action at a tool bar void setFloatingWidgetPos(QWidget *widget, QAction *act, QToolBar *toolbar, bool map_to_window); void configureSamplesMenu(void); /*! \brief Stores the current checkboxes states of the main dock widgets on the set of configuration params in order to save them on the main configuration file */ void storeDockWidgetsSettings(void); //! \brief Restore the dock widget configurations from the parameters loaded from main configuration file void restoreDockWidgetsSettings(void); //! \brief Shows a error dialog informing that the model demands a fix after the error ocurred when loading the filename. void showFixMessage(Exception &e, const QString &filename); /*! \brief This method determines if the provided layout has togglable buttons and one of them are checked. * This is an auxiliary method used to determine if widget bars (bottom or right) can be displayed based upon * the current button toggle state. */ bool isToolButtonsChecked(QHBoxLayout *layout); public: MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::Widget); ~MainWindow(void); //! \brief Loads a set of models from string list void loadModels(const QStringList &list); //! \brief Indicates if model must be validated before save, diff or export static void setConfirmValidation(bool value); public slots: /*! \brief Creates a new empty model inside the main window. If the parameter 'filename' is specified, creates the model loading it from a file */ void addModel(const QString &filename=QString()); /*! \brief Creates a new model inside the main window using the specified model widget. The method will raise an error is the widget isn't allocated or already has a parent */ void addModel(ModelWidget *model_wgt); //! \brief Closes the currently focused model. If the 'model_id' is specified the model at given index is closed void closeModel(int model_id=-1); //! \brief Returns the currently loaded model count. int getModelCount(void); //! \brief Returns the model at given index ModelWidget *getModel(int idx); //! \brief Switches the currently opened view (Design, Manage, Welcome) void switchView(int view); /*! \brief This is a convenience method to make able the addition of execution tabs in SQL tool without * expose the SQL Tool widget itself (useful for plugin developers) */ void addExecTabInSQLTool(const QString &sql_cmd); /*! \brief This is a convenience method that returns a true value when there're databases listed in the SQL tool widget without * expose the SQL Tool widget itself (useful for plugin developers) */ bool hasDbsListedInSQLTool(void); private slots: void showMainMenu(void); //! \brief Atualiza as definições da grade com base nas ações: Exibir Grade, Alin. Grade e Exibir limites void setGridOptions(void); //! \brief Updates the state (enable/disable) of the buttons of toolbars void updateToolsState(bool model_closed=false); void __updateToolsState(void); //! \brief Updates the operation list and model objects dockwidgets void updateDockWidgets(void); //! \brief Updates the reference to the current model when changing the tab focus void setCurrentModel(void); //! \brief Loads a model from a file via file dialog void loadModel(void); //! \brief Loads a model from a specified filename void loadModel(const QString &filename); //! \brief Saves the currently focused model. If the parameter 'model' is set, saves the passed model void saveModel(ModelWidget *model=nullptr); //! \brief Save all loaded models void saveAllModels(void); //! \brief Prints the currently focused model void printModel(void); //! \brief Executes the export of the currently focused model void exportModel(void); //! \brief Executes the reverse engineering void importDatabase(void); //! \brief Executes the model <> database comparison void diffModelDatabase(void); //! \brief Updates the opened models with new configurations void applyConfigurations(void); //! \brief Applies the zoom to the currently focused model void applyZoom(void); //! \brief Execute the plugin represented by the action that calls the slot void executePlugin(void); //! \brief Toggles the overview widget for the currently opened model void showOverview(bool show); //! \brief Updates the tab name of the currently opened model if the database name is changed void updateModelTabName(void); //! \brief Loads a recent model. The filename is get from the action that triggered the slot void loadModelFromAction(void); //! \brief Clears the recent models menu/list void clearRecentModelsMenu(void); //! \brief Update the recent models menu entries void updateRecentModelsMenu(void); //! \brief Updates the connections list of the validator widget void updateConnections(bool force = false); //! \brief Save the temp files for all opened models void saveTemporaryModels(void); //! \brief Opens the pgModeler Wiki in a web browser window void openSupport(void); /*! \brief Stop the saving timers. This is used when validating the model in order to avoid the saving while the validation is working */ void stopTimers(bool value); //! \brief Executes one of the pending operations (save, export, diff) after validate the model void executePendingOperation(bool valid_error); void fixModel(const QString &filename=QString()); void showRightWidgetsBar(void); void showBottomWidgetsBar(void); void restoreLastSession(void); void toggleUpdateNotifier(bool show); void toggleAboutWidget(bool show); void toggleDonateWidget(bool show); void removeModelActions(void); void showDemoVersionWarning(void); void changeCurrentView(bool checked); void reportBug(void); void removeOperations(void); void handleObjectsMetadata(void); void restoreTemporaryModels(void); void arrangeObjects(void); void toggleCompactView(void); void toggleLayersWidget(bool show); signals: void s_currentModelChanged(ModelWidget *model_wgt); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/messagebox.cpp000066400000000000000000000151341360462764600223140ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "messagebox.h" #include "pgmodeleruins.h" #include "baseobjectview.h" Messagebox::Messagebox(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); this->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); cancelled=false; connect(yes_ok_btn,SIGNAL(clicked()),this,SLOT(handleYesOkClick())); connect(no_btn,SIGNAL(clicked()),this,SLOT(handleNoCancelClick())); connect(cancel_btn,SIGNAL(clicked()),this,SLOT(handleNoCancelClick())); connect(show_errors_tb,SIGNAL(clicked()),this,SLOT(showExceptionList())); connect(show_errors_tb,SIGNAL(toggled(bool)),show_raw_info_tb,SLOT(setVisible(bool))); connect(show_raw_info_tb,SIGNAL(toggled(bool)),this,SLOT(showExceptionList(void))); show_raw_info_tb->setVisible(false); error_show_btns_wgt->setVisible(false); custom_option_chk->setVisible(false); } void Messagebox::handleYesOkClick(void) { exceptions_trw->clear(); accept(); } void Messagebox::handleNoCancelClick(void) { exceptions_trw->clear(); if((sender()==no_btn && !cancel_btn->isVisible()) || (sender()==cancel_btn && !no_btn->isVisible())) reject(); else if(sender()==no_btn && cancel_btn->isVisible()) reject(); else if(sender()==cancel_btn && no_btn->isVisible()) { cancelled=true; reject(); } } bool Messagebox::isCancelled(void) { return(cancelled); } void Messagebox::setCustomOptionText(const QString &text) { custom_option_chk->setVisible(!text.isEmpty()); custom_option_chk->setText(text); } bool Messagebox::isCustomOptionChecked(void) { return(custom_option_chk->isChecked()); } void Messagebox::showExceptionList(void) { if(show_errors_tb->isChecked()) { show_errors_tb->setIcon(QPixmap(PgModelerUiNs::getIconPath("desfazer"))); if(show_raw_info_tb->isChecked()) objs_group_wgt->setCurrentIndex(2); else objs_group_wgt->setCurrentIndex(1); } else if(!show_errors_tb->isVisible() && show_raw_info_tb->isChecked()) { objs_group_wgt->setCurrentIndex(2); } else { show_errors_tb->setIcon(QPixmap(PgModelerUiNs::getIconPath("refazer"))); objs_group_wgt->setCurrentIndex(0); } } void Messagebox::show(Exception e, const QString &msg, unsigned icon_type, unsigned buttons, const QString &yes_lbl, const QString &no_lbl, const QString &cancel_lbl, const QString &yes_ico, const QString &no_ico, const QString &cancel_ico) { QString str_aux, title; show_raw_info_tb->blockSignals(true); show_raw_info_tb->setChecked(false); show_raw_info_tb->blockSignals(false); raw_info_txt->setPlainText(e.getExceptionsText()); PgModelerUiNs::createExceptionsTree(exceptions_trw, e, nullptr); exceptions_trw->expandAll(); exceptions_trw->scrollToTop(); if(msg.isEmpty()) str_aux=PgModelerUiNs::formatMessage(e.getErrorMessage()); else str_aux=PgModelerUiNs::formatMessage(msg); this->show(title, str_aux, icon_type, buttons, yes_lbl, no_lbl, cancel_lbl, yes_ico, no_ico, cancel_ico); } void Messagebox::show(const QString &msg, unsigned icon_type, unsigned buttons) { this->show(QString(), msg, icon_type, buttons); } void Messagebox::show(const QString &title, const QString &msg, unsigned icon_type, unsigned buttons, const QString &yes_lbl, const QString &no_lbl, const QString &cancel_lbl, const QString &yes_ico, const QString &no_ico, const QString &cancel_ico) { QString icon_name, aux_title=title; if(!yes_lbl.isEmpty()) yes_ok_btn->setText(yes_lbl); else yes_ok_btn->setText(buttons==OkButton ? trUtf8("&Ok") : trUtf8("&Yes")); yes_ok_btn->setIcon(!yes_ico.isEmpty() ? QIcon(yes_ico) : QPixmap(PgModelerUiNs::getIconPath("confirmar"))); no_btn->setText(!no_lbl.isEmpty() ? no_lbl : trUtf8("&No")); no_btn->setIcon(!no_ico.isEmpty() ? QIcon(no_ico) : QPixmap(PgModelerUiNs::getIconPath("fechar1"))); cancel_btn->setText(!cancel_lbl.isEmpty() ? cancel_lbl : trUtf8("&Cancel")); cancel_btn->setIcon(!cancel_ico.isEmpty() ? QIcon(cancel_ico) : QPixmap(PgModelerUiNs::getIconPath("cancelar"))); no_btn->setVisible(buttons==YesNoButtons || buttons==AllButtons); cancel_btn->setVisible(buttons==OkCancelButtons || buttons==AllButtons); if(title.isEmpty()) { switch(icon_type) { case ErrorIcon: aux_title=trUtf8("Error"); break; case AlertIcon: aux_title=trUtf8("Alert"); break; case InfoIcon: aux_title=trUtf8("Information"); break; case ConfirmIcon: aux_title=trUtf8("Confirmation"); break; } } switch(icon_type) { case ErrorIcon: icon_name=QString("msgbox_erro"); break; case InfoIcon: icon_name=QString("msgbox_info"); break; case AlertIcon: icon_name=QString("msgbox_alerta"); break; case ConfirmIcon: icon_name=QString("msgbox_quest"); break; default: icon_name=QString(); break; } cancelled=false; icon_lbl->setVisible(!icon_name.isEmpty()); if(!icon_name.isEmpty()) icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(icon_name))); msg_lbl->setText(msg); this->setWindowTitle(aux_title); this->objs_group_wgt->setCurrentIndex(0); this->show_errors_tb->setChecked(false); error_show_btns_wgt->setVisible((exceptions_trw->topLevelItemCount() > 0)); showExceptionList(); this->resize(this->minimumWidth(), this->minimumHeight()); QFontMetrics fm(msg_lbl->font()); QString aux_msg=msg; aux_msg.replace(QRegExp(QString("(<)(br)(/)?(>)"), Qt::CaseInsensitive), QString("\n")); QSize size=QSize(msg_lbl->width(), fm.height() * (aux_msg.count('\n') + 1)); int max_h=msg_lbl->minimumHeight() * 3; //Resizing the message box if the text height is greater than the default size if(size.height() > msg_lbl->minimumHeight() && size.height() < max_h) this->setMinimumHeight((size.height() + (size.height() * 0.25)) + show_raw_info_tb->height() + name_lbl->height() + 30); else if(size.height() >= max_h) this->setMinimumHeight(max_h); double factor = BaseObjectView::getScreenDpiFactor(); this->resize(this->minimumWidth() * factor, this->minimumHeight() * factor); QDialog::exec(); } pgmodeler-0.9.2/libpgmodeler_ui/src/messagebox.h000066400000000000000000000055161360462764600217640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class MessageBox \brief Implements the message box to show errors / alerts / infos to the user. */ #ifndef MESSAGEBOX_H #define MESSAGEBOX_H #include "ui_messagebox.h" #include "exception.h" class Messagebox: public QDialog, public Ui::Messagebox { private: Q_OBJECT bool cancelled; public: //! \brief Constants used to define the message icon static constexpr unsigned NoIcon=10, ErrorIcon=11, InfoIcon=12, AlertIcon=13, ConfirmIcon=14; //! \brief Constants used to configure the visible buttons static constexpr unsigned YesNoButtons=0, OkCancelButtons=1, OkButton=2, AllButtons=3; Messagebox(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); /*! \brief Shows the message box defining the icons and available buttons. User can specify custom button labels as well custom icons. The icons can be a path to a local file or a Qt resource icon ':/path/icon' and will be enabled only specifing custom labels for the respective button. */ void show(const QString &title, const QString &msg, unsigned icon_type=NoIcon, unsigned buttons=OkButton, const QString &yes_lbl=QString(), const QString &no_lbl=QString(), const QString &cancel_lbl=QString(), const QString &yes_ico=QString(), const QString &no_ico=QString(), const QString &cancel_ico=QString()); //! \brief Shows the message box using an excpetion as message void show(Exception e, const QString &msg=QString(), unsigned icon_type=ErrorIcon, unsigned buttons=OkButton, const QString &yes_lbl=QString(), const QString &no_lbl=QString(), const QString &cancel_lbl=QString(), const QString &yes_ico=QString(), const QString &no_ico=QString(), const QString &cancel_ico=QString()); //! \brief Shows a simple message box with the title automatically defined by the icon type void show(const QString &msg, unsigned icon_type=NoIcon, unsigned buttons=OkButton); bool isCancelled(void); void setCustomOptionText(const QString &text); bool isCustomOptionChecked(void); private slots: void handleYesOkClick(void); void handleNoCancelClick(void); void showExceptionList(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/metadatahandlingform.cpp000066400000000000000000000274701360462764600243360ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "metadatahandlingform.h" #include "pgmodeleruins.h" MetadataHandlingForm::MetadataHandlingForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); root_item=nullptr; model_wgt=nullptr; settings_tbw->setTabEnabled(1, false); apply_btn->setEnabled(false); db_metadata_ht=new HintTextWidget(db_metadata_hint, this); db_metadata_ht->setText(db_metadata_chk->statusTip()); objs_positioning_ht=new HintTextWidget(objs_positioning_hint, this); objs_positioning_ht->setText(objs_positioning_chk->statusTip()); objs_protection_ht=new HintTextWidget(objs_protection_hint, this); objs_protection_ht->setText(objs_protection_chk->statusTip()); objs_sql_disabled_ht=new HintTextWidget(objs_sql_disabled_hint, this); objs_sql_disabled_ht->setText(objs_sql_disabled_chk->statusTip()); objs_fadedout_ht=new HintTextWidget(objs_fadedout_hint, this); objs_fadedout_ht->setText(objs_fadedout_chk->statusTip()); objs_collapse_mode_ht=new HintTextWidget(objs_collapse_mode_hint, this); objs_collapse_mode_ht->setText(objs_collapse_mode_chk->statusTip()); custom_sql_ht=new HintTextWidget(custom_sql_hint, this); custom_sql_ht->setText(custom_sql_chk->statusTip()); textbox_objs_ht=new HintTextWidget(textbox_objs_hint, this); textbox_objs_ht->setText(textbox_objs_chk->statusTip()); tag_objs_ht=new HintTextWidget(tag_objs_hint, this); tag_objs_ht->setText(tag_objs_chk->statusTip()); custom_colors_ht=new HintTextWidget(custom_colors_hint, this); custom_colors_ht->setText(custom_colors_chk->statusTip()); extract_restore_ht=new HintTextWidget(extract_restore_hint, this); extract_restore_ht->setText(extract_restore_rb->statusTip()); extract_only_ht=new HintTextWidget(extract_only_hint, this); extract_only_ht->setText(extract_only_rb->statusTip()); restore_ht=new HintTextWidget(restore_hint, this); restore_ht->setText(restore_rb->statusTip()); generic_sql_objs_ht=new HintTextWidget(generic_sql_objs_hint, this); generic_sql_objs_ht->setText(generic_sql_objs_chk->statusTip()); objs_aliases_ht=new HintTextWidget(objs_aliases_hint, this); objs_aliases_ht->setText(objs_aliases_chk->statusTip()); htmlitem_deleg=new HtmlItemDelegate(this); output_trw->setItemDelegateForColumn(0, htmlitem_deleg); connect(cancel_btn, SIGNAL(clicked()), this, SLOT(reject())); connect(apply_btn, SIGNAL(clicked()), this, SLOT(handleObjectsMetada())); connect(extract_from_cmb, &QComboBox::currentTextChanged, [&](){ apply_btn->setDisabled(extract_from_cmb->count() == 0); }); connect(select_file_tb, &QToolButton::clicked, [&](){ selectFile(extract_restore_rb->isChecked() || extract_only_rb->isChecked()); }); connect(extract_from_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(enableMetadataHandling())); connect(backup_file_edt, SIGNAL(textChanged(QString)), this, SLOT(enableMetadataHandling())); connect(restore_rb, SIGNAL(toggled(bool)), this, SLOT(enableMetadataHandling())); connect(extract_restore_rb, SIGNAL(toggled(bool)), this, SLOT(enableMetadataHandling())); connect(extract_only_rb, SIGNAL(toggled(bool)), this, SLOT(enableMetadataHandling())); connect(select_all_btn, SIGNAL(clicked(bool)), this, SLOT(selectAllOptions())); connect(clear_all_btn, SIGNAL(clicked(bool)), this, SLOT(selectAllOptions())); } void MetadataHandlingForm::enableMetadataHandling(void) { extract_from_cmb->setVisible(!restore_rb->isChecked()); extract_from_lbl->setVisible(!restore_rb->isChecked()); apply_to_lbl->setVisible(!extract_only_rb->isChecked()); apply_to_edt->setVisible(!extract_only_rb->isChecked()); apply_btn->setEnabled(model_wgt && (((extract_restore_rb->isChecked() && extract_from_cmb->count() > 0) || (extract_only_rb->isChecked() && extract_from_cmb->count() > 0 && !backup_file_edt->text().isEmpty()) || (restore_rb->isChecked() && !backup_file_edt->text().isEmpty())))); } void MetadataHandlingForm::selectAllOptions(void) { bool check = sender() == select_all_btn; QCheckBox *checkbox = nullptr; for(auto &obj : options_grp->children()) { checkbox = dynamic_cast(obj); if(checkbox) checkbox->setChecked(check); } } void MetadataHandlingForm::setModelWidget(ModelWidget *model_wgt) { this->model_wgt=model_wgt; apply_to_edt->clear(); if(model_wgt) { apply_to_edt->setText(QString("%1 (%2)").arg(model_wgt->getDatabaseModel()->getName()) .arg(model_wgt->getFilename().isEmpty() ? trUtf8("model not saved yet") : model_wgt->getFilename())); } } void MetadataHandlingForm::setModelWidgets(QList models) { extract_from_cmb->clear(); for(ModelWidget *model : models) { extract_from_cmb->addItem(QString("%1 (%2)").arg(model->getDatabaseModel()->getName()) .arg(model->getFilename().isEmpty() ? trUtf8("model not saved yet") : model->getFilename()), QVariant::fromValue(reinterpret_cast(model->getDatabaseModel()))); } } void MetadataHandlingForm::handleObjectsMetada(void) { if(!backup_file_edt->text().isEmpty() && backup_file_edt->text() == model_wgt->getFilename()) throw Exception(trUtf8("The backup file cannot be the same as the input model!"), ErrorCode::Custom, __PRETTY_FUNCTION__,__FILE__,__LINE__); QTemporaryFile tmp_file; QString metadata_file; unsigned options=0; DatabaseModel *extract_model=nullptr; try { root_item=nullptr; output_trw->clear(); settings_tbw->setTabEnabled(1, true); settings_tbw->setCurrentIndex(1); options+=(db_metadata_chk->isChecked() ? DatabaseModel::MetaDbAttributes : 0); options+=(custom_colors_chk->isChecked() ? DatabaseModel::MetaObjsCustomColors : 0); options+=(custom_sql_chk->isChecked() ? DatabaseModel::MetaObjsCustomSql : 0); options+=(objs_positioning_chk->isChecked() ? DatabaseModel::MetaObjsPositioning : 0); options+=(objs_protection_chk->isChecked() ? DatabaseModel::MetaObjsProtection : 0); options+=(objs_sql_disabled_chk->isChecked() ? DatabaseModel::MetaObjsSqlDisabled : 0); options+=(tag_objs_chk->isChecked() ? DatabaseModel::MetaTagObjs : 0); options+=(textbox_objs_chk->isChecked() ? DatabaseModel::MetaTextboxObjs : 0); options+=(objs_fadedout_chk->isChecked() ? DatabaseModel::MetaObjsFadeOut : 0); options+=(objs_collapse_mode_chk->isChecked() ? DatabaseModel::MetaObjsCollapseMode : 0); options+=(generic_sql_objs_chk->isChecked() ? DatabaseModel::MetaGenericSqlObjs : 0); options+=(objs_aliases_chk->isChecked() ? DatabaseModel::MetaObjsAliases : 0); connect(model_wgt->getDatabaseModel(), SIGNAL(s_objectLoaded(int,QString,unsigned)), this, SLOT(updateProgress(int,QString,unsigned)), Qt::UniqueConnection); if(extract_restore_rb->isChecked() || extract_only_rb->isChecked()) { extract_model=reinterpret_cast(extract_from_cmb->currentData(Qt::UserRole).value()); if(extract_only_rb->isChecked()) metadata_file = backup_file_edt->text(); else { //Configuring the temporary metadata file tmp_file.setFileTemplate(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + QString("%1_metadata_XXXXXX.%2").arg(extract_model->getName()).arg(QString("omf"))); tmp_file.open(); metadata_file=tmp_file.fileName(); tmp_file.close(); } connect(extract_model, SIGNAL(s_objectLoaded(int,QString,unsigned)), this, SLOT(updateProgress(int,QString,unsigned)), Qt::UniqueConnection); root_item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(trUtf8("Extracting metadata to file `%1'").arg(metadata_file)), QPixmap(PgModelerUiNs::getIconPath("msgbox_info")), nullptr); extract_model->saveObjectsMetadata(metadata_file, options); if(extract_restore_rb->isChecked() && !backup_file_edt->text().isEmpty()) { root_item->setExpanded(false); root_item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(trUtf8("Saving backup metadata to file `%1'").arg(backup_file_edt->text())), QPixmap(PgModelerUiNs::getIconPath("msgbox_info")), nullptr); model_wgt->getDatabaseModel()->saveObjectsMetadata(backup_file_edt->text()); } } else { metadata_file=backup_file_edt->text(); } if(root_item) root_item->setExpanded(false); if(!extract_only_rb->isChecked()) { root_item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(trUtf8("Applying metadata from file `%1'").arg(metadata_file)), QPixmap(PgModelerUiNs::getIconPath("msgbox_info")), nullptr); model_wgt->setUpdatesEnabled(false); model_wgt->getDatabaseModel()->loadObjectsMetadata(metadata_file, options); model_wgt->adjustSceneSize(); model_wgt->restoreLastCanvasPosition(); model_wgt->setUpdatesEnabled(true); model_wgt->setModified(true); model_wgt->updateObjectsOpacity(); } disconnect(model_wgt->getDatabaseModel(), nullptr, this, nullptr); if(extract_model) disconnect(extract_model, nullptr, this, nullptr); emit s_metadataHandled(); } catch(Exception &e) { QPixmap icon=QPixmap(PgModelerUiNs::getIconPath("msgbox_erro")); disconnect(model_wgt->getDatabaseModel(), nullptr, this, nullptr); if(extract_model) disconnect(extract_model, nullptr, this, nullptr); PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(e.getErrorMessage()), icon, nullptr); ico_lbl->setPixmap(icon); progress_lbl->setText(trUtf8("Metadata processing aborted!")); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void MetadataHandlingForm::showEvent(QShowEvent *) { if(!model_wgt) { apply_btn->setEnabled(false); settings_tbw->setEnabled(false); } } void MetadataHandlingForm::selectFile(bool is_output) { QFileDialog file_dlg; file_dlg.setNameFilter(trUtf8("Objects metadata file (*.omf);;All files (*.*)")); file_dlg.setWindowTitle(trUtf8("Select file")); if(!is_output) { file_dlg.setFileMode(QFileDialog::ExistingFiles); file_dlg.setAcceptMode(QFileDialog::AcceptOpen); file_dlg.selectFile(backup_file_edt->text()); } else { file_dlg.setConfirmOverwrite(true); file_dlg.setFileMode(QFileDialog::AnyFile); file_dlg.setAcceptMode(QFileDialog::AcceptSave); file_dlg.selectFile(model_wgt->getDatabaseModel()->getName() + QString(".omf")); } if(file_dlg.exec()==QFileDialog::Accepted && !file_dlg.selectedFiles().isEmpty()) backup_file_edt->setText(file_dlg.selectedFiles().at(0)); } void MetadataHandlingForm::updateProgress(int progress, QString msg, unsigned int type_id) { ObjectType obj_type=static_cast(type_id); QString fmt_msg=PgModelerUiNs::formatMessage(msg); QPixmap icon; if(obj_type==ObjectType::BaseObject) { if(progress==100) icon=QPixmap(PgModelerUiNs::getIconPath("msgbox_info")); else icon=QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")); } else icon=QPixmap(PgModelerUiNs::getIconPath(obj_type)); PgModelerUiNs::createOutputTreeItem(output_trw, fmt_msg, icon, root_item); progress_lbl->setText(fmt_msg); ico_lbl->setPixmap(icon); progress_pb->setValue(progress); } pgmodeler-0.9.2/libpgmodeler_ui/src/metadatahandlingform.h000066400000000000000000000040621360462764600237730ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectsMetadataForm \brief Implements an interface to the feature to extract and restore objects metadata in a model. */ #ifndef METADATA_HANDLING_FORM_H #define METADATA_HANDLING_FORM_H #include #include "ui_metadatahandlingform.h" #include "modelwidget.h" #include "htmlitemdelegate.h" #include "hinttextwidget.h" class MetadataHandlingForm: public QDialog, public Ui::MetadataHandlingForm { private: Q_OBJECT ModelWidget *model_wgt; HtmlItemDelegate *htmlitem_deleg; QTreeWidgetItem *root_item; HintTextWidget *db_metadata_ht, *objs_positioning_ht, *objs_protection_ht, *objs_sql_disabled_ht, *custom_sql_ht, *textbox_objs_ht, *tag_objs_ht, *custom_colors_ht, *extract_restore_ht, *restore_ht, *objs_fadedout_ht, *objs_collapse_mode_ht, *generic_sql_objs_ht, *extract_only_ht, *objs_aliases_ht; void showEvent(QShowEvent *); void selectFile(bool is_output); public: MetadataHandlingForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); void setModelWidget(ModelWidget *model_wgt); void setModelWidgets(QList models); private slots: void updateProgress(int progress, QString msg, unsigned type_id); void handleObjectsMetada(void); void enableMetadataHandling(void); void selectAllOptions(void); signals: void s_metadataHandled(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modeldatabasediffform.cpp000066400000000000000000001323771360462764600244720ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modeldatabasediffform.h" #include "configurationform.h" #include "databaseimportform.h" #include "pgmodeleruins.h" #include bool ModelDatabaseDiffForm::low_verbosity = false; map ModelDatabaseDiffForm::config_params; ModelDatabaseDiffForm::ModelDatabaseDiffForm(QWidget *parent, Qt::WindowFlags flags) : BaseConfigWidget (parent) { try { setupUi(this); setWindowFlags(flags); sqlcode_txt=PgModelerUiNs::createNumberedTextEditor(sqlcode_wgt); sqlcode_txt->setReadOnly(true); htmlitem_del=new HtmlItemDelegate(this); output_trw->setItemDelegateForColumn(0, htmlitem_del); is_adding_new_preset=false; imported_model=loaded_model=source_model=nullptr; src_import_helper=import_helper=nullptr; diff_helper=nullptr; export_helper=nullptr; src_import_thread=import_thread=diff_thread=export_thread=nullptr; src_import_item=import_item=diff_item=export_item=nullptr; export_conn=nullptr; process_paused=false; diff_progress=curr_step=total_steps=0; apply_on_server_ht=new HintTextWidget(apply_on_server_hint, this); apply_on_server_ht->setText(apply_on_server_rb->statusTip()); store_in_file_ht=new HintTextWidget(store_in_file_hint, this); store_in_file_ht->setText(store_in_file_rb->statusTip()); import_sys_objs_ht=new HintTextWidget(import_sys_objs_hint, this); import_sys_objs_ht->setText(import_sys_objs_chk->statusTip()); import_ext_objs_ht=new HintTextWidget(import_ext_objs_hint, this); import_ext_objs_ht->setText(import_ext_objs_chk->statusTip()); keep_cluster_objs_ht=new HintTextWidget(keep_cluster_objs_hint, this); keep_cluster_objs_ht->setText(keep_cluster_objs_chk->statusTip()); trunc_tables_ht=new HintTextWidget(trunc_tables_hint, this); trunc_tables_ht->setText(trunc_tables_chk->statusTip()); ignore_errors_ht=new HintTextWidget(ignore_errors_hint, this); ignore_errors_ht->setText(ignore_errors_chk->statusTip()); force_recreation_ht=new HintTextWidget(force_recreation_hint, this); force_recreation_ht->setText(force_recreation_chk->statusTip()); recreate_unmod_ht=new HintTextWidget(recreate_unmod_hint, this); recreate_unmod_ht->setText("Recreates only objects that can't be changed through ALTER commands according to pgModeler implementation not the PostgreSQL one.\ Currently, those objects are:

aggregate, cast, constraint, collation, conversion, language, operator, operator class, operator family, rule, trigger and view."); cascade_mode_ht=new HintTextWidget(drop_cascade_hint, this); cascade_mode_ht->setText(cascade_mode_chk->statusTip()); pgsql_ver_ht=new HintTextWidget(pgsql_ver_hint, this); pgsql_ver_ht->setText(pgsql_ver_chk->statusTip()); keep_obj_perms_ht=new HintTextWidget(keep_obj_perms_hint, this); keep_obj_perms_ht->setText(keep_obj_perms_chk->statusTip()); ignore_duplic_ht=new HintTextWidget(ignore_duplic_hint, this); ignore_duplic_ht->setText(ignore_duplic_chk->statusTip()); reuse_sequences_ht=new HintTextWidget(reuse_sequences_hint, this); reuse_sequences_ht->setText(reuse_sequences_chk->statusTip()); preserve_db_name_ht=new HintTextWidget(preserve_db_name_hint, this); preserve_db_name_ht->setText(preserve_db_name_chk->statusTip()); dont_drop_missing_objs_ht=new HintTextWidget(dont_drop_missing_objs_hint, this); dont_drop_missing_objs_ht->setText(dont_drop_missing_objs_chk->statusTip()); drop_missing_cols_constr_ht=new HintTextWidget(drop_missing_cols_constr_hint, this); drop_missing_cols_constr_ht->setText(drop_missing_cols_constr_chk->statusTip()); ignore_error_codes_ht=new HintTextWidget(ignore_extra_errors_hint, this); ignore_error_codes_ht->setText(ignore_error_codes_chk->statusTip()); sqlcode_hl=new SyntaxHighlighter(sqlcode_txt); sqlcode_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); pgsql_ver_cmb->addItems(PgSqlVersions::AllVersions); PgModelerUiNs::configureWidgetFont(message_lbl, PgModelerUiNs::MediumFontFactor); cancel_preset_edit_tb->setVisible(false); preset_name_edt->setVisible(false); new_preset_tb->setToolTip(new_preset_tb->toolTip() + QString(" (%1)").arg(new_preset_tb->shortcut().toString())); edit_preset_tb->setToolTip(edit_preset_tb->toolTip() + QString(" (%1)").arg(edit_preset_tb->shortcut().toString())); save_preset_tb->setToolTip(save_preset_tb->toolTip() + QString(" (%1)").arg(save_preset_tb->shortcut().toString())); cancel_preset_edit_tb->setToolTip(cancel_preset_edit_tb->toolTip() + QString(" (%1)").arg(cancel_preset_edit_tb->shortcut().toString())); remove_preset_tb->setToolTip(remove_preset_tb->toolTip() + QString(" (%1)").arg(remove_preset_tb->shortcut().toString())); default_presets_tb->setToolTip(default_presets_tb->toolTip() + QString(" (%1)").arg(default_presets_tb->shortcut().toString())); connect(cancel_btn, &QToolButton::clicked, [&](){ cancelOperation(true); }); connect(pgsql_ver_chk, SIGNAL(toggled(bool)), pgsql_ver_cmb, SLOT(setEnabled(bool))); connect(connections_cmb, SIGNAL(activated(int)), this, SLOT(listDatabases())); connect(store_in_file_rb, SIGNAL(clicked()), this, SLOT(enableDiffMode())); connect(apply_on_server_rb, SIGNAL(clicked()), this, SLOT(enableDiffMode())); connect(file_edt, SIGNAL(textChanged(QString)), this, SLOT(enableDiffMode())); connect(database_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(enableDiffMode())); connect(generate_btn, SIGNAL(clicked()), this, SLOT(generateDiff())); connect(close_btn, SIGNAL(clicked()), this, SLOT(close())); connect(store_in_file_rb, SIGNAL(clicked(bool)), store_in_file_wgt, SLOT(setEnabled(bool))); connect(select_file_tb, SIGNAL(clicked()), this, SLOT(selectOutputFile())); connect(file_edt, SIGNAL(textChanged(QString)), this, SLOT(enableDiffMode())); connect(force_recreation_chk, SIGNAL(toggled(bool)), recreate_unmod_chk, SLOT(setEnabled(bool))); connect(dont_drop_missing_objs_chk, SIGNAL(toggled(bool)), drop_missing_cols_constr_chk, SLOT(setEnabled(bool))); connect(create_tb, SIGNAL(toggled(bool)), this, SLOT(filterDiffInfos())); connect(drop_tb, SIGNAL(toggled(bool)), this, SLOT(filterDiffInfos())); connect(alter_tb, SIGNAL(toggled(bool)), this, SLOT(filterDiffInfos())); connect(ignore_tb, SIGNAL(toggled(bool)), this, SLOT(filterDiffInfos())); connect(ignore_error_codes_chk, SIGNAL(toggled(bool)), error_codes_edt, SLOT(setEnabled(bool))); connect(src_model_rb, SIGNAL(toggled(bool)), src_model_name_lbl, SLOT(setEnabled(bool))); connect(src_connections_cmb, SIGNAL(activated(int)), this, SLOT(listDatabases())); connect(src_database_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(enableDiffMode())); connect(src_model_rb, SIGNAL(toggled(bool)), this, SLOT(enableDiffMode())); connect(open_in_sql_tool_btn, SIGNAL(clicked(bool)), this, SLOT(loadDiffInSQLTool())); connect(presets_cmb, SIGNAL(activated(int)), this, SLOT(selectPreset())); connect(default_presets_tb, SIGNAL(clicked(bool)), this, SLOT(restoreDefaults())); connect(remove_preset_tb, SIGNAL(clicked(bool)), this, SLOT(removePreset())); connect(save_preset_tb, SIGNAL(clicked(bool)), this, SLOT(savePreset())); connect(src_database_rb, &QRadioButton::toggled, [&](bool toggle){ src_database_wgt->setEnabled(toggle); src_connection_lbl->setEnabled(toggle && src_connections_cmb->count() > 0); enableDiffMode(); }); connect(new_preset_tb, &QToolButton::clicked, [&](){ togglePresetConfiguration(true); }); connect(edit_preset_tb, &QToolButton::clicked, [&](){ togglePresetConfiguration(true, true); }); connect(cancel_preset_edit_tb, &QToolButton::clicked, [&](){ togglePresetConfiguration(false); enablePresetButtons(); }); connect(preset_name_edt, &QLineEdit::textChanged, [&](const QString &text){ save_preset_tb->setEnabled(!text.isEmpty()); }); #ifdef DEMO_VERSION #warning "DEMO VERSION: forcing ignore errors in diff due to the object count limit." ignore_errors_chk->setChecked(true); ignore_errors_chk->setEnabled(false); ignore_error_codes_chk->setChecked(false); ignore_error_codes_chk->setEnabled(false); apply_on_server_rb->setChecked(false); apply_on_server_rb->setEnabled(false); #endif } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } ModelDatabaseDiffForm::~ModelDatabaseDiffForm(void) { destroyThread(ImportThread); destroyThread(DiffThread); destroyThread(ExportThread); destroyModel(); } void ModelDatabaseDiffForm::exec(void) { show(); loadConfiguration(); event_loop.exec(); } void ModelDatabaseDiffForm::setModelWidget(ModelWidget *model_wgt) { if(model_wgt) { source_model=loaded_model=model_wgt->getDatabaseModel(); src_model_name_lbl->setText(QString("%1 [%2]").arg(source_model->getName()).arg(QFileInfo(model_wgt->getFilename()).fileName())); src_model_name_lbl->setToolTip(model_wgt->getFilename().isEmpty() ? trUtf8("model not saved yet") : model_wgt->getFilename()); } else { src_model_name_lbl->setText(trUtf8("(none)")); src_model_name_lbl->setToolTip(""); src_database_rb->setChecked(true); src_model_rb->setEnabled(false); } } void ModelDatabaseDiffForm::setLowVerbosity(bool value) { low_verbosity = value; } bool ModelDatabaseDiffForm::isThreadsRunning(void) { return ((import_thread && import_thread->isRunning()) || (src_import_thread && src_import_thread->isRunning()) || (diff_thread && diff_thread->isRunning()) || (export_thread && export_thread->isRunning())); } void ModelDatabaseDiffForm::resetForm(void) { ConnectionsConfigWidget::fillConnectionsComboBox(src_connections_cmb, true); src_connections_cmb->setEnabled(src_connections_cmb->count() > 0); src_connection_lbl->setEnabled(src_connections_cmb->isEnabled()); src_database_cmb->setCurrentIndex(0); ConnectionsConfigWidget::fillConnectionsComboBox(connections_cmb, true, Connection::OpDiff); connections_cmb->setEnabled(connections_cmb->count() > 0); connection_lbl->setEnabled(connections_cmb->isEnabled()); database_cmb->setCurrentIndex(0); enableDiffMode(); settings_tbw->setTabEnabled(1, false); settings_tbw->setTabEnabled(2, false); } void ModelDatabaseDiffForm::closeEvent(QCloseEvent *event) { //Ignore the close event when the thread is running if(isThreadsRunning()) event->ignore(); else if(process_paused) cancelOperation(true); //If no threads are running we quit the event loop so the control can be returned to main thread (application) if(!isThreadsRunning()) event_loop.quit(); } void ModelDatabaseDiffForm::showEvent(QShowEvent *) { //Doing the form configuration in the first show in order to populate the connections combo if(!isThreadsRunning() && connections_cmb->count() == 0) { resetForm(); if(connections_cmb->currentIndex() > 0) listDatabases(); } } void ModelDatabaseDiffForm::createThread(unsigned thread_id) { if(thread_id==SrcImportThread) { src_import_thread=new QThread; src_import_helper=new DatabaseImportHelper; src_import_helper->moveToThread(src_import_thread); connect(src_import_thread, SIGNAL(started(void)), src_import_helper, SLOT(importDatabase())); connect(src_import_helper, SIGNAL(s_progressUpdated(int,QString,ObjectType)), this, SLOT(updateProgress(int,QString,ObjectType)), Qt::BlockingQueuedConnection); connect(src_import_helper, SIGNAL(s_importFinished(Exception)), this, SLOT(handleImportFinished(Exception))); connect(src_import_helper, SIGNAL(s_importAborted(Exception)), this, SLOT(captureThreadError(Exception))); } else if(thread_id==ImportThread) { import_thread=new QThread; import_helper=new DatabaseImportHelper; import_helper->moveToThread(import_thread); connect(import_thread, SIGNAL(started(void)), import_helper, SLOT(importDatabase())); connect(import_helper, SIGNAL(s_progressUpdated(int,QString,ObjectType)), this, SLOT(updateProgress(int,QString,ObjectType)), Qt::BlockingQueuedConnection); connect(import_helper, SIGNAL(s_importFinished(Exception)), this, SLOT(handleImportFinished(Exception))); connect(import_helper, SIGNAL(s_importAborted(Exception)), this, SLOT(captureThreadError(Exception))); } else if(thread_id==DiffThread) { diff_thread=new QThread; diff_helper=new ModelsDiffHelper; diff_helper->moveToThread(diff_thread); connect(diff_thread, SIGNAL(started(void)), diff_helper, SLOT(diffModels())); connect(diff_helper, SIGNAL(s_progressUpdated(int,QString,ObjectType)), this, SLOT(updateProgress(int,QString,ObjectType))); connect(diff_helper, SIGNAL(s_diffFinished()), this, SLOT(handleDiffFinished())); connect(diff_helper, SIGNAL(s_diffAborted(Exception)), this, SLOT(captureThreadError(Exception))); connect(diff_helper, SIGNAL(s_objectsDiffInfoGenerated(ObjectsDiffInfo)), this, SLOT(updateDiffInfo(ObjectsDiffInfo)), Qt::BlockingQueuedConnection); } else { export_thread=new QThread; export_helper=new ModelExportHelper; export_helper->setIgnoredErrors({ QString("0A000") }); export_helper->moveToThread(export_thread); connect(apply_on_server_btn, &QPushButton::clicked, [&](){ apply_on_server_btn->setEnabled(false); if(!export_thread->isRunning()) exportDiff(false); }); connect(export_thread, SIGNAL(started(void)), export_helper, SLOT(exportToDBMS())); connect(export_helper, SIGNAL(s_progressUpdated(int,QString,ObjectType,QString)), this, SLOT(updateProgress(int,QString,ObjectType,QString)), Qt::BlockingQueuedConnection); connect(export_helper, SIGNAL(s_errorIgnored(QString,QString, QString)), this, SLOT(handleErrorIgnored(QString,QString,QString))); connect(export_helper, SIGNAL(s_exportFinished()), this, SLOT(handleExportFinished())); connect(export_helper, SIGNAL(s_exportAborted(Exception)), this, SLOT(captureThreadError(Exception))); } } void ModelDatabaseDiffForm::destroyThread(unsigned thread_id) { if(thread_id==SrcImportThread && src_import_thread) { delete(src_import_thread); delete(src_import_helper); src_import_thread=nullptr; src_import_helper=nullptr; } else if(thread_id==ImportThread && import_thread) { delete(import_thread); delete(import_helper); import_thread=nullptr; import_helper=nullptr; } else if(thread_id==DiffThread && diff_thread) { diff_thread=nullptr; diff_helper=nullptr; delete(diff_thread); delete(diff_helper); } else if(export_thread) { if(export_conn) { delete(export_conn); export_conn=nullptr; } delete(export_thread); delete(export_helper); export_thread=nullptr; export_helper=nullptr; } } void ModelDatabaseDiffForm::destroyModel(void) { if(imported_model) delete(imported_model); if(source_model && source_model != loaded_model && src_database_rb->isChecked()) { delete(source_model); source_model = nullptr; } imported_model=nullptr; } void ModelDatabaseDiffForm::clearOutput(void) { output_trw->clear(); src_import_item=import_item=diff_item=export_item=nullptr; step_lbl->setText(trUtf8("Waiting process to start...")); step_ico_lbl->setPixmap(QPixmap()); progress_lbl->setText(trUtf8("Waiting process to start...")); progress_ico_lbl->setPixmap(QPixmap()); step_pb->setValue(0); progress_pb->setValue(0); create_tb->setText(QString("0")); alter_tb->setText(QString("0")); drop_tb->setText(QString("0")); ignore_tb->setText(QString("0")); } void ModelDatabaseDiffForm::listDatabases(void) { QComboBox *conn_cmb = (sender() == src_connections_cmb ? src_connections_cmb : connections_cmb), *db_cmb = (conn_cmb == src_connections_cmb ? src_database_cmb : database_cmb); QLabel *db_lbl = (conn_cmb == src_connections_cmb ? src_database_lbl : database_lbl); try { if(conn_cmb->currentIndex()==conn_cmb->count()-1) { ConnectionsConfigWidget::openConnectionsConfiguration(conn_cmb, true); resetForm(); emit s_connectionsUpdateRequest(); } Connection *conn=reinterpret_cast(conn_cmb->itemData(conn_cmb->currentIndex()).value()); if(conn) { DatabaseImportHelper imp_helper; imp_helper.setConnection(*conn); DatabaseImportForm::listDatabases(imp_helper, db_cmb); } else db_cmb->clear(); db_cmb->setEnabled(db_cmb->count() > 0); db_lbl->setEnabled(db_cmb->isEnabled()); } catch(Exception &e) { db_cmb->clear(); db_cmb->setEnabled(false); db_lbl->setEnabled(false); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelDatabaseDiffForm::enableDiffMode(void) { store_in_file_wgt->setEnabled(store_in_file_rb->isChecked()); generate_btn->setEnabled(database_cmb->currentIndex() > 0 && ((src_database_rb->isChecked() && src_database_cmb->currentIndex() > 0) || (src_model_rb->isChecked() && loaded_model)) && ((store_in_file_rb->isChecked() && !file_edt->text().isEmpty()) || (apply_on_server_rb->isChecked()))); } void ModelDatabaseDiffForm::generateDiff(void) { // Cancel any pending preset editing before run the diff togglePresetConfiguration(false); //Destroy previously allocated threads and helper before start over. destroyModel(); destroyThread(SrcImportThread); destroyThread(ImportThread); destroyThread(DiffThread); destroyThread(ExportThread); clearOutput(); curr_step = 1; if(low_verbosity) PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Low verbosity is set: only key informations and errors will be displayed."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), nullptr, false); if(src_model_rb->isChecked()) { source_model = loaded_model; total_steps=3; } else total_steps=4; importDatabase(src_database_rb->isChecked() ? SrcImportThread : ImportThread); buttons_wgt->setEnabled(false); cancel_btn->setEnabled(true); generate_btn->setEnabled(false); close_btn->setEnabled(false); settings_tbw->setTabEnabled(0, false); settings_tbw->setTabEnabled(1, true); settings_tbw->setTabEnabled(2, false); settings_tbw->setCurrentIndex(1); } void ModelDatabaseDiffForm::importDatabase(unsigned thread_id) { try { if(thread_id != SrcImportThread && thread_id != ImportThread) throw Exception(ErrorCode::AllocationObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); createThread(thread_id); QThread *thread = (thread_id == SrcImportThread ? src_import_thread : import_thread); DatabaseImportHelper *import_hlp = (thread_id == SrcImportThread ? src_import_helper : import_helper); QComboBox *conn_cmb = (thread_id == SrcImportThread ? src_connections_cmb : connections_cmb), *db_cmb = (thread_id == SrcImportThread ? src_database_cmb : database_cmb); Connection conn=(*reinterpret_cast(conn_cmb->itemData(conn_cmb->currentIndex()).value())), conn1; map> obj_oids; map> col_oids; Catalog catalog; DatabaseModel *db_model = nullptr; conn1=conn; step_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("import"))); conn.switchToDatabase(db_cmb->currentText()); step_lbl->setText(trUtf8("Step %1/%2: Importing database %3...") .arg(curr_step) .arg(total_steps) .arg(conn.getConnectionId(true, true))); if(thread_id == SrcImportThread) src_import_item=PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); else import_item=PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); pgsql_ver=conn.getPgSQLVersion(true); catalog.setConnection(conn); //The import process will exclude built-in array array types, system and extension objects catalog.setFilter(Catalog::ListAllObjects | Catalog::ExclBuiltinArrayTypes | Catalog::ExclExtensionObjs | Catalog::ExclSystemObjs); catalog.getObjectsOIDs(obj_oids, col_oids, {{Attributes::FilterTableTypes, Attributes::True}}); obj_oids[ObjectType::Database].push_back(db_cmb->currentData().value()); if(thread_id == SrcImportThread) { source_model=new DatabaseModel; source_model->createSystemObjects(true); db_model = source_model; } else { imported_model=new DatabaseModel; imported_model->createSystemObjects(true); db_model = imported_model; } import_hlp->setConnection(conn1); import_hlp->setSelectedOIDs(db_model, obj_oids, col_oids); import_hlp->setCurrentDatabase(db_cmb->currentText()); import_hlp->setImportOptions(import_sys_objs_chk->isChecked(), import_ext_objs_chk->isChecked(), true, ignore_errors_chk->isChecked(), false, false, false); thread->start(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelDatabaseDiffForm::diffModels(void) { createThread(DiffThread); step_lbl->setText(trUtf8("Step %1/%2: Comparing %3 and %4...") .arg(curr_step) .arg(total_steps) .arg(source_model->getName()) .arg(imported_model->getName())); step_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("diff"))); if(src_import_item) output_trw->collapseItem(src_import_item); output_trw->collapseItem(import_item); diff_progress=step_pb->value(); diff_item=PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); diff_helper->setDiffOption(ModelsDiffHelper::OptKeepClusterObjs, keep_cluster_objs_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptCascadeMode, cascade_mode_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptTruncateTables, trunc_tables_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptForceRecreation, force_recreation_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptRecreateUnchangeble, recreate_unmod_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptKeepObjectPerms, keep_obj_perms_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptReuseSequences, reuse_sequences_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptPreserveDbName, preserve_db_name_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptDontDropMissingObjs, dont_drop_missing_objs_chk->isChecked()); diff_helper->setDiffOption(ModelsDiffHelper::OptDropMissingColsConstr, drop_missing_cols_constr_chk->isChecked()); diff_helper->setModels(source_model, imported_model); if(pgsql_ver_chk->isChecked()) diff_helper->setPgSQLVersion(pgsql_ver_cmb->currentText()); else diff_helper->setPgSQLVersion(pgsql_ver); diff_thread->start(); } void ModelDatabaseDiffForm::exportDiff(bool confirm) { createThread(ExportThread); Messagebox msg_box; if(confirm) msg_box.show(trUtf8("Confirmation"), trUtf8(" WARNING: The generated diff is ready to be exported! Once started this process will cause irreversible changes on the database. Do you really want to proceed?"), Messagebox::AlertIcon, Messagebox::AllButtons, trUtf8("Apply diff"), trUtf8("Preview diff"), QString(), PgModelerUiNs::getIconPath("diff"), PgModelerUiNs::getIconPath("codigosql")); if(!confirm || msg_box.result()==QDialog::Accepted) { export_conn=new Connection; *export_conn=*reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value()); settings_tbw->setCurrentIndex(1); apply_on_server_btn->setEnabled(true); step_lbl->setText(trUtf8("Step %1/%2: Exporting diff to database %3@%4...") .arg(curr_step) .arg(total_steps) .arg(imported_model->getName()) .arg(export_conn->getConnectionId(true))); step_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("exportar"))); output_trw->collapseItem(diff_item); diff_progress=step_pb->value(); export_item=PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); export_helper->setExportToDBMSParams(sqlcode_txt->toPlainText(), export_conn, database_cmb->currentText(), ignore_duplic_chk->isChecked()); if(ignore_error_codes_chk->isChecked()) export_helper->setIgnoredErrors(error_codes_edt->text().simplified().split(' ')); export_thread->start(); close_btn->setEnabled(false); } else if(msg_box.isCancelled()) cancelOperation(true); else { process_paused=true; close_btn->setEnabled(true); settings_tbw->setCurrentIndex(2); apply_on_server_btn->setVisible(true); output_trw->collapseItem(diff_item); PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Diff process paused. Waiting user action..."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), nullptr); } } void ModelDatabaseDiffForm::filterDiffInfos(void) { QToolButton *btn=dynamic_cast(sender()); map diff_types={ {create_tb, ObjectsDiffInfo::CreateObject}, {drop_tb, ObjectsDiffInfo::DropObject}, {alter_tb, ObjectsDiffInfo::AlterObject}, {ignore_tb, ObjectsDiffInfo::IgnoreObject}}; for(int i=0; i < diff_item->childCount(); i++) { if(diff_item->child(i)->data(0, Qt::UserRole).toUInt()==diff_types[btn]) output_trw->setItemHidden(diff_item->child(i), !btn->isChecked()); } } void ModelDatabaseDiffForm::loadDiffInSQLTool(void) { QString database = database_cmb->currentText(), filename; QFile out_tmp_file; Connection conn=(*reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value())); QByteArray buffer; QTemporaryFile tmp_sql_file; cancelOperation(true); if(store_in_file_rb->isChecked()) filename = file_edt->text(); else { tmp_sql_file.setFileTemplate(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + QString("diff_%1_XXXXXX.sql").arg(database)); tmp_sql_file.open(); filename = tmp_sql_file.fileName(); tmp_sql_file.close(); out_tmp_file.setFileName(filename); out_tmp_file.open(QFile::WriteOnly); if(!out_tmp_file.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(out_tmp_file.fileName()), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); buffer.append(sqlcode_txt->toPlainText()); out_tmp_file.write(buffer); out_tmp_file.close(); } emit s_loadDiffInSQLTool(conn.getConnectionId(), database, filename); close(); } void ModelDatabaseDiffForm::resetButtons(void) { buttons_wgt->setEnabled(true); cancel_btn->setEnabled(false); settings_tbw->setTabEnabled(0, true); apply_on_server_btn->setVisible(false); enableDiffMode(); } void ModelDatabaseDiffForm::saveDiffToFile(void) { if(!sqlcode_txt->toPlainText().isEmpty()) { QFile output; step_lbl->setText(trUtf8("Saving diff to file %1").arg(file_edt->text())); step_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("salvar"))); import_item=PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); step_pb->setValue(90); progress_pb->setValue(100); output.setFileName(file_edt->text()); if(!output.open(QFile::WriteOnly)) captureThreadError(Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(file_edt->text()), ErrorCode::FileDirectoryNotWritten, __PRETTY_FUNCTION__,__FILE__,__LINE__)); output.write(sqlcode_txt->toPlainText().toUtf8()); output.close(); } finishDiff(); } void ModelDatabaseDiffForm::finishDiff(void) { cancelOperation(false); step_lbl->setText(trUtf8("Diff process sucessfully ended!")); progress_lbl->setText(trUtf8("No operations left.")); step_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); progress_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); import_item=PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); step_pb->setValue(100); progress_pb->setValue(100); } void ModelDatabaseDiffForm::cancelOperation(bool cancel_by_user) { if(cancel_by_user) { step_lbl->setText(trUtf8("Operation cancelled by the user.")); progress_lbl->setText(trUtf8("No operations left.")); step_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); progress_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); PgModelerUiNs::createOutputTreeItem(output_trw, step_lbl->text(), *step_ico_lbl->pixmap(), nullptr); } if(src_import_helper && src_import_thread->isRunning()) { src_import_helper->cancelImport(); src_import_thread->quit(); } if(import_helper && import_thread->isRunning()) { import_helper->cancelImport(); import_thread->quit(); } if(diff_helper && diff_thread->isRunning()) { diff_helper->cancelDiff(); diff_thread->quit(); } if(export_helper && export_thread->isRunning()) { export_helper->cancelExport(); export_thread->quit(); } resetButtons(); process_paused=false; close_btn->setEnabled(true); } void ModelDatabaseDiffForm::captureThreadError(Exception e) { QTreeWidgetItem *item=nullptr; cancelOperation(false); progress_lbl->setText(trUtf8("Process aborted due to errors!")); progress_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_erro"))); item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(e.getErrorMessage()), *progress_ico_lbl->pixmap(), nullptr, false, true); PgModelerUiNs::createExceptionsTree(output_trw, e, item); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } void ModelDatabaseDiffForm::handleImportFinished(Exception e) { if(!e.getErrorMessage().isEmpty()) { Messagebox msgbox; msgbox.show(e, e.getErrorMessage(), Messagebox::AlertIcon); } curr_step++; if(src_import_thread && src_import_thread->isRunning()) { src_import_thread->quit(); src_import_item->setExpanded(false); importDatabase(ImportThread); } else { import_thread->quit(); diffModels(); } } void ModelDatabaseDiffForm::handleDiffFinished(void) { curr_step++; sqlcode_txt->setPlainText(diff_helper->getDiffDefinition()); #ifdef DEMO_VERSION #warning "DEMO VERSION: SQL code preview truncated." if(!sqlcode_txt->toPlainText().isEmpty()) { QString code=sqlcode_txt->toPlainText(); code=code.mid(0, code.size()/2); code+=trUtf8("\n\n-- SQL code purposely truncated at this point in demo version!"); sqlcode_txt->setPlainText(code); } #endif settings_tbw->setTabEnabled(2, true); diff_thread->quit(); if(store_in_file_rb->isChecked()) saveDiffToFile(); else if(!sqlcode_txt->toPlainText().isEmpty()) exportDiff(); else finishDiff(); if(sqlcode_txt->toPlainText().isEmpty()) sqlcode_txt->setPlainText(trUtf8("-- No differences were detected between model and database. --")); } void ModelDatabaseDiffForm::handleExportFinished(void) { export_thread->quit(); export_thread->wait(); listDatabases(); finishDiff(); } void ModelDatabaseDiffForm::handleErrorIgnored(QString err_code, QString err_msg, QString cmd) { QTreeWidgetItem *item=nullptr; item=PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Error code %1 found and ignored. Proceeding with export.").arg(err_code), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), export_item, false); PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(err_msg), QPixmap(QString("msgbox_alerta")), item, false); PgModelerUiNs::createOutputTreeItem(output_trw, cmd, QPixmap(), item, false); } void ModelDatabaseDiffForm::updateProgress(int progress, QString msg, ObjectType obj_type, QString cmd) { int progress_aux = 0; msg=PgModelerUiNs::formatMessage(msg); if(src_import_thread && src_import_thread->isRunning()) { progress_aux = progress/5; if(!low_verbosity) { PgModelerUiNs::createOutputTreeItem(output_trw, msg, QPixmap(PgModelerUiNs::getIconPath(obj_type)), src_import_item); } } else if(import_thread && import_thread->isRunning()) { if(src_model_rb->isChecked()) progress_aux = progress/4; else progress_aux = 20 + (progress/5); if(!low_verbosity) { PgModelerUiNs::createOutputTreeItem(output_trw, msg, QPixmap(PgModelerUiNs::getIconPath(obj_type)), import_item); } } else if(diff_thread && diff_thread->isRunning()) { if((progress == 0 || progress == 100) && obj_type==ObjectType::BaseObject) { PgModelerUiNs::createOutputTreeItem(output_trw, msg, QPixmap(PgModelerUiNs::getIconPath("msgbox_info")), diff_item); } progress_aux = diff_progress + (progress/3); } else if(export_thread && export_thread->isRunning()) { QTreeWidgetItem *item=nullptr; QPixmap ico; progress_aux = diff_progress + (progress/3); if(!low_verbosity) { if(obj_type==ObjectType::BaseObject) ico=QPixmap(PgModelerUiNs::getIconPath("codigosql")); else ico=QPixmap(PgModelerUiNs::getIconPath(obj_type)); item=PgModelerUiNs::createOutputTreeItem(output_trw, msg, ico, export_item, false); if(!cmd.isEmpty()) PgModelerUiNs::createOutputTreeItem(output_trw, cmd, QPixmap(), item, false); } } if(progress_aux > step_pb->value()) step_pb->setValue(progress_aux); progress_lbl->setText(msg); progress_pb->setValue(progress); if(obj_type!=ObjectType::BaseObject) progress_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(obj_type))); else progress_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); } void ModelDatabaseDiffForm::updateDiffInfo(ObjectsDiffInfo diff_info) { map buttons={ {ObjectsDiffInfo::CreateObject, create_tb}, {ObjectsDiffInfo::DropObject, drop_tb}, {ObjectsDiffInfo::AlterObject, alter_tb}, {ObjectsDiffInfo::IgnoreObject, ignore_tb} }; unsigned diff_type=diff_info.getDiffType(); QToolButton *btn=buttons[diff_type]; QTreeWidgetItem *item=nullptr; if(!low_verbosity) { item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(diff_info.getInfoMessage()), QPixmap(PgModelerUiNs::getIconPath(diff_info.getObject()->getSchemaName())), diff_item); item->setData(0, Qt::UserRole, diff_info.getDiffType()); } if(diff_helper) btn->setText(QString::number(diff_helper->getDiffTypeCount(diff_type))); if(item) output_trw->setItemHidden(item, !btn->isChecked()); } void ModelDatabaseDiffForm::selectOutputFile(void) { QFileDialog file_dlg; file_dlg.setWindowTitle(trUtf8("Save diff as...")); file_dlg.setFileMode(QFileDialog::AnyFile); file_dlg.setAcceptMode(QFileDialog::AcceptSave); file_dlg.setModal(true); file_dlg.setNameFilter(trUtf8("SQL code (*.sql);;All files (*.*)")); if(source_model) file_dlg.selectFile(source_model->getName() + QString("-diff.sql")); if(file_dlg.exec()==QFileDialog::Accepted) { QString file; if(!file_dlg.selectedFiles().isEmpty()) file = file_dlg.selectedFiles().at(0); file_edt->setText(file); } } void ModelDatabaseDiffForm::loadConfiguration(void) { try { BaseConfigWidget::loadConfiguration(GlobalAttributes::DiffPresetsConf, config_params, { Attributes::Name }); applyConfiguration(); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e, QString("%1 %2").arg(e.getErrorMessage()).arg(trUtf8("In some cases restore the default settings related to it may solve the problem. Would like to do that?")), Messagebox::AlertIcon, Messagebox::YesNoButtons, trUtf8("Restore"), QString(), QString(), PgModelerUiNs::getIconPath("atualizar")); if(msg_box.result() == QDialog::Accepted) restoreDefaults(); } } void ModelDatabaseDiffForm::saveConfiguration(void) { try { attribs_map attribs; QString preset_sch, root_dir; QString presets; root_dir=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator; preset_sch=root_dir + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + Attributes::Preset + GlobalAttributes::SchemaExt; for(auto &conf : config_params) { schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); presets += schparser.getCodeDefinition(preset_sch, conf.second); schparser.ignoreUnkownAttributes(false); schparser.ignoreEmptyAttributes(false); } config_params[GlobalAttributes::DiffPresetsConf][Attributes::Preset] = presets; BaseConfigWidget::saveConfiguration(GlobalAttributes::DiffPresetsConf, config_params); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelDatabaseDiffForm::applyConfiguration(void) { presets_cmb->clear(); presets_cmb->blockSignals(true); for(auto &conf : config_params) presets_cmb->addItem(conf.first); presets_cmb->blockSignals(false); enablePresetButtons(); selectPreset(); } void ModelDatabaseDiffForm::restoreDefaults(void) { try { Messagebox msg_box; msg_box.show(trUtf8("Do you really want to restore the default settings?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { BaseConfigWidget::restoreDefaults(GlobalAttributes::DiffPresetsConf, false); BaseConfigWidget::loadConfiguration(GlobalAttributes::DiffPresetsConf, config_params, { Attributes::Name }); applyConfiguration(); } } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } void ModelDatabaseDiffForm::selectPreset(void) { attribs_map conf = config_params[presets_cmb->currentText()]; QStringList db_name; src_model_rb->setChecked(src_model_rb->isEnabled() && conf[Attributes::CurrentModel] == Attributes::True); src_database_rb->setChecked(!conf[Attributes::InputDatabase].isEmpty()); src_connections_cmb->setCurrentIndex(0); src_connections_cmb->activated(0); db_name = conf[Attributes::InputDatabase].split('@'); if(db_name.size() > 1) { int idx = src_connections_cmb->findText(db_name[1], Qt::MatchStartsWith); if(idx >= 0) { src_connections_cmb->setCurrentIndex(idx); src_connections_cmb->activated(idx); src_database_cmb->setCurrentText(db_name[0]); } } // Selecting the database to compare connections_cmb->setCurrentIndex(0); connections_cmb->activated(0); db_name = conf[Attributes::CompareToDatabase].split('@'); if(db_name.size() > 1) { int idx = connections_cmb->findText(db_name[1], Qt::MatchStartsWith); if(idx > 0) { connections_cmb->setCurrentIndex(idx); connections_cmb->activated(idx); database_cmb->setCurrentText(db_name[0]); } } pgsql_ver_chk->setChecked(!conf[Attributes::Version].isEmpty()); if(pgsql_ver_chk->isChecked()) pgsql_ver_cmb->setCurrentText(conf[Attributes::Version]); store_in_file_rb->setChecked(conf[Attributes::StoreInFile] == Attributes::True); apply_on_server_rb->setChecked(conf[Attributes::ApplyOnServer] == Attributes::True); enableDiffMode(); keep_cluster_objs_chk->setChecked(conf[Attributes::KeepClusterObjs] == Attributes::True); keep_obj_perms_chk->setChecked(conf[Attributes::KeepObjsPerms] == Attributes::True); dont_drop_missing_objs_chk->setChecked(conf[Attributes::DontDropMissingObjs] == Attributes::True); drop_missing_cols_constr_chk->setChecked(conf[Attributes::DontDropMissingObjs] == Attributes::True && conf[Attributes::DropMissingColsConstrs] == Attributes::True); preserve_db_name_chk->setChecked(conf[Attributes::PreserveDbName] == Attributes::True); cascade_mode_chk->setChecked(conf[Attributes::DropTruncCascade] == Attributes::True); trunc_tables_chk->setChecked(conf[Attributes::TruncColsBeforeAlter] == Attributes::True); reuse_sequences_chk->setChecked(conf[Attributes::ReuseSequences] == Attributes::True); force_recreation_chk->setChecked(conf[Attributes::ForceObjsRecreation] == Attributes::True); recreate_unmod_chk->setChecked(conf[Attributes::ForceObjsRecreation] == Attributes::True && conf[Attributes::RecreateUnmodObjs] == Attributes::True); import_sys_objs_chk->setChecked(conf[Attributes::ImportSysObjs] == Attributes::True); import_ext_objs_chk->setChecked(conf[Attributes::ImportExtObjs] == Attributes::True); ignore_duplic_chk->setChecked(conf[Attributes::IgnoreDuplicErrors] == Attributes::True); ignore_errors_chk->setChecked(conf[Attributes::IgnoreImportErrors] == Attributes::True); ignore_error_codes_chk->setChecked(!conf[Attributes::IgnoreErrorCodes].isEmpty()); error_codes_edt->setText(conf[Attributes::IgnoreErrorCodes]); } void ModelDatabaseDiffForm::togglePresetConfiguration(bool toggle, bool is_edit) { is_adding_new_preset = toggle && !is_edit; presets_cmb->setVisible(!toggle); preset_name_edt->setVisible(toggle); default_presets_tb->setVisible(!toggle); cancel_preset_edit_tb->setVisible(toggle); new_preset_tb->setVisible(!toggle); edit_preset_tb->setVisible(!toggle); remove_preset_tb->setVisible(!toggle); preset_name_edt->clear(); save_preset_tb->setEnabled(toggle && (is_edit && presets_cmb->count() > 0)); if(is_edit) preset_name_edt->setText(presets_cmb->currentText()); if(toggle) preset_name_edt->setFocus(); } void ModelDatabaseDiffForm::enablePresetButtons(void) { presets_cmb->setEnabled(presets_cmb->count() > 0); edit_preset_tb->setEnabled(presets_cmb->isEnabled()); remove_preset_tb->setEnabled(presets_cmb->isEnabled()); save_preset_tb->setEnabled(presets_cmb->isEnabled()); } void ModelDatabaseDiffForm::removePreset(void) { Messagebox msg_box; msg_box.show(trUtf8("Are you sure do you want to remove the selected diff preset?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result() == QDialog::Accepted) { config_params.erase(presets_cmb->currentText()); applyConfiguration(); saveConfiguration(); } } void ModelDatabaseDiffForm::savePreset(void) { QString name, fmt_name; attribs_map conf; int idx = 0; if(!is_adding_new_preset) { fmt_name = name = preset_name_edt->text().isEmpty() ? presets_cmb->currentText() : preset_name_edt->text(); config_params.erase(presets_cmb->currentText()); presets_cmb->removeItem(presets_cmb->currentIndex()); } else fmt_name = name = preset_name_edt->text(); // Checking the preset name duplication and performing a basic desambiguation if necessary while(presets_cmb->findText(fmt_name, Qt::MatchExactly) >= 0) fmt_name = name + QString::number(++idx); conf[Attributes::Name] = fmt_name; conf[Attributes::CurrentModel] = src_model_rb->isChecked() ? Attributes::True : QString(); if(src_database_rb->isChecked()) { conf[Attributes::InputDatabase] = QString("%1@%2") .arg(src_database_cmb->currentIndex() > 0 ? src_database_cmb->currentText() : QString("-")) .arg(src_connections_cmb->currentIndex() > 0 ? src_connections_cmb->currentText() : QString("-")); } else conf[Attributes::InputDatabase] = QString(); conf[Attributes::CompareToDatabase] = QString("%1@%2") .arg(database_cmb->currentIndex() > 0 ? database_cmb->currentText() : QString("-")) .arg(connections_cmb->currentIndex() > 0 ? connections_cmb->currentText() : QString("-")); conf[Attributes::Version] = pgsql_ver_chk->isChecked() ? pgsql_ver_cmb->currentText() : QString(); conf[Attributes::StoreInFile] = store_in_file_rb->isChecked() ? Attributes::True : QString(); conf[Attributes::ApplyOnServer] = apply_on_server_rb->isChecked() ? Attributes::True : QString(); conf[Attributes::KeepClusterObjs] = keep_cluster_objs_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::KeepObjsPerms] = keep_obj_perms_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::DontDropMissingObjs] = dont_drop_missing_objs_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::DropMissingColsConstrs] = drop_missing_cols_constr_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::PreserveDbName] = preserve_db_name_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::DropTruncCascade] = cascade_mode_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::TruncColsBeforeAlter] = trunc_tables_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::ReuseSequences] = reuse_sequences_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::ForceObjsRecreation] = force_recreation_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::RecreateUnmodObjs] = recreate_unmod_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::ImportSysObjs] = import_sys_objs_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::ImportExtObjs] = import_ext_objs_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::IgnoreDuplicErrors] = ignore_duplic_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::IgnoreImportErrors] = ignore_errors_chk->isChecked() ? Attributes::True : Attributes::False; conf[Attributes::IgnoreErrorCodes] = error_codes_edt->text(); config_params[fmt_name] = conf; saveConfiguration(); togglePresetConfiguration(false); applyConfiguration(); presets_cmb->setCurrentText(fmt_name); selectPreset(); } pgmodeler-0.9.2/libpgmodeler_ui/src/modeldatabasediffform.h000066400000000000000000000152061360462764600241260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelDatabaseDiffForm \brief Implements the operations to compare and generate a diff between model and database via form. */ #ifndef MODEL_DATABASE_DIFF_FORM #define MODEL_DATABASE_DIFF_FORM #include "ui_modeldatabasediffform.h" #include "modelsdiffhelper.h" #include "databaseimporthelper.h" #include "modelexporthelper.h" #include "hinttextwidget.h" #include "syntaxhighlighter.h" #include "htmlitemdelegate.h" #include "numberedtexteditor.h" #include "baseconfigwidget.h" #include class ModelDatabaseDiffForm: public BaseConfigWidget, public Ui::ModelDatabaseDiffForm { private: Q_OBJECT /*! \brief Indicates if the full output generated during the process should be displayed * When this attribute is true, only errors and some key info messages are displayed. */ static bool low_verbosity; static map config_params; QEventLoop event_loop; bool is_adding_new_preset; NumberedTextEditor *sqlcode_txt; //! \brief Custom delegate used to paint html texts in output tree HtmlItemDelegate *htmlitem_del; //! \brief Hint texts used on the diff options HintTextWidget *apply_on_server_ht, *store_in_file_ht, *import_sys_objs_ht, *import_ext_objs_ht, *keep_cluster_objs_ht, *trunc_tables_ht, *ignore_errors_ht, *force_recreation_ht, *cascade_mode_ht, *pgsql_ver_ht, *recreate_unmod_ht, *keep_obj_perms_ht, *ignore_duplic_ht, *reuse_sequences_ht, *preserve_db_name_ht, *dont_drop_missing_objs_ht, *ignore_error_codes_ht, *drop_missing_cols_constr_ht; //! \brief Syntax highlighter used on the diff preview tab SyntaxHighlighter *sqlcode_hl; //! \brief Helper that will execute the diff between models ModelsDiffHelper *diff_helper; //! \brief Helper that will execute the database import DatabaseImportHelper *import_helper, *src_import_helper; //! \brief Helper that will execute the diff export to database ModelExportHelper *export_helper; //! \brief Threads that will execute each step: import, diff, export QThread *import_thread, *diff_thread, *export_thread, *src_import_thread; //! \brief Tree items generated in each diff step QTreeWidgetItem *import_item, *diff_item, *export_item, *src_import_item; /*! \brief This is the model used in the diff process representing the source. * It can be the modelo loaded from file or a representation of the source database (when comparing two dbs) */ DatabaseModel *source_model, //! \brief This is the model loaded from file *loaded_model, //! \brief This is the model generated by the reverse engineering step *imported_model; //! \brief Connection used to export the diff to database Connection *export_conn; //! \brief PostgreSQL version used by the diff process QString pgsql_ver; int diff_progress, curr_step, total_steps; bool process_paused; void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *); //! \brief Creates the helpers and threads void createThread(unsigned thread_id); //! \brief Destroy the helpers and threads void destroyThread(unsigned thread_id); //! \brief Destroy the imported model void destroyModel(void); void clearOutput(void); void resetForm(void); void resetButtons(void); void saveDiffToFile(void); void finishDiff(void); //! \brief Returns true when one or more threads of the whole diff process are running. bool isThreadsRunning(void); //! \brief Constants used to reference the thread/helper to be handled in createThread() and destroyThread() static constexpr unsigned SrcImportThread=0, ImportThread=1, DiffThread=2, ExportThread=3; //! \brief Applies the loaded configurations to the form. In this widget only list the loaded presets virtual void applyConfiguration(void); //! \brief Loads a set of configurations from a file virtual void loadConfiguration(void); //! \brief Saves the current settings to a file virtual void saveConfiguration(void); void togglePresetConfiguration(bool toggle, bool is_edit = false); void enablePresetButtons(void); public: ModelDatabaseDiffForm(QWidget * parent = nullptr, Qt::WindowFlags flags = Qt::Widget); ~ModelDatabaseDiffForm(void); //! \brief Makes the form behaves like a QDialog by running it from an event loop. The event loop is finished when the user clicks close void exec(void); void setModelWidget(ModelWidget *model_wgt); //! \brief Defines if all the output generated during the import process should be displayed static void setLowVerbosity(bool value); private slots: void listDatabases(void); void enableDiffMode(void); void generateDiff(void); void cancelOperation(bool cancel_by_user); void updateProgress(int progress, QString msg, ObjectType obj_type, QString cmd=QString()); void updateDiffInfo(ObjectsDiffInfo diff_info); void captureThreadError(Exception e); void handleImportFinished(Exception e); void handleDiffFinished(void); void handleExportFinished(void); void handleErrorIgnored(QString err_code, QString err_msg, QString cmd); void selectOutputFile(void); void importDatabase(unsigned thread_id); void diffModels(void); void exportDiff(bool confirm=true); void filterDiffInfos(void); void loadDiffInSQLTool(void); void selectPreset(void); void removePreset(void); void savePreset(void); //! \brief Destroy the current configuration file and makes a copy of the default one located at conf/defaults virtual void restoreDefaults(void); signals: /*! \brief This signal is emitted whenever the user changes the connections settings within this widget without use the main configurations dialog */ void s_connectionsUpdateRequest(void); /*! \brief This signal is emitted whenever the user wants to load the generated diff in the sql tool * The signal contains the connection id, the database name and the temp filename that is generated containing * the commands to be loaded */ void s_loadDiffInSQLTool(QString conn_id, QString database, QString sql_file); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelexportform.cpp000066400000000000000000000346541360462764600234150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelexportform.h" #include "taskprogresswidget.h" #include "configurationform.h" #include "pgmodeleruins.h" bool ModelExportForm::low_verbosity = false; ModelExportForm::ModelExportForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { model=nullptr; viewp=nullptr; setupUi(this); htmlitem_del=new HtmlItemDelegate(this); output_trw->setItemDelegateForColumn(0, htmlitem_del); export_thread=new QThread(this); export_hlp.moveToThread(export_thread); pgsqlvers_ht=new HintTextWidget(pgsqlvers_hint, this); pgsqlvers_ht->setText(pgsqlvers_chk->statusTip()); drop_ht=new HintTextWidget(drop_hint, this); drop_ht->setText(drop_chk->statusTip()); ignore_dup_ht=new HintTextWidget(ignore_dup_hint, this); ignore_dup_ht->setText(ignore_dup_chk->statusTip()); page_by_page_ht=new HintTextWidget(page_by_page_hint, this); page_by_page_ht->setText(page_by_page_chk->statusTip()); ignore_error_codes_ht=new HintTextWidget(ignore_extra_errors_hint, this); ignore_error_codes_ht->setText(ignore_error_codes_chk->statusTip()); mode_ht=new HintTextWidget(mode_hint, this); mode_ht->setText(mode_hint->statusTip()); incl_index_ht=new HintTextWidget(incl_index_hint, this); incl_index_ht->setText(incl_index_hint->statusTip()); connect(export_to_file_rb, SIGNAL(clicked()), this, SLOT(selectExportMode(void))); connect(export_to_dbms_rb, SIGNAL(clicked()), this, SLOT(selectExportMode(void))); connect(export_to_img_rb, SIGNAL(clicked()), this, SLOT(selectExportMode(void))); connect(export_to_dict_rb, SIGNAL(clicked()), this, SLOT(selectExportMode(void))); connect(pgsqlvers_chk, SIGNAL(toggled(bool)), pgsqlvers1_cmb, SLOT(setEnabled(bool))); connect(close_btn, SIGNAL(clicked(bool)), this, SLOT(close(void))); connect(select_file_tb, SIGNAL(clicked(void)), this, SLOT(selectOutputFile(void))); connect(select_img_tb, SIGNAL(clicked(void)), this, SLOT(selectOutputFile(void))); connect(select_dict_tb, SIGNAL(clicked(void)), this, SLOT(selectOutputFile(void))); connect(export_btn, SIGNAL(clicked(void)), this, SLOT(exportModel(void))); connect(drop_chk, SIGNAL(toggled(bool)), drop_db_rb, SLOT(setEnabled(bool))); connect(drop_chk, SIGNAL(toggled(bool)), drop_objs_rb, SLOT(setEnabled(bool))); connect(export_thread, &QThread::started, [&](){ output_trw->setUniformRowHeights(true); if(export_to_dbms_rb->isChecked()) export_hlp.exportToDBMS(); else if(export_to_img_rb->isChecked()) { if(png_rb->isChecked()) export_hlp.exportToPNG(); else export_hlp.exportToSVG(); } else if(export_to_dict_rb->isChecked()) export_hlp.exportToDataDict(); else export_hlp.exportToSQL(); }); connect(export_thread, &QThread::finished, [&](){ output_trw->setUniformRowHeights(false); }); connect(&export_hlp, SIGNAL(s_progressUpdated(int,QString,ObjectType,QString,bool)), this, SLOT(updateProgress(int,QString,ObjectType,QString,bool)), Qt::BlockingQueuedConnection); connect(&export_hlp, SIGNAL(s_exportFinished(void)), this, SLOT(handleExportFinished(void))); connect(&export_hlp, SIGNAL(s_exportCanceled(void)), this, SLOT(handleExportCanceled(void))); connect(&export_hlp, SIGNAL(s_errorIgnored(QString,QString,QString)), this, SLOT(handleErrorIgnored(QString,QString,QString))); connect(&export_hlp, SIGNAL(s_exportAborted(Exception)), this, SLOT(captureThreadError(Exception))); connect(cancel_btn, SIGNAL(clicked(bool)), this, SLOT(cancelExport(void))); connect(connections_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(editConnections(void))); connect(svg_rb, SIGNAL(toggled(bool)), zoom_cmb, SLOT(setDisabled(bool))); connect(svg_rb, SIGNAL(toggled(bool)), zoom_lbl, SLOT(setDisabled(bool))); connect(svg_rb, SIGNAL(toggled(bool)), page_by_page_chk, SLOT(setDisabled(bool))); connect(ignore_error_codes_chk, SIGNAL(toggled(bool)), error_codes_edt, SLOT(setEnabled(bool))); pgsqlvers_cmb->addItems(PgSqlVersions::AllVersions); pgsqlvers1_cmb->addItems(PgSqlVersions::AllVersions); double values[]={ ModelWidget::MinimumZoom, 0.10, 0.25, 0.5, 0.75, 1, 1.25, 1.50, 1.75, 2, 2.25, 2.50, 2.75, 3, 3.25, 3.50, 3.75, ModelWidget::MaximumZoom }; unsigned cnt=sizeof(values)/sizeof(double); for(unsigned i=0; i < cnt; i++) zoom_cmb->addItem(QString("%1%").arg(values[i] * 100), QVariant(values[i])); zoom_cmb->setCurrentText(QString("100%")); settings_tbw->setTabEnabled(1, false); } void ModelExportForm::setLowVerbosity(bool value) { low_verbosity = value; } void ModelExportForm::exec(ModelWidget *model) { if(model) { this->model=model; ConnectionsConfigWidget::fillConnectionsComboBox(connections_cmb, true, Connection::OpExport); selectExportMode(); QDialog::exec(); } } void ModelExportForm::handleErrorIgnored(QString err_code, QString err_msg, QString cmd) { QTreeWidgetItem *item=nullptr; item=PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Error code %1 found and ignored. Proceeding with export.").arg(err_code), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), nullptr, false); PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(err_msg), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), item, false); PgModelerUiNs::createOutputTreeItem(output_trw, cmd, QPixmap(), item, false); } void ModelExportForm::updateProgress(int progress, QString msg, ObjectType obj_type, QString cmd, bool is_code_gen) { QTreeWidgetItem *item=nullptr; QString text=PgModelerUiNs::formatMessage(msg); QPixmap ico; progress_lbl->setText(text); progress_pb->setValue(progress); if(obj_type!=ObjectType::BaseObject) ico=QPixmap(PgModelerUiNs::getIconPath(obj_type)); else if(!cmd.isEmpty()) ico=QPixmap(PgModelerUiNs::getIconPath("codigosql")); else ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_info")); ico_lbl->setPixmap(ico); // If low_verbosity is set only messages hinted by obj_type == BaseObject are show because they hold key info messages if(!is_code_gen && (!low_verbosity || (low_verbosity && obj_type == ObjectType::BaseObject && cmd.isEmpty()))) { item=PgModelerUiNs::createOutputTreeItem(output_trw, text, ico, nullptr, false); if(!cmd.isEmpty()) PgModelerUiNs::createOutputTreeItem(output_trw, cmd, QPixmap(), item, false); } } void ModelExportForm::exportModel(void) { try { output_trw->clear(); settings_tbw->setTabEnabled(1, true); settings_tbw->setCurrentIndex(1); enableExportModes(false); cancel_btn->setEnabled(true); //Export to png if(export_to_img_rb->isChecked()) { viewp=new QGraphicsView(model->scene); if(png_rb->isChecked()) export_hlp.setExportToPNGParams(model->scene, viewp, image_edt->text(), zoom_cmb->itemData(zoom_cmb->currentIndex()).toDouble(), show_grid_chk->isChecked(), show_delim_chk->isChecked(), page_by_page_chk->isChecked()); else export_hlp.setExportToSVGParams(model->scene, image_edt->text(), show_grid_chk->isChecked(), show_delim_chk->isChecked()); export_thread->start(); } else { progress_lbl->setText(trUtf8("Initializing model export...")); if(low_verbosity) PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Low verbosity is set: only key informations and errors will be displayed."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), nullptr, false); //Exporting to sql file if(export_to_file_rb->isChecked()) { progress_lbl->setText(trUtf8("Saving file '%1'").arg(file_edt->text())); export_hlp.setExportToSQLParams(model->db_model, file_edt->text(), pgsqlvers_cmb->currentText()); export_thread->start(); } else if(export_to_dict_rb->isChecked()) { export_hlp.setExportToDataDictParams(model->db_model, dict_edt->text(), incl_index_chk->isChecked(), splitted_rb->isChecked()); export_thread->start(); } //Exporting directly to DBMS else { QString version; Connection *conn=reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value()); //If the user chose a specific version if(pgsqlvers1_cmb->isEnabled()) version=pgsqlvers1_cmb->currentText(); export_hlp.setExportToDBMSParams(model->db_model, conn, version, ignore_dup_chk->isChecked(), drop_chk->isChecked() && drop_db_rb->isChecked(), drop_chk->isChecked() && drop_objs_rb->isChecked()); if(ignore_error_codes_chk->isChecked()) export_hlp.setIgnoredErrors(error_codes_edt->text().simplified().split(' ')); export_thread->start(); } } } catch(Exception &e) { Messagebox msg_box; finishExport(trUtf8("Exporting process aborted!")); msg_box.show(e); } } void ModelExportForm::selectExportMode(void) { QList radios={ export_to_dbms_rb, export_to_img_rb, export_to_file_rb, export_to_dict_rb}; QWidgetList wgts={ export_to_dbms_wgt, export_to_img_wgt, export_to_file_wgt, export_to_dict_wgt }; int i=0; for(QRadioButton *rb : radios) { rb->blockSignals(true); rb->setChecked((!sender() && rb==export_to_dbms_rb) || (sender()==rb)); wgts[i++]->setEnabled(rb->isChecked()); rb->blockSignals(false); } pgsqlvers1_cmb->setEnabled(export_to_dbms_rb->isChecked() && pgsqlvers_chk->isChecked()); export_btn->setEnabled((export_to_dbms_rb->isChecked() && connections_cmb->currentIndex() > 0 && connections_cmb->currentIndex()!=connections_cmb->count()-1) || (export_to_file_rb->isChecked() && !file_edt->text().isEmpty()) || (export_to_img_rb->isChecked() && !image_edt->text().isEmpty()) || (export_to_dict_rb->isChecked() && !dict_edt->text().isEmpty())); } void ModelExportForm::selectOutputFile(void) { QFileDialog file_dlg; file_dlg.setWindowTitle(trUtf8("Export model as...")); file_dlg.setFileMode(QFileDialog::AnyFile); file_dlg.setAcceptMode(QFileDialog::AcceptSave); file_dlg.setModal(true); if(export_to_file_rb->isChecked()) { file_dlg.setNameFilter(trUtf8("SQL script (*.sql);;All files (*.*)")); file_dlg.selectFile(model->getDatabaseModel()->getName() + QString(".sql")); } else if(export_to_dict_rb->isChecked()) { if(splitted_rb->isChecked()) { file_dlg.setFileMode(QFileDialog::DirectoryOnly); file_dlg.setNameFilter(QString()); } else { file_dlg.setNameFilter(trUtf8("HTML file (*.html);;All files (*.*)")); file_dlg.selectFile(model->getDatabaseModel()->getName() + QString(".html")); } } else { if(png_rb->isChecked()) { file_dlg.setNameFilter(trUtf8("Portable Network Graphics (*.png);;All files (*.*)")); file_dlg.selectFile(model->getDatabaseModel()->getName() + QString(".png")); } else { file_dlg.setNameFilter(trUtf8("Scalable Vector Graphics (*.svg);;All files (*.*)")); file_dlg.selectFile(model->getDatabaseModel()->getName() + QString(".svg")); } } if(file_dlg.exec()==QFileDialog::Accepted) { QString file; if(!file_dlg.selectedFiles().isEmpty()) file = file_dlg.selectedFiles().at(0); if(export_to_file_rb->isChecked()) file_edt->setText(file); else if(export_to_dict_rb->isChecked()) dict_edt->setText(file); else image_edt->setText(file); } export_btn->setEnabled(!file_edt->text().isEmpty() || !dict_edt->text().isEmpty() || !image_edt->text().isEmpty()); } void ModelExportForm::captureThreadError(Exception e) { QTreeWidgetItem *item=PgModelerUiNs::createOutputTreeItem(output_trw, PgModelerUiNs::formatMessage(e.getErrorMessage()), QPixmap(PgModelerUiNs::getIconPath("msgbox_erro")), nullptr, false, true); PgModelerUiNs::createExceptionsTree(output_trw, e, item); ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_erro"))); finishExport(trUtf8("Exporting process aborted!")); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } void ModelExportForm::cancelExport(void) { export_hlp.cancelExport(); cancel_btn->setEnabled(false); } void ModelExportForm::handleExportCanceled(void) { QPixmap ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")); QString msg=trUtf8("Exporting process canceled by user!"); finishExport(msg); ico_lbl->setPixmap(ico); PgModelerUiNs::createOutputTreeItem(output_trw, msg, ico); } void ModelExportForm::handleExportFinished(void) { QPixmap ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_info")); QString msg=trUtf8("Exporting process sucessfully ended!"); finishExport(msg); ico_lbl->setPixmap(ico); PgModelerUiNs::createOutputTreeItem(output_trw, msg, ico); } void ModelExportForm::finishExport(const QString &msg) { if(export_thread->isRunning()) export_thread->quit(); enableExportModes(true); cancel_btn->setEnabled(false); progress_pb->setValue(100); progress_lbl->setText(msg); progress_lbl->repaint(); if(viewp) { export_thread->wait(); delete(viewp); viewp=nullptr; } } void ModelExportForm::enableExportModes(bool value) { export_to_dbms_rb->setEnabled(value); export_to_file_rb->setEnabled(value); export_to_img_rb->setEnabled(value); export_to_dict_rb->setEnabled(value); export_btn->setEnabled(value); close_btn->setEnabled(value); } void ModelExportForm::closeEvent(QCloseEvent *event) { /* Ignore the close event when the thread is running this avoid close the form and make thread execute in background */ if(export_thread->isRunning()) event->ignore(); } void ModelExportForm::editConnections(void) { try { if(connections_cmb->currentIndex()==connections_cmb->count()-1) { ConnectionsConfigWidget::openConnectionsConfiguration(connections_cmb, true); emit s_connectionsUpdateRequest(); } } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } export_btn->setEnabled(export_to_dbms_rb->isChecked() && connections_cmb->currentIndex() > 0 && connections_cmb->currentIndex()!=connections_cmb->count()-1); } pgmodeler-0.9.2/libpgmodeler_ui/src/modelexportform.h000066400000000000000000000060441360462764600230520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelExportForm \brief Implements the operations to export a model to a file, image or directly to DBMS. */ #ifndef MODEL_EXPORT_FORM_H #define MODEL_EXPORT_FORM_H #include "ui_modelexportform.h" #include "schemaparser.h" #include "modelwidget.h" #include "modelexporthelper.h" #include "hinttextwidget.h" #include "htmlitemdelegate.h" class ModelExportForm: public QDialog, public Ui::ModelExportForm { private: Q_OBJECT /*! \brief Indicates if the full output generated during the process should be displayed * When this attribute is true, only errors and some key info messages are displayed. */ static bool low_verbosity; //! \brief Custom delegate used to paint html texts in output tree HtmlItemDelegate *htmlitem_del; //! \brief Stores the model widget which will be exported ModelWidget *model; //! \brief Export helper ModelExportHelper export_hlp; //! \brief Thread used to manage the export helper when dealing with dbms export QThread *export_thread; //! \brief Auxiliary viewport passed to export helper when dealing with PNG export QGraphicsView *viewp; HintTextWidget *pgsqlvers_ht, *drop_ht, *ignore_dup_ht, *page_by_page_ht, *ignore_error_codes_ht, *mode_ht, *incl_index_ht; void finishExport(const QString &msg); void enableExportModes(bool value); void closeEvent(QCloseEvent *event); int exec(void){ return(QDialog::Rejected); } public: ModelExportForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); //! \brief Defines if all the output generated during the import process should be displayed static void setLowVerbosity(bool value); public slots: void exec(ModelWidget *model); private slots: void selectExportMode(void); void exportModel(void); void selectOutputFile(void); void updateProgress(int progress, QString msg, ObjectType obj_type, QString cmd, bool is_code_gen); void captureThreadError(Exception e); void cancelExport(void); void handleExportFinished(void); void handleExportCanceled(void); void handleErrorIgnored(QString err_code, QString err_msg, QString cmd); void editConnections(void); signals: /*! \brief This signal is emitted whenever the user changes the connections settings within this widget without use the main configurations dialog */ void s_connectionsUpdateRequest(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelexporthelper.cpp000066400000000000000000001104701360462764600237200ustar00rootroot00000000000000#include "modelexporthelper.h" #include ModelExportHelper::ModelExportHelper(QObject *parent) : QObject(parent) { resetExportParams(); } void ModelExportHelper::resetExportParams(void) { sql_gen_progress=progress=0; db_created=ignore_dup=drop_db=drop_objs=export_canceled=false; simulate=use_tmp_names=db_sql_reenabled=false; created_objs[ObjectType::Role]=created_objs[ObjectType::Tablespace]=-1; db_model=nullptr; connection=nullptr; scene=nullptr; zoom=100; show_grid=show_delim=page_by_page=splitted=browsable=false; viewp=nullptr; } void ModelExportHelper::abortExport(Exception &e) { resetExportParams(); //When running in a separated thread (other than the main application thread) redirects the error in form of signal if(this->thread() && this->thread()!=qApp->thread()) emit s_exportAborted(Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e)); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } void ModelExportHelper::handleSQLError(Exception &e, const QString &sql_cmd, bool ignore_dup) { //Ignoring the error if it is in the ignored list if(ignored_errors.indexOf(e.getExtraInfo()) >= 0 || (ignore_dup && isDuplicationError(e.getExtraInfo()))) emit s_errorIgnored(e.getExtraInfo(), e.getErrorMessage(), sql_cmd); //Raises an excpetion if the error returned by the database is not listed in the ignored list of errors else if(ignored_errors.indexOf(e.getExtraInfo()) < 0) throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e, sql_cmd); else errors.push_back(e); } void ModelExportHelper::setIgnoredErrors(const QStringList &err_codes) { QRegExp valid_code = QRegExp("([a-z]|[A-Z]|[0-9])+"); QStringList error_codes=err_codes; ignored_errors.clear(); error_codes.removeDuplicates(); for(QString code : error_codes) { if(valid_code.exactMatch(code)) ignored_errors.push_back(code); } } void ModelExportHelper::exportToSQL(DatabaseModel *db_model, const QString &filename, const QString &pgsql_ver) { if(!db_model) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); connect(db_model, SIGNAL(s_objectLoaded(int,QString,uint)), this, SLOT(updateProgress(int,QString,uint))); try { progress=sql_gen_progress=0; BaseObject::setPgSQLVersion(pgsql_ver); emit s_progressUpdated(progress, trUtf8("Generating SQL code for PostgreSQL `%1'").arg(BaseObject::getPgSQLVersion()), ObjectType::BaseObject); progress=1; db_model->saveModel(filename, SchemaParser::SqlDefinition); emit s_progressUpdated(100, trUtf8("Output SQL file `%1' successfully written.").arg(filename), ObjectType::BaseObject); emit s_exportFinished(); } catch(Exception &e) { disconnect(db_model, nullptr, this, nullptr); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } disconnect(db_model, nullptr, this, nullptr); } void ModelExportHelper::exportToPNG(ObjectsScene *scene, const QString &filename, double zoom, bool show_grid, bool show_delim, bool page_by_page, QGraphicsView *viewp) { if(!scene) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { QPixmap pix; bool shw_grd, shw_dlm, align_objs; QGraphicsView *view=nullptr; QRect retv; QPolygon pol; vector pages; unsigned v_cnt=0, h_cnt=0, page_idx=1; QString tmpl_filename, file; /* If an external view is specified it will be used instead of creating a local one, this is a workaround to the error below when running the helper in a separated thread QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread */ if(viewp) view=viewp; else view=new QGraphicsView(scene); //Clear the object scene selection to avoid drawing the selectoin rectangle of the objects scene->clearSelection(); //Make a backup of the current scene options shw_grd = ObjectsScene::isShowGrid(); align_objs = ObjectsScene::isAlignObjectsToGrid(); shw_dlm = ObjectsScene::isShowPageDelimiters(); //Sets the options passed by the user ObjectsScene::setGridOptions(show_grid, false, show_delim); if(page_by_page) { QPrinter::Orientation orient; QRectF margins; QSizeF custom_sz, page_sz; QPrinter::PaperSize paper_sz; QPrinter prt; QFileInfo fi(filename); ObjectsScene::getPaperConfiguration(paper_sz, orient, margins, custom_sz); if(paper_sz==QPrinter::Custom) page_sz=custom_sz; else { prt.setPaperSize(paper_sz); prt.setOrientation(orient); page_sz=prt.paperSize(QPrinter::Point); } //Calculates the page count to be exported pages=scene->getPagesForPrinting(page_sz, margins.size(), h_cnt, v_cnt); //Configures the template filename for pages pixmaps tmpl_filename=fi.absolutePath() + GlobalAttributes::DirSeparator + fi.baseName() + QString("_p%1.") + fi.completeSuffix(); } else { QRectF rect=scene->itemsBoundingRect(true); //Give some margin to the resulting image QSizeF margin=QSizeF(5 * BaseObjectView::HorizSpacing, 5 * BaseObjectView::VertSpacing); rect.setTopLeft(rect.topLeft() - QPointF(margin.width(), margin.height())); rect.setSize(rect.size() + margin); pages.push_back(rect); file=filename; } //Updates the scene to apply the change on grid and delimiter scene->update(); //Configures the viewport alignment to top-left coordinates. view->setAlignment(Qt::AlignLeft | Qt::AlignTop); //Apply the zoom factor on the viewport view->resetTransform(); view->centerOn(0,0); view->scale(zoom, zoom); QPainter painter; vector::iterator itr=pages.begin(), itr_end=pages.end(); while(itr!=itr_end && !export_canceled) { //Convert the objects bounding rect to viewport coordinates to correctly draw them onto pixmap pol=view->mapFromScene(*itr); itr++; //Configure the viewport area to be copied retv.setTopLeft(pol.at(0)); retv.setTopRight(pol.at(1)); retv.setBottomRight(pol.at(2)); retv.setBottomLeft(pol.at(3)); //Creates the output pixmap pix=QPixmap(retv.size()); pix.fill(); //Setting optimizations on the painter painter.begin(&pix); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::TextAntialiasing, true); painter.setRenderHint(QPainter::SmoothPixmapTransform, true); emit s_progressUpdated((page_idx/static_cast(pages.size())) * 90, trUtf8("Rendering objects to page %1/%2.").arg(page_idx).arg(pages.size()), ObjectType::BaseObject); //Render the entire viewport onto the pixmap view->render(&painter, QRectF(QPointF(0,0), pix.size()), retv); painter.end(); if(page_by_page) file=tmpl_filename.arg(page_idx++); //If the pixmap is not saved raises an error if(!pix.save(file)) { //Restoring the scene settings before throw error ObjectsScene::setGridOptions(shw_grd, align_objs, shw_dlm); scene->update(); throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(file), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } //Restoring the scene settings ObjectsScene::setGridOptions(shw_grd, align_objs, shw_dlm); scene->update(); if(!export_canceled) { emit s_progressUpdated(100, trUtf8("Output image `%1' successfully written.").arg(filename), ObjectType::BaseObject); emit s_exportFinished(); } else emit s_exportCanceled(); if(view!=viewp) delete(view); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelExportHelper::exportToSVG(ObjectsScene *scene, const QString &filename, bool show_grid, bool show_delim) { if(!scene) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); bool shw_dlm=false, shw_grd=false, align_objs=false; QSvgGenerator svg_gen; QRectF scene_rect=scene->itemsBoundingRect(true); QFileInfo fi(filename); //Making a backup of the current scene options shw_grd = ObjectsScene::isShowGrid(); shw_dlm = ObjectsScene::isShowPageDelimiters(); align_objs = ObjectsScene::isAlignObjectsToGrid(); scene->setBackgroundBrush(Qt::NoBrush); //Disabling grid and delimiters ObjectsScene::setGridOptions(show_grid, false, show_delim); scene->update(); emit s_progressUpdated(0, trUtf8("Exporting model to SVG file.")); svg_gen.setFileName(filename); svg_gen.setTitle(trUtf8("SVG representation of database model")); svg_gen.setDescription(trUtf8("SVG file generated by pgModeler")); QPainter *painter=new QPainter(&svg_gen); scene->render(painter, QRectF(0, 0, scene_rect.size().width(), scene_rect.size().height()), scene_rect); delete(painter); //Restoring the scene settings ObjectsScene::setGridOptions(shw_grd, align_objs, shw_dlm); scene->update(); if(!fi.exists() || !fi.isWritable() || !fi.isReadable()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(filename), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); QFile svg_file; svg_file.setFileName(filename); svg_file.open(QFile::ReadOnly); if(svg_file.isOpen()) { QByteArray buf; QString svg_def, font_attr=QString("font-family=\"%1\""); svg_def.append(svg_file.readAll()); svg_file.close(); //Forcing the usage of the font settings defined for BaseObjectView and its subclasses svg_def.replace(font_attr.arg(scene->font().family()), font_attr.arg(BaseObjectView::getFontStyle(Attributes::Global).font().family())); /* Removing the empty (transparent) backgound object in order to save some space in the file if the grid or delimiter is displayed */ if(!show_delim && !show_grid) svg_def.replace(QRegExp("()"), QString()); buf.append(svg_def); svg_file.open(QFile::WriteOnly | QFile::Truncate); svg_file.write(buf); svg_file.close(); } emit s_progressUpdated(100, trUtf8("Output file `%1' successfully written.").arg(filename), ObjectType::BaseObject); emit s_exportFinished(); } void ModelExportHelper::exportToDBMS(DatabaseModel *db_model, Connection conn, const QString &pgsql_ver, bool ignore_dup, bool drop_db, bool drop_objs, bool simulate, bool use_tmp_names) { int type_id = 0, pos = -1; QString version, sql_cmd, buf, sql_cmd_comment; Connection new_db_conn; unsigned i, count; ObjectType types[]={ObjectType::Role, ObjectType::Tablespace}; BaseObject *object=nullptr; QString tmpl_comm_regexp = QString("(COMMENT)( )+(ON)( )+(%1)(.)+(\n)(") + Attributes::DdlEndToken + QString(")"); QRegExp comm_regexp; try { if(!db_model) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); /* If the export is called using ignore duplications or drop database and simulation mode at same time an error is raised because the simulate mode (mainly used as SQL validation) cannot undo column addition (this can be changed in the future) */ if(simulate && (ignore_dup || drop_db || drop_objs)) throw Exception(ErrorCode::MixingIncompExportOptions,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(drop_db && drop_objs) throw Exception(ErrorCode::MixingIncompDropOptions,__PRETTY_FUNCTION__,__FILE__,__LINE__); connect(db_model, SIGNAL(s_objectLoaded(int,QString,uint)), this, SLOT(updateProgress(int,QString,uint)), Qt::DirectConnection); export_canceled=false; db_created=false; progress=sql_gen_progress=0; created_objs[ObjectType::Role]=created_objs[ObjectType::Tablespace]=-1; errors.clear(); //Retrive the DBMS version in order to generate the correct code conn.connect(); version=conn.getPgSQLVersion(true); emit s_progressUpdated(progress, trUtf8("Starting export to DBMS.")); //Overriding the DBMS version case the version is informed on parameter if(!pgsql_ver.isEmpty()) { BaseObject::setPgSQLVersion(pgsql_ver); emit s_progressUpdated(progress, trUtf8("PostgreSQL version detection overridden. Using version `%1'.").arg(pgsql_ver)); } else { BaseObject::setPgSQLVersion(version); emit s_progressUpdated(progress, trUtf8("PostgreSQL `%1' server detected.").arg(version)); } if(simulate && use_tmp_names) { emit s_progressUpdated(progress, trUtf8("Generating temporary names for database, roles and tablespaces.")); generateTempObjectNames(db_model); } else if(use_tmp_names) throw Exception(ErrorCode::InvUsageTempNamesExportOption,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(simulate && db_model->isSQLDisabled()) { db_model->setSQLDisabled(false); db_sql_reenabled=true; emit s_progressUpdated(progress, trUtf8("Enabling the SQL code for database `%1' to avoid errors.").arg(db_model->getName())); } if(ignore_dup) { emit s_progressUpdated(progress, trUtf8("Ignoring object duplication errors.")); //Save the current status for ALTER command generation for table columns/constraints saveGenAtlerCmdsStatus(db_model); } if(!ignored_errors.isEmpty()) emit s_progressUpdated(progress, trUtf8("Ignoring the following error code(s): `%1'.").arg(ignored_errors.join(", "))); if(drop_db) { emit s_progressUpdated(progress, trUtf8("Trying to drop database `%1'.").arg(db_model->getName())); try { sql_cmd = QString("DROP DATABASE IF EXISTS %1;").arg(db_model->getName(true)); conn.executeDDLCommand(sql_cmd); } catch(Exception &e) { handleSQLError(e, sql_cmd, ignore_dup); } sql_cmd.clear(); } if(simulate) emit s_progressUpdated(progress, trUtf8("Simulation mode activated.")); //Creates the roles and tablespaces separately from the other objects for(type_id=0; type_id < 2 && !export_canceled; type_id++) { count=db_model->getObjectCount(types[type_id]); for(i=0; i < count && !export_canceled; i++) { object=db_model->getObject(i, types[type_id]); progress=((10 * (type_id+1)) + ((i/static_cast(count)) * 10)); try { if(!object->isSQLDisabled()) { //Emits a signal indicating that the object is being exported emit s_progressUpdated(progress, trUtf8("Creating object `%1' (%2)") .arg(object->getName()) .arg(object->getTypeName()), object->getObjectType()); sql_cmd=object->getCodeDefinition(SchemaParser::SqlDefinition); if(types[type_id] == ObjectType::Tablespace) { comm_regexp = QRegExp(tmpl_comm_regexp.arg(object->getSQLName())); pos = comm_regexp.indexIn(sql_cmd); /* If we find a comment on statement we should strip it from the tablespace definition in * order to execute it after creating the db */ if(pos >= 0) { sql_cmd_comment = sql_cmd.mid(pos, comm_regexp.matchedLength()); sql_cmd.remove(pos, comm_regexp.matchedLength()); pos = -1; } } conn.executeDDLCommand(sql_cmd); if(!sql_cmd_comment.isEmpty()) conn.executeDDLCommand(sql_cmd_comment); } } catch(Exception &e) { handleSQLError(e, sql_cmd, ignore_dup); } created_objs[types[type_id]]++; } } try { if(!db_model->isSQLDisabled() && !export_canceled) { comm_regexp = QRegExp(tmpl_comm_regexp.arg(db_model->getSQLName())); //Creating the database on the DBMS emit s_progressUpdated(progress, trUtf8("Creating database `%1'") .arg(db_model->getName()), ObjectType::Database); sql_cmd=db_model->__getCodeDefinition(SchemaParser::SqlDefinition); pos = comm_regexp.indexIn(sql_cmd); /* If we find a comment on statment we should strip it from the DB definition in * order to execute it after creating the db */ if(pos >= 0) { sql_cmd_comment = sql_cmd.mid(pos, comm_regexp.matchedLength()); sql_cmd.remove(pos, comm_regexp.matchedLength()); } conn.executeDDLCommand(sql_cmd); db_created=true; if(!sql_cmd_comment.isEmpty()) conn.executeDDLCommand(sql_cmd_comment); } } catch(Exception &e) { handleSQLError(e, sql_cmd, ignore_dup); } if(!export_canceled) { //Connects to the new created database to create the other objects progress=20; new_db_conn=conn; new_db_conn.setConnectionParam(Connection::ParamDbName, db_model->getName()); emit s_progressUpdated(progress, trUtf8("Connecting to database `%1'") .arg(db_model->getName())); new_db_conn.connect(); progress=30; //Creating the other object types emit s_progressUpdated(progress, trUtf8("Generating SQL for `%1' objects...").arg(db_model->getObjectCount())); //Exporting the database model definition using the opened connection buf=db_model->getCodeDefinition(SchemaParser::SqlDefinition, false); progress=40; exportBufferToDBMS(buf, new_db_conn, drop_objs); } disconnect(db_model, nullptr, this, nullptr); if(ignore_dup) restoreGenAtlerCmdsStatus(); //Closes the new opened connection new_db_conn.close(); /* If the process was a simulation or even canceled undo the export removing the created objects */ if(simulate || export_canceled) undoDBMSExport(db_model, conn, use_tmp_names); conn.close(); if(!export_canceled) emit s_exportFinished(); else emit s_exportCanceled(); } catch(Exception &e) { disconnect(db_model, nullptr, this, nullptr); if(ignore_dup) restoreGenAtlerCmdsStatus(); try { //Closes the new opened connection new_db_conn.close(); //Undo the export removing the created objects undoDBMSExport(db_model, conn, use_tmp_names); } catch(Exception &){} conn.close(); /* When running in a separated thread (other than the main application thread) redirects the error in form of signal */ if(this->thread() && this->thread()!=qApp->thread()) { errors.push_back(e); emit s_exportAborted(Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, errors)); } else { //Redirects any error to terrorsr if(errors.empty()) throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); else { errors.push_back(e); throw Exception(e.getErrorMessage(),__PRETTY_FUNCTION__,__FILE__,__LINE__, errors); } } } } void ModelExportHelper::exportToDataDict(DatabaseModel *db_model, const QString &path, bool browsable, bool splitted) { if(!db_model) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); connect(db_model, SIGNAL(s_objectLoaded(int,QString,uint)), this, SLOT(updateProgress(int,QString,uint))); try { progress=0; emit s_progressUpdated(progress, trUtf8("Starting data dictionary generation..."), ObjectType::BaseObject); progress=1; db_model->saveDataDictionary(path, browsable, splitted); emit s_progressUpdated(100, trUtf8("Data dictionary successfully saved into `%1'.").arg(path), ObjectType::BaseObject); emit s_exportFinished(); } catch(Exception &e) { disconnect(db_model, nullptr, this, nullptr); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } disconnect(db_model, nullptr, this, nullptr); } void ModelExportHelper::saveGenAtlerCmdsStatus(DatabaseModel *db_model) { vector objects; PhysicalTable *tab=nullptr; Relationship *rel=nullptr; objects.insert(objects.end(), db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::ForeignTable)->begin(), db_model->getObjectList(ObjectType::ForeignTable)->end()); //Store the relationship on the auxiliary vector but only many-to-many are considered objects.insert(objects.end(), db_model->getObjectList(ObjectType::Relationship)->begin(), db_model->getObjectList(ObjectType::Relationship)->end()); alter_cmds_status.clear(); while(!objects.empty()) { rel=dynamic_cast(objects.back()); /* If the current object is a relationship try to get the generated table (if the relationship is many-to-many only) */ if(rel) tab=rel->getGeneratedTable(); else tab=dynamic_cast(objects.back()); if(tab) { //Store the current alter state alter_cmds_status[tab]=tab->isGenerateAlterCmds(); //Forcing columns and constraints to be generated via ALTER command tab->setGenerateAlterCmds(true); } objects.pop_back(); } } void ModelExportHelper::restoreGenAtlerCmdsStatus(void) { for(auto &itr : alter_cmds_status) itr.first->setGenerateAlterCmds(itr.second); alter_cmds_status.clear(); } void ModelExportHelper::undoDBMSExport(DatabaseModel *db_model, Connection &conn, bool use_tmp_names) { QString drop_cmd=QString("DROP %1 %2;"); ObjectType types[]={ObjectType::Role, ObjectType::Tablespace}; int type_id; BaseObject *object=nullptr; //In case of error during the export all created object are removed if(db_created || created_objs[ObjectType::Role] >= 0 || created_objs[ObjectType::Tablespace] >= 0) { emit s_progressUpdated(99, trUtf8("Destroying objects created on the server.")); //Dropping the database if(db_created) conn.executeDDLCommand(drop_cmd.arg(db_model->getSQLName()).arg(db_model->getName(true))); //Drop the roles / tablespaces created for(type_id=1; type_id >=0; type_id--) { while(created_objs[types[type_id]] >= 0) { object=db_model->getObject(created_objs[types[type_id]], types[type_id]); try { if(!object->isSQLDisabled()) conn.executeDDLCommand(drop_cmd.arg(object->getSQLName()).arg(object->getName(true))); } catch(Exception &){} created_objs[types[type_id]]--; } } if(use_tmp_names) { emit s_progressUpdated(100, trUtf8("Restoring original names of database, roles and tablespaces.")); restoreObjectNames(); } } if(db_sql_reenabled) { db_model->setSQLDisabled(true); db_sql_reenabled=false; } } void ModelExportHelper::generateTempObjectNames(DatabaseModel *db_model) { QString tmp_name, old_name; QTextStream stream(&tmp_name); QDateTime dt=QDateTime::currentDateTime(); QCryptographicHash hash(QCryptographicHash::Md5); map obj_suffixes={ { ObjectType::Database, QString("db_") }, { ObjectType::Role, QString("rl_")}, { ObjectType::Tablespace, QString("tb_")} }; orig_obj_names.clear(); orig_obj_names[db_model]=db_model->getName(); for(auto &role : *db_model->getObjectList(ObjectType::Role)) { if(!role->isSystemObject()) orig_obj_names[role]=role->getName(); } for(auto &tabspc : *db_model->getObjectList(ObjectType::Tablespace)) { if(!tabspc->isSystemObject()) orig_obj_names[tabspc]=tabspc->getName(); } for(auto &obj : orig_obj_names) { stream << reinterpret_cast(obj.first) << QString("_") << dt.toTime_t(); //Generates an unique name for the object through md5 hash hash.addData(QByteArray(tmp_name.toStdString().c_str())); tmp_name=obj_suffixes[obj.first->getObjectType()] + hash.result().toHex(); old_name=obj.first->getName(); obj.first->setName(tmp_name.mid(0,15)); tmp_name.clear(); emit s_progressUpdated(progress, trUtf8("Renaming `%1' (%2) to `%3'") .arg(old_name) .arg(obj.first->getTypeName()) .arg(obj.first->getName())); } /* Invalidates the codes of all objects on database model in order to generate the SQL referencing the renamed object correctly */ db_model->setCodesInvalidated(); } void ModelExportHelper::restoreObjectNames(void) { for(auto &obj : orig_obj_names) obj.first->setName(obj.second); /* Invalidates the codes of all objects on database model in order to generate the SQL referencing the object's with their original names */ if(db_model) db_model->setCodesInvalidated(); } bool ModelExportHelper::isDuplicationError(const QString &error_code) { /* Error codes treated in this method 42P04 duplicate_database 42723 duplicate_function 42P06 duplicate_schema 42P07 duplicate_table 42710 duplicate_object 42701 duplicate_column 42P16 invalid_table_definition Reference: http://www.postgresql.org/docs/current/static/errcodes-appendix.html*/ static QStringList err_codes = {QString("42P04"), QString("42723"), QString("42P06"), QString("42P07"), QString("42710"), QString("42701"), QString("42P16")}; return(err_codes.contains(error_code)); } void ModelExportHelper::exportBufferToDBMS(const QString &buffer, Connection &conn, bool drop_objs) { Connection aux_conn; QString sql_buf=buffer, sql_cmd, aux_cmd, lin, msg, obj_name, obj_tp_name, tab_name, orig_conn_db_name, alter_tab=QString("ALTER TABLE"); vector db_sql_cmds; QTextStream ts; ObjectType obj_type=ObjectType::BaseObject; bool ddl_tk_found=false, is_create=false, is_drop=false; unsigned aux_prog=0, curr_size=0, buf_size=sql_buf.size(), factor=(db_name.isEmpty() ? 70 : 90); int pos=0, pos1=0, comm_cnt=0; //Regexp used to extract the object being created QRegExp obj_reg(QString("(CREATE|DROP|ALTER)(.)+(\n)")), tab_obj_reg(QString("^(%1)(.)+(ADD|DROP)( )(COLUMN|CONSTRAINT)( )*").arg(alter_tab)), drop_reg(QString("^((\\-\\-)+( )*)+(DROP)(.)+")), drop_tab_obj_reg(QString("^((\\-\\-)+( )*)+(%1)(.)+(DROP)(.)+").arg(alter_tab)), reg_aux; vector obj_types={ ObjectType::Role, ObjectType::Function, ObjectType::Trigger, ObjectType::Index, ObjectType::Policy, ObjectType::Rule, ObjectType::Table, ObjectType::View, ObjectType::Domain, ObjectType::Schema, ObjectType::Aggregate, ObjectType::OpFamily, ObjectType::OpClass, ObjectType::Operator, ObjectType::Sequence, ObjectType::Conversion, ObjectType::Cast, ObjectType::Language, ObjectType::Collation, ObjectType::Extension, ObjectType::Type, ObjectType::EventTrigger, ObjectType::ForeignDataWrapper, ObjectType::ForeignServer, ObjectType::UserMapping, ObjectType::ForeignTable, ObjectType::Database, ObjectType::BaseObject }; /* Extract each SQL command from the buffer and execute them separately. This is done to permit the user, in case of error, identify what object is wrongly configured. */ ts.setString(&sql_buf); if(!conn.isStablished()) { orig_conn_db_name = conn.getConnectionParam(Connection::ParamDbName); if(!db_name.isEmpty()) conn.setConnectionParam(Connection::ParamDbName, db_name); conn.connect(); } while(!ts.atEnd() && !export_canceled) { try { //Cleanup single line comments lin=ts.readLine(); curr_size+=lin.size(); aux_prog=progress + ((curr_size/static_cast(buf_size)) * factor); /* If the simulation mode is off and the drop objects option is checked, check if the current line matches one of the accepted drop commands (DROP [OBJECT] or ALTER TABLE...DROP) */ if(drop_objs && (drop_reg.exactMatch(lin) || drop_tab_obj_reg.exactMatch(lin))) { comm_cnt=lin.count(QString("--")); lin=lin.remove(QString("--")).trimmed(); /* If the count of comment indicators (--) is 1 indicates that the DDL of the object related to the DROP is enabled, so the DROP is executed otherwise ignored */ if(comm_cnt==1) { sql_cmd=lin + QString("\n"); ddl_tk_found=true; } } else { ddl_tk_found=(lin.indexOf(Attributes::DdlEndToken) >= 0); lin.remove(QRegExp(QString("^(--)+(.)+$"))); //If the line isn't empty after cleanup it will be included on sql command if(!lin.isEmpty()) sql_cmd += lin + QString("\n"); } //If the ddl end token is found if(ddl_tk_found || (!sql_cmd.isEmpty() && ts.atEnd())) { //Checking if the command is a column or constraint creation via ALTER TABLE aux_cmd=sql_cmd; pos=tab_obj_reg.indexIn(aux_cmd); if(pos >= 0) { aux_cmd.remove('"'); aux_cmd.remove(QString("IF EXISTS ")); obj_type=(aux_cmd.contains(QString("COLUMN")) ? ObjectType::Column : ObjectType::Constraint); reg_aux=QRegExp(QString("(COLUMN|CONSTRAINT)( )+")); //Extracting the table name pos=aux_cmd.indexOf(alter_tab) + alter_tab.size(); pos1=aux_cmd.indexOf(QString("ADD")); if(pos1 < 0) { pos1=aux_cmd.indexOf(QString("DROP")); is_drop=true; } tab_name=aux_cmd.mid(pos, pos1 - pos).simplified(); //Extracting the child object name (column | constraint) the one between pos=reg_aux.indexIn(aux_cmd, pos1); pos+=reg_aux.matchedLength(); pos1=aux_cmd.indexOf(" ", pos); obj_name=aux_cmd.mid(pos, pos1 - pos).simplified(); //Creating a fully qualified name for the object (schema.table.name) obj_name=tab_name + QString(".") + obj_name; if(is_drop) msg=trUtf8("Dropping object `%1' (%2)").arg(obj_name).arg(BaseObject::getTypeName(obj_type)); else msg=trUtf8("Creating object `%1' (%2)").arg(obj_name).arg(BaseObject::getTypeName(obj_type)); emit s_progressUpdated(aux_prog, msg, obj_type, sql_cmd); is_drop=false; } //Check if the regex matches the sql command else if(obj_reg.exactMatch(sql_cmd)) { //Get the fisrt line of the sql command, that contains the CREATE/DROP/ALTER ... statement lin=sql_cmd.mid(0, sql_cmd.indexOf('\n')); for(ObjectType obj_tp : obj_types) { if(export_canceled) break; obj_type=obj_tp; if(lin.startsWith(QString("CREATE")) || lin.startsWith(QString("ALTER"))) { if(obj_tp==ObjectType::Index) { lin.remove(QString("UNIQUE")); lin.remove(QString("CONCURRENTLY")); } else if(obj_tp==ObjectType::View) { lin.remove(QString("MATERIALIZED")); lin.remove(QString("RECURSIVE")); } else if(obj_tp==ObjectType::Table) { lin.remove(QString("UNLOGGED")); } else if(obj_tp==ObjectType::Function) { lin.remove(QString("OR REPLACE")); } } else if(lin.startsWith(QString("DROP"))) { lin.remove(QString("IF EXISTS")); lin.remove(QString("MATERIALIZED")); } lin=lin.simplified(); //Check if the keyword for the current object exists on string reg_aux.setPattern(QString("(CREATE|DROP|ALTER)( )(%1)").arg(BaseObject::getSQLName(obj_tp))); pos=reg_aux.indexIn(lin); if(pos >= 0) { is_create=lin.startsWith(QString("CREATE")); is_drop=(!is_create && lin.startsWith(QString("DROP"))); //Extracts from the line the string starting with the object's name lin=lin.mid(reg_aux.matchedLength(), sql_cmd.indexOf('\n')).simplified(); lin.remove('"'); if(obj_tp != ObjectType::BaseObject) { if(obj_tp!=ObjectType::Cast && obj_tp != ObjectType::UserMapping) { int spc_idx=lin.indexOf(' '); obj_name=lin.mid(0, (spc_idx >= 0 ? spc_idx + 1 : lin.size())); if(obj_tp!=ObjectType::Function) { obj_name=obj_name.remove('(').simplified(); obj_name=obj_name.remove(')').simplified(); } } else if(obj_tp == ObjectType::UserMapping) { obj_name.prepend(lin.remove(QString("FOR")).trimmed() + QChar('@')); } else { obj_name=QString("cast") + lin.replace(QString(" AS "),QString(",")); } //Stores the object type name obj_tp_name=BaseObject::getTypeName(obj_tp); obj_name.remove(';'); if(is_create) msg=trUtf8("Creating object `%1' (%2)").arg(obj_name).arg(obj_tp_name); else if(is_drop) msg=trUtf8("Dropping object `%1' (%2)").arg(obj_name).arg(obj_tp_name); else msg=trUtf8("Changing object `%1' (%2)").arg(obj_name).arg(obj_tp_name); } // If the type of the object being create can't be identified else { QString aux_cmd_type; if(is_create) aux_cmd_type = QString("CREATE"); else if(is_drop) aux_cmd_type = QString("DROP"); else aux_cmd_type = QString("ALTER"); msg=trUtf8("Running auxiliary `%1' command...").arg(aux_cmd_type); } break; } } emit s_progressUpdated(aux_prog, msg, obj_type, sql_cmd); is_create=is_drop=false; msg.clear(); } else if(!sql_cmd.trimmed().isEmpty()) { //General commands like grant, revoke or set aren't explicitly shown emit s_progressUpdated(aux_prog, trUtf8("Running auxiliary command."), ObjectType::BaseObject, sql_cmd); } //Executes the extracted SQL command if(!sql_cmd.isEmpty()) { if(obj_type != ObjectType::Database) conn.executeDDLCommand(sql_cmd); else db_sql_cmds.push_back(sql_cmd); } sql_cmd.clear(); ddl_tk_found=false; } if(ts.atEnd() && !db_sql_cmds.empty()) { conn.close(); aux_conn=conn; if(!orig_conn_db_name.isEmpty()) aux_conn.setConnectionParam(Connection::ParamDbName, orig_conn_db_name); aux_conn.connect(); for(QString cmd : db_sql_cmds) aux_conn.executeDDLCommand(cmd); } } catch(Exception &e) { if(ddl_tk_found) ddl_tk_found=false; handleSQLError(e, sql_cmd, ignore_dup); sql_cmd.clear(); } } if(!db_name.isEmpty()) emit s_exportFinished(); } void ModelExportHelper::updateProgress(int prog, QString object_id, unsigned obj_type) { int aux_prog=progress + (prog/progress); sql_gen_progress=prog; if(aux_prog > 100) aux_prog=100; emit s_progressUpdated(aux_prog, object_id, static_cast(obj_type), "", sender()==db_model); } void ModelExportHelper::setExportToDBMSParams(DatabaseModel *db_model, Connection *conn, const QString &pgsql_ver, bool ignore_dup, bool drop_db, bool drop_objs, bool simulate, bool use_rand_names) { this->db_model=db_model; this->connection=conn; this->pgsql_ver=pgsql_ver; this->ignore_dup=ignore_dup; this->simulate=simulate; this->drop_db=drop_db && !drop_objs; this->drop_objs=drop_objs && !drop_db; this->use_tmp_names=use_rand_names; this->sql_buffer.clear(); this->db_name.clear(); this->errors.clear(); } void ModelExportHelper::setExportToDBMSParams(const QString &sql_buffer, Connection *conn, const QString &db_name, bool ignore_dup) { this->sql_buffer=sql_buffer; this->connection=conn; this->db_name=db_name; this->ignore_dup=ignore_dup; this->simulate=false; this->drop_db=false; this->use_tmp_names=false; this->errors.clear(); } void ModelExportHelper::setExportToSQLParams(DatabaseModel *db_model, const QString &filename, const QString &pgsql_ver) { this->db_model=db_model; this->filename=filename; this->pgsql_ver=pgsql_ver; } void ModelExportHelper::setExportToPNGParams(ObjectsScene *scene, QGraphicsView *viewp, const QString &filename, double zoom, bool show_grid, bool show_delim, bool page_by_page) { this->scene=scene; this->viewp=viewp; this->filename=filename; this->zoom=zoom; this->show_grid=show_grid; this->show_delim=show_delim; this->page_by_page=page_by_page; } void ModelExportHelper::setExportToSVGParams(ObjectsScene *scene, const QString &filename, bool show_grid, bool show_delim) { this->scene=scene; this->filename=filename; this->show_grid=show_grid; this->show_delim=show_delim; } void ModelExportHelper::setExportToDataDictParams(DatabaseModel *db_model, const QString &path, bool browsable, bool splitted) { this->db_model=db_model; this->filename=path; this->browsable=browsable; this->splitted=splitted; } void ModelExportHelper::exportToDBMS(void) { if(connection) { if(sql_buffer.isEmpty()) exportToDBMS(db_model, *connection, pgsql_ver, ignore_dup, drop_db, drop_objs, simulate, use_tmp_names); else { try { exportBufferToDBMS(sql_buffer, *connection); } catch(Exception &e) { abortExport(e); } } resetExportParams(); } } void ModelExportHelper::exportToPNG(void) { try { exportToPNG(scene, filename, zoom, show_grid, show_delim, page_by_page, viewp); resetExportParams(); } catch(Exception &e) { abortExport(e); } } void ModelExportHelper::exportToSVG(void) { try { exportToSVG(scene, filename, show_grid, show_delim); resetExportParams(); } catch(Exception &e) { abortExport(e); } } void ModelExportHelper::exportToSQL(void) { try { exportToSQL(db_model, filename, pgsql_ver); resetExportParams(); } catch(Exception &e) { abortExport(e); } } void ModelExportHelper::exportToDataDict(void) { try { exportToDataDict(db_model, filename, browsable, splitted); resetExportParams(); } catch(Exception &e) { abortExport(e); } } void ModelExportHelper::cancelExport(void) { export_canceled=true; } pgmodeler-0.9.2/libpgmodeler_ui/src/modelexporthelper.h000066400000000000000000000252701360462764600233700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelExportHelper \brief Implements the base operations to export models (forward engineering) */ #ifndef MODEL_EXPORT_HELPER_H #define MODEL_EXPORT_HELPER_H #include "modelwidget.h" #include "connection.h" class ModelExportHelper: public QObject { private: Q_OBJECT //! \brief Stores the total progress int progress, //! \brief Stores the sql generation progress sql_gen_progress; /*! \brief Indicates if the database was created on the server (only dbms export). This attribute is used to drop the database from server */ bool db_created; //! \brief PostgreSQL version used by the exporter (only in thread mode) QString pgsql_ver; //! \brief Indicates to the exporter to ignore object duplicity (only in thread mode) bool ignore_dup, //! \brief Indicates to the exporter to run as a simulator[model validation] (only in thread mode) simulate, //! \brief Indicates to the exporter to drop database before export drop_db, //! \brief Indicates to the exporter to drop the objects that are enabled and have a DROP command attached (see SQL source for objects) drop_objs, //! \brief Indicates to the exporter to generate random names for database, roles and tablespaces before export (only in thread mode) use_tmp_names, //! \brief Indicates if the exporting thread was canceled by the user (only in thread mode) export_canceled, db_sql_reenabled; //! \brief Database model used as reference on export operation (only in thread mode) DatabaseModel *db_model; //! \brief Database connection used to export data to DBMS (only in thread mode) Connection *connection; QString sql_buffer, db_name; //! \brief List of ignored error codes QStringList ignored_errors; vector errors; /*! \brief Indicates which role / tablespaces were created on server (only dbms export). This attribute is used to drop the created roles / tablespaces from server */ map created_objs; //! \brief Stores the current state of ALTER command generation for table columns/constraints map alter_cmds_status; //! \brief Stores the original object names before the call of generateRandomObjectNames() map orig_obj_names; ObjectsScene *scene; QGraphicsView *viewp; QString filename; double zoom; bool show_grid, show_delim, page_by_page, splitted, browsable; //! \brief Saves the current state of ALTER command generaton for table columns/constraints void saveGenAtlerCmdsStatus(DatabaseModel *db_model); //! \brief Retores the previous ALTER command generation state for table columns/constraints void restoreGenAtlerCmdsStatus(void); //! \brief Revert the dbms export process, removing the created database, roles and tablespaces void undoDBMSExport(DatabaseModel *db_model, Connection &conn, bool use_tmp_names); /*! \brief Cause the names of the database, roles and tablespaces to be replaced by a temporary name in order to avoid duplicity error when exporting. This feature is only useful when validating the model against a server which some of the objects (at cluster level) still exists */ void generateTempObjectNames(DatabaseModel *db_model); //! \brief Restore the original name of the database, roles and tablespaces void restoreObjectNames(void); //! \brief Exports the contents of the buffer to a previously opened connection void exportBufferToDBMS(const QString &buffer, Connection &conn, bool drop_objs=false); //! \brief Returns if the error code is one of the treated by the export process as object duplication error bool isDuplicationError(const QString &error_code); //! \brief Restore the export parameters to their default values void resetExportParams(void); /*! \brief Aborts the export process by redirecting the provided exception in form of a signal or to the main loop, depending on the mode the helper is being used (in a thread or locally) */ void abortExport(Exception &e); /*! brief Handles the provided exception related to the sql command can 1) emit a ignored error signal if the error code in the exception is one of the ignored ones 2) append the error in a list of errors generated during the export process 3) abort the export by immediatelly redirecting the error to the user */ void handleSQLError(Exception &e, const QString &sql_cmd, bool ignore_dup); public: ModelExportHelper(QObject *parent = nullptr); /*! \brief Determines which error codes must be ignored during the export process. There must be some caution when ignore some error codes because the export may create an incomplete database or even reach unknown behaviors. Error catalog is available at: postgresql.org/docs/current/static/errcodes-appendix.html */ void setIgnoredErrors(const QStringList &err_codes); //! \brief Exports the model to a named SQL file. The PostgreSQL version syntax must be specified. void exportToSQL(DatabaseModel *db_model, const QString &filename, const QString &pgsql_ver); /*! \brief Exports the model to a named PNG image. The boolean parameters controls the grid exhibition as well the page delimiters on the output image. The zoom parameter controls the zoom applied to the viewport before draw it on the pixmap. It is possible to specified an viewport (QGraphicsView instance) previously allocated and the method will use it instead of allocate a local one. This is a workaround to error raised by QCoreApplication::sendPostedEvents when running the helper in a thread */ void exportToPNG(ObjectsScene *scene, const QString &filename, double zoom, bool show_grid, bool show_delim, bool page_by_page, QGraphicsView *viewp=nullptr); //! \brief Exports the model to a named SVG file. void exportToSVG(ObjectsScene *scene, const QString &filename, bool show_grid, bool show_delim); /*! \brief Exports the model directly to the DBMS. A valid connection must be specified. The PostgreSQL version is optional, since the helper identifies the version from the server. The boolean parameter make the helper to ignore object duplicity errors. \note The params drop_db and drop_objs can't be true at the same time. */ void exportToDBMS(DatabaseModel *db_model, Connection conn, const QString &pgsql_ver=QString(), bool ignore_dup=false, bool drop_db=false, bool drop_objs=false, bool simulate=false, bool use_tmp_names=false); /*! \brief Exports the model to a named data dictionary. The options browsable and splitted indicate, * respectively, that the data dictionary should have an object index and the dictionary should be splitted * in different files per table */ void exportToDataDict(DatabaseModel *db_model, const QString &path, bool browsable, bool splitted); /*! \brief Configures the DBMS export params before start the export thread (when in thread mode). This form receive a database model as input and the sql code to be exported will be generated from it. \note The params drop_db and drop_objs can't be true at the same time. */ void setExportToDBMSParams(DatabaseModel *db_model, Connection *conn, const QString &pgsql_ver=QString(), bool ignore_dup=false, bool drop_db=false, bool drop_objs=false, bool simulate=false, bool use_tmp_names=false); /*! \brief Configures the DBMS export params before start the export thread (when in thread mode). This form receive a previously generated sql buffer to be exported the the helper */ void setExportToDBMSParams(const QString &sql_buffer, Connection *conn, const QString &db_name, bool ignore_dup=false); /*! \brief Configures the SQL export params before start the export thread (when in thread mode). This form receive the model, output filename and pgsql version to be used */ void setExportToSQLParams(DatabaseModel *db_model, const QString &filename, const QString &pgsql_ver); /*! \brief Configures the PNG export params before start the export thread (when in thread mode). This form receive the objects scene, a viewport, the output filename, zoom factor, grid options and page by page export options */ void setExportToPNGParams(ObjectsScene *scene, QGraphicsView *viewp, const QString &filename, double zoom, bool show_grid, bool show_delim, bool page_by_page); /*! \brief Configures the SVG export params before start the export thread (when in thread mode). This form receive the objects scene, the output filename, grid options. */ void setExportToSVGParams(ObjectsScene *scene, const QString &filename, bool show_grid, bool show_delim); /*! \brief Configures the Data Dictionary export params before start the export thread (when in thread mode). This form receive the database model, the output path and browsabe and splitted options. */ void setExportToDataDictParams(DatabaseModel *db_model, const QString &path, bool browsable, bool splitted); signals: //! \brief This singal is emitted whenever the export progress changes void s_progressUpdated(int progress, QString msg, ObjectType obj_type=ObjectType::BaseObject, QString cmd=QString(), bool is_code_gen=false); //! \brief This signal is emited when the export has finished void s_exportFinished(void); //! \brief This signal is emited when the export has been cancelled void s_exportCanceled(void); //! \brief This signal is emited when the export has encountered a critical error (only in thread mode) void s_exportAborted(Exception e); //! \brief This signal is emited when the export has encountered a ignorable error (only in thread mode) void s_errorIgnored(QString err_code, QString err_msg, QString cmd); public slots: void exportToDBMS(void); void exportToPNG(void); void exportToSVG(void); void exportToSQL(void); void exportToDataDict(void); void cancelExport(void); private slots: //! \brief Updates the exporting progress with the internal progress of sql generation of objects void updateProgress(int progress, QString object_id, unsigned obj_type); friend class ModelValidationHelper; friend class ModelExportForm; friend class ModelDatabaseDiffForm; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelfixform.cpp000066400000000000000000000141211360462764600226450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelfixform.h" #include "configurationform.h" #include #include "pgmodeleruins.h" const QString ModelFixForm::PgModelerCli=QString("pgmodeler-cli"); ModelFixForm::ModelFixForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { map confs=GeneralConfigWidget::getConfigurationParams(); setupUi(this); hideEvent(nullptr); PgModelerUiNs::configureWidgetFont(invalid_cli_lbl, PgModelerUiNs::MediumFontFactor); PgModelerUiNs::configureWidgetFont(message_lbl, PgModelerUiNs::MediumFontFactor); PgModelerUiNs::configureWidgetFont(not_found_lbl, PgModelerUiNs::MediumFontFactor); //Configuring font style for output widget if(!confs[Attributes::Configuration][Attributes::CodeFont].isEmpty()) { double size=confs[Attributes::Configuration][Attributes::CodeFontSize].toDouble(); if(size < 5.0) size=5.0; output_txt->setFontFamily(confs[Attributes::Configuration][Attributes::CodeFont]); output_txt->setFontPointSize(size); } connect(&pgmodeler_cli_proc, SIGNAL(readyReadStandardOutput()), this, SLOT(updateOutput())); connect(&pgmodeler_cli_proc, SIGNAL(readyReadStandardError()), this, SLOT(updateOutput())); connect(&pgmodeler_cli_proc, SIGNAL(finished(int)), this, SLOT(handleProcessFinish(int))); connect(fix_btn, SIGNAL(clicked()), this, SLOT(fixModel())); connect(sel_cli_exe_tb, SIGNAL(clicked()), this, SLOT(selectFile())); connect(sel_in_file_tb, SIGNAL(clicked()), this, SLOT(selectFile())); connect(sel_out_file_tb, SIGNAL(clicked()), this, SLOT(selectFile())); connect(input_file_edt, SIGNAL(textChanged(QString)), this, SLOT(enableFix())); connect(output_file_edt, SIGNAL(textChanged(QString)), this, SLOT(enableFix())); connect(pgmodeler_cli_edt, SIGNAL(textChanged(QString)), this, SLOT(enableFix())); connect(close_btn, SIGNAL(clicked()), this, SLOT(reject())); } void ModelFixForm::hideEvent(QHideEvent *) { message_frm->setVisible(false); pgmodeler_cli_lbl->setVisible(false); pgmodeler_cli_edt->setVisible(false); sel_cli_exe_tb->setVisible(false); invalid_cli_lbl->setVisible(false); input_file_edt->clear(); output_file_edt->clear(); output_txt->setPlainText(trUtf8("Waiting process to start...")); load_model_chk->setChecked(true); } int ModelFixForm::exec(void) { QFileInfo fi(GlobalAttributes::PgModelerCLIPath); //Show an warning if the cli command doesn't exists if(!fi.exists()) { not_found_lbl->setText(trUtf8("Could not locate %1 tool on %2. The fix process can't continue! Please check pgModeler installation or try to manually specify the command below.") .arg(PgModelerCli).arg(fi.absoluteDir().absolutePath())); message_frm->setVisible(true); pgmodeler_cli_lbl->setVisible(true); pgmodeler_cli_edt->setVisible(true); sel_cli_exe_tb->setVisible(true); } else pgmodeler_cli_edt->setText(GlobalAttributes::PgModelerCLIPath); return(QDialog::exec()); } void ModelFixForm::enableFix(void) { if(!pgmodeler_cli_edt->text().isEmpty()) { QFileInfo fi(pgmodeler_cli_edt->text()); bool visible=!fi.exists() || fi.baseName()!=PgModelerCli; invalid_cli_lbl->setVisible(visible); message_frm->setVisible(visible); } else { invalid_cli_lbl->setVisible(false); message_frm->setVisible(false); } fix_btn->setEnabled(!input_file_edt->text().isEmpty() && !output_file_edt->text().isEmpty() && !pgmodeler_cli_edt->text().isEmpty() && !invalid_cli_lbl->isVisible()); } void ModelFixForm::fixModel(void) { QString cmd=QString("\"%1\""); #ifdef Q_OS_MAC cmd+=QString(" pgmodeler-cli"); #endif cmd+=QString(" --fix-model --fix-tries=%2 --input=\"%3\" --output=\"%4\""); cmd=cmd.arg(pgmodeler_cli_edt->text()) .arg(fix_tries_sb->value()) .arg(input_file_edt->text()) .arg(output_file_edt->text()); output_txt->clear(); pgmodeler_cli_proc.blockSignals(false); pgmodeler_cli_proc.start(cmd); } void ModelFixForm::selectFile(void) { QObject *sender_obj=sender(); QFileDialog file_dlg; QLineEdit *txt=nullptr; if(sender_obj==sel_cli_exe_tb) { QString cli_cmd=PgModelerCli; txt=pgmodeler_cli_edt; #ifdef Q_OS_WIN cli_cmd+=QString(".exe"); #endif file_dlg.selectFile(cli_cmd); file_dlg.setFileMode(QFileDialog::ExistingFile); file_dlg.setNameFilter(trUtf8("pgModeler command line tool (%1)").arg(cli_cmd)); file_dlg.setWindowTitle(QString("Browse pgmodeler-cli command...")); } else { if(sender_obj==sel_in_file_tb) txt=input_file_edt; else txt=output_file_edt; file_dlg.setWindowTitle(QString("Select model file...")); } file_dlg.exec(); if(file_dlg.result()==QDialog::Accepted && !file_dlg.selectedFiles().isEmpty()) txt->setText(file_dlg.selectedFiles().at(0)); } void ModelFixForm::updateOutput(void) { QTextCursor cursor; QString txt=output_txt->toPlainText(); //Append both stdout and stderr txt.append(pgmodeler_cli_proc.readAllStandardOutput()); txt.append(pgmodeler_cli_proc.readAllStandardError()); output_txt->setPlainText(txt); //Moving the output to the last line cursor=output_txt->textCursor(); cursor.movePosition(QTextCursor::End); output_txt->setTextCursor(cursor); } void ModelFixForm::handleProcessFinish(int res) { /* If the model as sucessfully fixed and user requested the loading */ if(res==0 && load_model_chk->isChecked()) { //Emit a signal indicating the file to be loaded emit s_modelLoadRequested(output_file_edt->text()); this->close(); } pgmodeler_cli_proc.blockSignals(true); } pgmodeler-0.9.2/libpgmodeler_ui/src/modelfixform.h000066400000000000000000000030171360462764600223140ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelFixForm \brief Implements an interface to pgmodeler-cli --fix-model command. */ #ifndef MODEL_FIX_FORM_H #define MODEL_FIX_FORM_H #include #include "globalattributes.h" #include "ui_modelfixform.h" class ModelFixForm: public QDialog, public Ui::ModelFixForm { private: Q_OBJECT static const QString PgModelerCli; //! \brief Process used to execute pgmodeler-cli QProcess pgmodeler_cli_proc; void hideEvent(QHideEvent *); public: ModelFixForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); public slots: int exec(void); private slots: void enableFix(void); void fixModel(void); void selectFile(void); void updateOutput(void); void handleProcessFinish(int res); signals: void s_modelLoadRequested(QString); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelnavigationwidget.cpp000066400000000000000000000075001360462764600245410ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelnavigationwidget.h" ModelNavigationWidget::ModelNavigationWidget(QWidget *parent): QWidget(parent) { setupUi(this); connect(models_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentModel())); connect(close_tb, &QToolButton::clicked, [&](){ emit s_modelCloseRequested(models_cmb->currentIndex()); }); connect(next_tb, &QToolButton::clicked, [&](){ models_cmb->setCurrentIndex(models_cmb->currentIndex()+1); }); connect(previous_tb, &QToolButton::clicked, [&](){ models_cmb->setCurrentIndex(models_cmb->currentIndex()-1); }); connect(models_cmb, SIGNAL(highlighted(int)), this, SLOT(showTooltip(int))); previous_tb->setToolTip(previous_tb->toolTip() + QString(" (%1)").arg(previous_tb->shortcut().toString())); next_tb->setToolTip(next_tb->toolTip() + QString(" (%1)").arg(next_tb->shortcut().toString())); close_tb->setToolTip(close_tb->toolTip() + QString(" (%1)").arg(close_tb->shortcut().toString())); } int ModelNavigationWidget::getCurrentIndex(void) { return(models_cmb->currentIndex()); } QString ModelNavigationWidget::getText(int idx) { if(idx < 0 || idx >= models_cmb->count()) return(QString()); else return(models_cmb->itemText(idx)); } QList ModelNavigationWidget::getModelWidgets() { return(model_wgts); } void ModelNavigationWidget::addModel(ModelWidget *model) { if(model) { QString tooltip; setEnabled(true); models_cmb->blockSignals(true); tooltip=model->getFilename(); if(tooltip.isEmpty()) tooltip=trUtf8("(model not saved yet)"); models_cmb->addItem(model->getDatabaseModel()->getName(), tooltip); models_cmb->setCurrentIndex(models_cmb->count()-1); models_cmb->setToolTip(tooltip); models_cmb->blockSignals(false); model_wgts.append(model); enableNavigationButtons(); } } void ModelNavigationWidget::updateModelText(int idx, const QString &text, const QString &filename) { if(idx >= 0 && idx < models_cmb->count()) { models_cmb->setItemText(idx, QString("%1").arg(text)); models_cmb->setItemData(idx, filename); if(idx==models_cmb->currentIndex()) models_cmb->setToolTip(filename); } } void ModelNavigationWidget::removeModel(int idx) { models_cmb->blockSignals(true); models_cmb->removeItem(idx); this->setEnabled(models_cmb->count() >= 1); if(models_cmb->count() >= 1) models_cmb->setToolTip(models_cmb->currentData().toString()); models_cmb->blockSignals(false); model_wgts.removeAt(idx); enableNavigationButtons(); emit s_modelRemoved(idx); } void ModelNavigationWidget::setCurrentModel(void) { models_cmb->setToolTip(models_cmb->currentData().toString()); enableNavigationButtons(); if(models_cmb->currentIndex() >= 0) emit s_currentModelChanged(models_cmb->currentIndex()); } void ModelNavigationWidget::enableNavigationButtons(void) { previous_tb->setEnabled(models_cmb->currentIndex() > 0 && models_cmb->count() > 1); next_tb->setEnabled(models_cmb->currentIndex() >= 0 && models_cmb->currentIndex()!=(models_cmb->count()-1)); } void ModelNavigationWidget::showTooltip(int idx) { QString tooltip=models_cmb->itemData(idx).toString(); QToolTip::showText(QCursor::pos(), tooltip); } pgmodeler-0.9.2/libpgmodeler_ui/src/modelnavigationwidget.h000066400000000000000000000037201360462764600242060ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelNavigationWidget \brief Implements the operations to navigate through openend models without use tabs. */ #ifndef MODEL_NAVIGATION_WIDGET_H #define MODEL_NAVIGATION_WIDGET_H #include #include "modelwidget.h" #include "ui_modelnavigationwidget.h" class ModelNavigationWidget: public QWidget, public Ui::ModelNavigationWidget { private: Q_OBJECT QList model_wgts; void enableNavigationButtons(void); public: ModelNavigationWidget(QWidget * parent = nullptr); //! \brief Returns the combo's current index int getCurrentIndex(void); //! \brief Returns the text of the combo's current index QString getText(int idx); QList getModelWidgets(void); public slots: //! \brief Adds the model to the listing void addModel(ModelWidget *model); //! \brief Updates a model's info on the listing void updateModelText(int idx, const QString &text, const QString &filename); //! \brief Remove an entry for a model using its index void removeModel(int idx); private slots: void setCurrentModel(void); void showTooltip(int idx); signals: void s_modelRemoved(int idx); void s_modelCloseRequested(int idx); void s_currentModelChanged(int idx); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelobjectswidget.cpp000066400000000000000000000734731360462764600240470ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelobjectswidget.h" #include "databaseimportform.h" #include "pgmodeleruins.h" ModelObjectsWidget::ModelObjectsWidget(bool simplified_view, QWidget *parent) : QWidget(parent) { setupUi(this); model_wgt=nullptr; db_model=nullptr; setModel(db_model); title_wgt->setVisible(!simplified_view); this->simplified_view=simplified_view; this->save_tree_state=!simplified_view; enable_obj_creation=simplified_view; select_tb->setVisible(simplified_view); cancel_tb->setVisible(simplified_view); options_tb->setVisible(!simplified_view); visibleobjects_grp->setVisible(false); filter_wgt->setVisible(simplified_view); selected_object=nullptr; splitter->handle(1)->setEnabled(false); connect(objectstree_tw,SIGNAL(itemPressed(QTreeWidgetItem*,int)),this, SLOT(selectObject(void))); connect(objectslist_tbw,SIGNAL(itemPressed(QTableWidgetItem*)),this, SLOT(selectObject(void))); connect(expand_all_tb, SIGNAL(clicked(void)), objectstree_tw, SLOT(expandAll(void))); connect(collapse_all_tb, SIGNAL(clicked(void)), this, SLOT(collapseAll(void))); if(!simplified_view) { widgets_conf.setValue(QString("splitterSize"), splitter->saveState()); connect(options_tb,SIGNAL(clicked(void)),this,SLOT(changeObjectsView(void))); connect(visibleobjects_lst,SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(setObjectVisible(QListWidgetItem*))); connect(select_all_tb,SIGNAL(clicked(bool)), this, SLOT(setAllObjectsVisible(bool))); connect(clear_all_tb,SIGNAL(clicked(bool)), this, SLOT(setAllObjectsVisible(bool))); connect(objectstree_tw,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this, SLOT(editObject(void))); connect(objectslist_tbw,SIGNAL(itemDoubleClicked(QTableWidgetItem*)),this, SLOT(editObject(void))); connect(hide_tb, SIGNAL(clicked(bool)), this, SLOT(hide(void))); ObjectFinderWidget::updateObjectTypeList(visibleobjects_lst); setAllObjectsVisible(true); objectslist_tbw->installEventFilter(this); objectstree_tw->installEventFilter(this); } else { setMinimumSize(250, 300); setWindowModality(Qt::ApplicationModal); setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint | Qt::WindowTitleHint); connect(objectstree_tw,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this, SLOT(close(void))); connect(objectslist_tbw,SIGNAL(itemDoubleClicked(QTableWidgetItem*)),this, SLOT(close(void))); connect(select_tb,SIGNAL(clicked(void)),this,SLOT(close(void))); connect(cancel_tb,SIGNAL(clicked(void)),this,SLOT(close(void))); } connect(tree_view_tb,SIGNAL(clicked(void)),this,SLOT(changeObjectsView(void))); connect(list_view_tb,SIGNAL(clicked(void)),this,SLOT(changeObjectsView(void))); connect(filter_edt, SIGNAL(textChanged(QString)), this, SLOT(filterObjects())); connect(by_id_chk, SIGNAL(toggled(bool)), this, SLOT(filterObjects())); } bool ModelObjectsWidget::eventFilter(QObject *object, QEvent *event) { if(event->type() == QEvent::FocusOut && (object==objectslist_tbw || object==objectstree_tw)) { QFocusEvent *evnt=dynamic_cast(event); if(evnt->reason()==Qt::MouseFocusReason) { objectslist_tbw->clearSelection(); objectstree_tw->clearSelection(); if(model_wgt) model_wgt->configurePopupMenu({}); return(true); } } return(QWidget::eventFilter(object, event)); } void ModelObjectsWidget::hide(void) { QWidget::hide(); emit s_visibilityChanged(false); } void ModelObjectsWidget::showObjectMenu(void) { if(selected_object && QApplication::mouseButtons()==Qt::RightButton && model_wgt && !simplified_view) model_wgt->popup_menu.exec(QCursor::pos()); } void ModelObjectsWidget::editObject(void) { if(selected_object && model_wgt && !simplified_view) { //If the user double-clicked the item "Permission (n)" on tree view if(sender()==objectstree_tw && objectstree_tw->currentItem() && objectstree_tw->currentItem()->data(1, Qt::UserRole).toUInt() == enum_cast(ObjectType::Permission)) model_wgt->showObjectForm(ObjectType::Permission, reinterpret_cast(objectstree_tw->currentItem()->data(0, Qt::UserRole).value())); //If the user double-clicked a permission on list view else if(sender()==objectslist_tbw && objectslist_tbw->currentRow() >= 0) { BaseObject *obj=reinterpret_cast(objectslist_tbw->item(objectslist_tbw->currentRow(), 0)->data(Qt::UserRole).value()); Permission *perm=dynamic_cast(obj); if(perm) model_wgt->showObjectForm(ObjectType::Permission, perm->getObject()); else model_wgt->editObject(); } else model_wgt->editObject(); } } void ModelObjectsWidget::selectObject(void) { ObjectType obj_type=ObjectType::BaseObject; ModelWidget *model_wgt=nullptr; if(!simplified_view && this->model_wgt) model_wgt=this->model_wgt; else if(simplified_view) model_wgt=db_model->getModelWidget(); if(tree_view_tb->isChecked()) { QTreeWidgetItem *tree_item=objectstree_tw->currentItem(); if(tree_item) { obj_type=static_cast(tree_item->data(1,Qt::UserRole).toUInt()); selected_object=reinterpret_cast(tree_item->data(0,Qt::UserRole).value()); } //If user select a group item popups a "New [OBJECT]" menu if((!simplified_view || (simplified_view && enable_obj_creation)) && !selected_object && QApplication::mouseButtons()==Qt::RightButton && obj_type!=ObjectType::Column && obj_type!=ObjectType::Constraint && obj_type!=ObjectType::Rule && obj_type!=ObjectType::Index && obj_type!=ObjectType::Trigger && obj_type!=ObjectType::Permission) { QAction act(QPixmap(PgModelerUiNs::getIconPath(obj_type)), trUtf8("New") + QString(" ") + BaseObject::getTypeName(obj_type), nullptr); QMenu popup; //If not a relationship, connect the action to the addNewObject method of the model wiget if(obj_type!=ObjectType::Relationship) { act.setData(QVariant(enum_cast(obj_type))); connect(&act, SIGNAL(triggered()), model_wgt, SLOT(addNewObject())); } //Case is a relationship, insert the relationship menu of the model wiget into the action else act.setMenu(model_wgt->rels_menu); if(simplified_view && enable_obj_creation) connect(model_wgt->getDatabaseModel(), SIGNAL(s_objectAdded(BaseObject*)), this, SLOT(selectCreatedObject(BaseObject *)), Qt::QueuedConnection); popup.addAction(&act); popup.exec(QCursor::pos()); disconnect(&act,nullptr,model_wgt,nullptr); disconnect(model_wgt->getDatabaseModel(),nullptr, this,nullptr); } } else { QTableWidgetItem *tab_item=objectslist_tbw->item(objectslist_tbw->currentRow(), 0); if(tab_item) { selected_object=reinterpret_cast(tab_item->data(Qt::UserRole).value()); obj_type=selected_object->getObjectType(); } } if(obj_type!=ObjectType::Permission && selected_object && !simplified_view) { model_wgt->scene->clearSelection(); model_wgt->configureObjectMenu(selected_object); showObjectMenu(); } } QVariant ModelObjectsWidget::generateItemValue(BaseObject *object) { return(QVariant::fromValue(reinterpret_cast(object))); } QTreeWidgetItem *ModelObjectsWidget::createItemForObject(BaseObject *object, QTreeWidgetItem *root, bool update_perms) { QTreeWidgetItem *item=nullptr; QFont font; QString str_aux; unsigned rel_type=0; ConstraintType constr_type; ObjectType obj_type; TableObject *tab_obj=nullptr; QString obj_name; if(!object) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); obj_type=object->getObjectType(); tab_obj=dynamic_cast(object); item=new QTreeWidgetItem(root); if(obj_type==ObjectType::Function) { Function *func=dynamic_cast(object); func->createSignature(false); item->setText(0,func->getSignature()); obj_name=func->getSignature(); func->createSignature(true); } else if(obj_type==ObjectType::Operator) { Operator *oper=dynamic_cast(object); item->setText(0, oper->getSignature(false)); obj_name=oper->getSignature(false); } else if(obj_type==ObjectType::OpClass || obj_type == ObjectType::OpFamily) { obj_name=object->getSignature(false); obj_name.replace(QRegExp("( )+(USING)( )+"), QString(" [")); obj_name+=QChar(']'); item->setText(0,obj_name); } else { item->setText(0,object->getName()); obj_name=object->getName(); } item->setToolTip(0, QString("%1 (id: %2)").arg(obj_name).arg(object->getObjectId())); item->setData(0, Qt::UserRole, generateItemValue(object)); item->setText(1, QString::number(object->getObjectId())); if(update_perms) updatePermissionTree(item, object); font=item->font(0); font.setStrikeOut(object->isSQLDisabled() && !object->isSystemObject()); if(tab_obj && tab_obj->isAddedByRelationship()) { font.setItalic(true); item->setForeground(0,BaseObjectView::getFontStyle(Attributes::InhColumn).foreground()); } else if(object->isProtected() || object->isSystemObject()) { font.setItalic(true); item->setForeground(0,BaseObjectView::getFontStyle(Attributes::ProtColumn).foreground()); } item->setFont(0,font); if(obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Relationship) { rel_type=dynamic_cast(object)->getRelationshipType(); if(obj_type==ObjectType::BaseRelationship) { if(rel_type==BaseRelationship::RelationshipFk) str_aux=QString("fk"); else str_aux=QString("tv"); } else if(rel_type==BaseRelationship::Relationship11) str_aux=QString("11"); else if(rel_type==BaseRelationship::Relationship1n) str_aux=QString("1n"); else if(rel_type==BaseRelationship::RelationshipNn) str_aux=QString("nn"); else if(rel_type==BaseRelationship::RelationshipDep) str_aux=QString("dep"); else if(rel_type==BaseRelationship::RelationshipGen) str_aux=QString("gen"); } else if(obj_type==ObjectType::Constraint) { constr_type=dynamic_cast(object)->getConstraintType(); if(constr_type==ConstraintType::PrimaryKey) str_aux=QString("_%1").arg(TableObjectView::TextPrimaryKey); else if(constr_type==ConstraintType::ForeignKey) str_aux=QString("_%1").arg(TableObjectView::TextForeignKey); else if(constr_type==ConstraintType::Check) str_aux=QString("_%1").arg(TableObjectView::TextCheck); else if(constr_type==ConstraintType::Unique) str_aux=QString("_%1").arg(TableObjectView::TextUnique); else if(constr_type==ConstraintType::Exclude) str_aux=QString("_%1").arg(TableObjectView::TextExclude); } item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(obj_type) + str_aux))); return(item); } void ModelObjectsWidget::setObjectVisible(ObjectType obj_type, bool visible) { if(obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::BaseTable) visible_objs_map[obj_type]=visible; if(visible && simplified_view) { if(obj_type!=ObjectType::Database) visible_objs_map[ObjectType::Database]=true; if(TableObject::isTableObject(obj_type)) { visible_objs_map[ObjectType::Table]=visible_objs_map[ObjectType::Schema]=true; if(obj_type == ObjectType::Column || obj_type == ObjectType::Constraint || obj_type == ObjectType::Trigger) visible_objs_map[ObjectType::ForeignTable]=true; } if(BaseObject::acceptsSchema(obj_type)) visible_objs_map[ObjectType::Schema]=true; } } void ModelObjectsWidget::setObjectVisible(QListWidgetItem *item) { ObjectType obj_type; //Get the object type related to the selected item obj_type=static_cast(item->data(Qt::UserRole).toInt()); //Set the visibility of the object type setObjectVisible(obj_type, item->checkState()==Qt::Checked); //Updates the entire objects view (list and tree) to reflect the modification updateObjectsView(); } void ModelObjectsWidget::setAllObjectsVisible(bool value) { ObjectType obj_type; QListWidgetItem *item=nullptr; bool checked; checked=(sender()==select_all_tb || value); for(int i=0; i < visibleobjects_lst->count(); i++) { item=visibleobjects_lst->item(i); obj_type=static_cast(item->data(Qt::UserRole).toInt()); visible_objs_map[obj_type]=checked; item->setCheckState((checked ? Qt::Checked : Qt::Unchecked)); } updateObjectsView(); } void ModelObjectsWidget::changeObjectsView(void) { if(sender()==tree_view_tb || sender()==list_view_tb) { visaoobjetos_stw->setCurrentIndex(sender()==tree_view_tb ? 0 : 1); tree_view_tb->setChecked(sender()==tree_view_tb); list_view_tb->setChecked(sender()==list_view_tb); by_id_chk->setEnabled(sender()==tree_view_tb); } else if(sender()==options_tb) { filter_wgt->setVisible(options_tb->isChecked()); visibleobjects_grp->setVisible(options_tb->isChecked()); splitter->handle(1)->setEnabled(options_tb->isChecked()); //Restore the splitter state if the options toolbutton is not toggled if(!options_tb->isChecked()) splitter->restoreState(widgets_conf.value(QString("splitterSize")).toByteArray()); } expand_all_tb->setEnabled(tree_view_tb->isChecked()); collapse_all_tb->setEnabled(tree_view_tb->isChecked()); } void ModelObjectsWidget::collapseAll(void) { QTreeWidgetItem *root=objectstree_tw->topLevelItem(0); objectstree_tw->collapseAll(); if(root) root->setExpanded(true); } void ModelObjectsWidget::filterObjects(void) { if(tree_view_tb->isChecked()) { DatabaseImportForm::filterObjects(objectstree_tw, filter_edt->text(), (by_id_chk->isChecked() ? 1 : 0), simplified_view); } else { QList items=objectslist_tbw->findItems(filter_edt->text(), Qt::MatchStartsWith | Qt::MatchRecursive); objectslist_tbw->blockSignals(true); for(int row=0; row < objectslist_tbw->rowCount(); row++) objectslist_tbw->setRowHidden(row, true); while(!items.isEmpty()) { objectslist_tbw->setRowHidden(items.front()->row(), false); items.pop_front(); } objectslist_tbw->blockSignals(false); } } void ModelObjectsWidget::updateObjectsView(void) { updateDatabaseTree(); updateObjectsList(); if(!filter_edt->text().isEmpty()) filterObjects(); } void ModelObjectsWidget::updateObjectsList(void) { vector objects; if(db_model) { vector visible_types; for(auto &tp : visible_objs_map) { if(tp.second) visible_types.push_back(tp.first); } objects=db_model->findObjects(QString(), visible_types, false, false, false); } ObjectFinderWidget::updateObjectTable(objectslist_tbw, objects); } void ModelObjectsWidget::updateSchemaTree(QTreeWidgetItem *root) { if(db_model && visible_objs_map[ObjectType::Schema]) { BaseObject *schema=nullptr; vector obj_list; QFont font; QTreeWidgetItem *item=nullptr, *item1=nullptr, *item2=nullptr, *item3=nullptr; vector types = BaseObject::getChildObjectTypes(ObjectType::Schema); int count = 0, count2 = 0, i = 0; QPixmap group_icon=QPixmap(PgModelerUiNs::getIconPath(QString(BaseObject::getSchemaName(ObjectType::Schema)) + QString("_grp"))); //Removing the ObjectType::Table and ObjectType::View types since they are handled separetedly types.erase(std::find(types.begin(), types.end(), ObjectType::Table)); types.erase(std::find(types.begin(), types.end(), ObjectType::ForeignTable)); types.erase(std::find(types.begin(), types.end(), ObjectType::View)); //Get the current schema count on database count=(db_model->getObjectCount(ObjectType::Schema)); item=new QTreeWidgetItem(root); item->setIcon(0,group_icon); item->setData(1, Qt::UserRole, QVariant(enum_cast(ObjectType::Schema))); //Create the schema group item item->setText(0, QString("%1 (%2)").arg(BaseObject::getTypeName(ObjectType::Schema)).arg(count)); font=item->font(0); font.setItalic(true); item->setFont(0, font); try { for(i=0; i < count; i++) { //The first item is the public schema if(i==-1) { //The new sub item to be configured will be the public schema item item2=item1; schema=nullptr; } else { schema=db_model->getObject(i, ObjectType::Schema); item2=createItemForObject(schema, item); } //Updates the table subtree for the current schema updateTableTree(item2, schema, ObjectType::Table); //Updates the foreign table subtree for the current schema updateTableTree(item2, schema, ObjectType::ForeignTable); //Updates the view subtree for the current schema updateViewTree(item2, schema); //Creates the object group at schema level (function, domain, sequences, etc) for(auto type : types) { if(visible_objs_map[type]) { item3=new QTreeWidgetItem(item2); item3->setIcon(0,QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(type) + QString("_grp")))); //Get the objects that belongs to the current schema obj_list=db_model->getObjects(type, schema); count2=obj_list.size(); item3->setText(0, QString("%1 (%2)").arg(BaseObject::getTypeName(type)).arg(count2)); item3->setData(1, Qt::UserRole, QVariant(enum_cast(type))); font=item3->font(0); font.setItalic(true); item3->setFont(0, font); for(auto obj : obj_list) createItemForObject(obj, item3); } } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void ModelObjectsWidget::updateTableTree(QTreeWidgetItem *root, BaseObject *schema, ObjectType table_type) { if(db_model && PhysicalTable::isPhysicalTable(table_type) && visible_objs_map[table_type]) { vector obj_list; PhysicalTable *table=nullptr; QTreeWidgetItem *item=nullptr, *item1=nullptr, *item2=nullptr; QFont font; vector types = BaseObject::getChildObjectTypes(table_type); QPixmap group_icon=QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(table_type) + QString("_grp"))); try { //Get all tables that belongs to the specified schema obj_list=db_model->getObjects(table_type, schema); //Create a table group item item=new QTreeWidgetItem(root); item->setIcon(0,group_icon); item->setText(0,BaseObject::getTypeName(table_type) + QString(" (%1)").arg(obj_list.size())); item->setData(1, Qt::UserRole, QVariant(enum_cast(table_type))); font=item->font(0); font.setItalic(true); item->setFont(0, font); for(auto obj : obj_list) { table=dynamic_cast(obj); item1=createItemForObject(table, item); //Creating the group for the child objects (column, rules, triggers, indexes and constraints) for(auto type : types) { if(visible_objs_map[type]) { item2=new QTreeWidgetItem(item1); item2->setIcon(0,QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(type) + QString("_grp")))); font=item2->font(0); font.setItalic(true); item2->setFont(0, font); item2->setText(0, QString("%1 (%2)").arg(BaseObject::getTypeName(type)).arg(table->getObjectCount(type))); for(auto tab_obj : *table->getObjectList(type)) createItemForObject(tab_obj, item2); } } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void ModelObjectsWidget::updateViewTree(QTreeWidgetItem *root, BaseObject *schema) { if(db_model && visible_objs_map[ObjectType::View]) { BaseObject *object=nullptr; vector obj_list; View *view=nullptr; QTreeWidgetItem *item=nullptr, *item1=nullptr, *item2=nullptr; QFont font; vector types = BaseObject::getChildObjectTypes(ObjectType::View); int count = 0, count1 = 0, i = 0, i2 = 0; QPixmap group_icon=QPixmap(PgModelerUiNs::getIconPath(QString(BaseObject::getSchemaName(ObjectType::View)) + QString("_grp"))); try { //Get all views that belongs to the specified schema obj_list=db_model->getObjects(ObjectType::View, schema); //Create a table group item item=new QTreeWidgetItem(root); item->setIcon(0,group_icon); item->setText(0,BaseObject::getTypeName(ObjectType::View) + QString(" (%1)").arg(obj_list.size())); item->setData(1, Qt::UserRole, QVariant(enum_cast(ObjectType::View))); font=item->font(0); font.setItalic(true); item->setFont(0, font); count=obj_list.size(); for(i=0; i < count; i++) { view=dynamic_cast(obj_list[i]); item1=createItemForObject(view, item); //Creating the group for the child objects (rules, triggers) for(auto &type : types) { if(visible_objs_map[type]) { item2=new QTreeWidgetItem(item1); item2->setIcon(0,QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(type) + QString("_grp")))); font=item2->font(0); font.setItalic(true); item2->setFont(0, font); count1 = view->getObjectCount(type); item2->setText(0,BaseObject::getTypeName(type) + QString(" (%1)").arg(count1)); for(i2=0; i2 < count1; i2++) { object=view->getObject(i2, type); createItemForObject(object, item2); } } } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void ModelObjectsWidget::updatePermissionTree(QTreeWidgetItem *root, BaseObject *object) { try { if(db_model && visible_objs_map[ObjectType::Permission] && Permission::acceptsPermission(object->getObjectType())) { vector perms; QTreeWidgetItem *item=new QTreeWidgetItem(root); QFont font=item->font(0); db_model->getPermissions(object, perms); item->setIcon(0,QPixmap(PgModelerUiNs::getIconPath("permission_grp"))); font.setItalic(true); item->setFont(0, font); item->setText(0, QString("%1 (%2)") .arg(BaseObject::getTypeName(ObjectType::Permission)) .arg(perms.size())); item->setData(0, Qt::UserRole, generateItemValue(object)); item->setData(1, Qt::UserRole, static_cast(ObjectType::Permission)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelObjectsWidget::updateDatabaseTree(void) { if(!db_model) objectstree_tw->clear(); else { QString str_aux; BaseObject *object=nullptr; QTreeWidgetItem *root=nullptr,*item1=nullptr, *item2=nullptr; QFont font; vector ref_list, tree_state, obj_list; vector types = BaseObject::getChildObjectTypes(ObjectType::Database); unsigned count = 0, i = 0, i1 = 0; types.push_back(ObjectType::Tag); types.push_back(ObjectType::GenericSql); types.push_back(ObjectType::Textbox); types.push_back(ObjectType::Relationship); types.erase(std::find(types.begin(), types.end(), ObjectType::Schema)); try { if(save_tree_state) saveTreeState(tree_state); objectstree_tw->setUpdatesEnabled(false); objectstree_tw->clear(); if(visible_objs_map[ObjectType::Database]) { root=createItemForObject(db_model); objectstree_tw->insertTopLevelItem(0,root); updateSchemaTree(root); for(auto &type : types) { if(visible_objs_map[type]) { item1=new QTreeWidgetItem(root); str_aux=QString(BaseObject::getSchemaName(type)); item1->setIcon(0,QPixmap(PgModelerUiNs::getIconPath(str_aux + QString("_grp")))); item1->setData(1, Qt::UserRole, QVariant(enum_cast(type))); obj_list=(*db_model->getObjectList(type)); //Special case for relationship, merging the base relationship list to the relationship list if(type==ObjectType::Relationship) { vector obj_list_aux; obj_list_aux=(*db_model->getObjectList(ObjectType::BaseRelationship)); obj_list.insert(obj_list.end(), obj_list_aux.begin(), obj_list_aux.end()); } count=obj_list.size(); item1->setText(0,BaseObject::getTypeName(type) + QString(" (%1)").arg(count)); font=item1->font(0); font.setItalic(true); item1->setFont(0, font); for(i1=0; i1 < count; i1++) { object=obj_list.at(i1); item2=createItemForObject(object, item1); if(types[i]==ObjectType::Tag) { db_model->getObjectReferences(object, ref_list); for(auto &ref : ref_list) createItemForObject(ref, item2, false); } } } } objectstree_tw->setUpdatesEnabled(true); objectstree_tw->expandItem(root); if(save_tree_state) restoreTreeState(tree_state); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } objectstree_tw->sortByColumn(0, Qt::AscendingOrder); } } BaseObject *ModelObjectsWidget::getSelectedObject(void) { return(selected_object); } void ModelObjectsWidget::enableObjectCreation(bool value) { enable_obj_creation=value; } void ModelObjectsWidget::close(void) { QObject *obj_sender=sender(); if(obj_sender==cancel_tb) selected_object=nullptr; else { QVariant data; if(tree_view_tb->isChecked() && objectstree_tw->currentItem()) data=objectstree_tw->currentItem()->data(0,Qt::UserRole); else if(objectslist_tbw->currentItem()) data=objectslist_tbw->currentItem()->data(Qt::UserRole); selected_object=reinterpret_cast(data.value()); } QWidget::close(); } void ModelObjectsWidget::setModel(ModelWidget *model_wgt) { this->model_wgt=model_wgt; if(model_wgt) setModel(model_wgt->db_model); else setModel(static_cast(nullptr)); } void ModelObjectsWidget::setModel(DatabaseModel *db_model) { bool enable = (db_model!=nullptr); this->db_model=db_model; content_wgt->setEnabled(enable); updateObjectsView(); visaoobjetos_stw->setEnabled(true); expand_all_tb->setEnabled(enable && tree_view_tb->isChecked()); collapse_all_tb->setEnabled(enable && tree_view_tb->isChecked()); tree_view_tb->setEnabled(enable); list_view_tb->setEnabled(enable); options_tb->setEnabled(enable); filter_lbl->setEnabled(enable); filter_edt->setEnabled(enable); by_id_chk->setEnabled(enable); } void ModelObjectsWidget::showEvent(QShowEvent *) { if(simplified_view) { QWidget *wgt=QApplication::activeWindow(); filter_edt->setFocus(); filter_edt->blockSignals(true); by_id_chk->blockSignals(true); filter_edt->clear(); by_id_chk->setChecked(false); filter_edt->blockSignals(false); by_id_chk->blockSignals(false); if(wgt) { int x, y; x = wgt->pos().x() + abs((wgt->width() - this->width()) / 2); y = wgt->pos().y() + abs((wgt->height() - this->height()) / 2); this->setGeometry(QRect(QPoint(x,y), this->minimumSize())); } } } void ModelObjectsWidget::closeEvent(QCloseEvent *) { if(simplified_view) { map::iterator itr, itr_end; itr=visible_objs_map.begin(); itr_end=visible_objs_map.end(); while(itr!=itr_end) { itr->second=false; itr++; } this->resize(this->minimumSize()); } emit s_visibilityChanged(selected_object, !this->isVisible()); } void ModelObjectsWidget::mouseMoveEvent(QMouseEvent *) { static QPoint pos=QCursor::pos(), pos1=QCursor::pos(); pos=pos1; pos1=QCursor::pos(); if(simplified_view && QApplication::mouseButtons()==Qt::LeftButton) { QPoint pos_dif; QDesktopWidget desktop; QRect ret=desktop.screenGeometry(); int px, py; pos_dif=pos1-pos; px=this->pos().x() + pos_dif.x(); py=this->pos().y() + pos_dif.y(); if(px<0) px=0; else if((px + this->width()) > ret.right()) px=ret.right() - this->width(); if(py<0) py=0; else if((py + this->height()) > ret.bottom()) py=ret.bottom() - this->height(); this->move(px,py); } } void ModelObjectsWidget::resizeEvent(QResizeEvent *) { objectstree_tw->header()->setMinimumSectionSize(objectstree_tw->width()); objectstree_tw->header()->setDefaultSectionSize(objectstree_tw->width()); } void ModelObjectsWidget::saveTreeState(bool value) { save_tree_state=(!simplified_view && value); } void ModelObjectsWidget::saveTreeState(vector &tree_items) { QTreeWidgetItemIterator itr(objectstree_tw); BaseObject *obj=nullptr; QTreeWidgetItem *item=nullptr; while(*itr) { item=*itr; obj=reinterpret_cast(item->data(0,Qt::UserRole).value()); if(obj && item->parent() && item->parent()->isExpanded()) tree_items.push_back(obj); ++itr; } } void ModelObjectsWidget::restoreTreeState(vector &tree_items) { QTreeWidgetItem *item=nullptr, *parent_item=nullptr; objectslist_tbw->setUpdatesEnabled(false); while(!tree_items.empty()) { item=getTreeItem(tree_items.back()); if(item) { parent_item=item->parent(); if(parent_item) objectstree_tw->expandItem(parent_item); if(parent_item && parent_item->parent()) objectstree_tw->expandItem(parent_item->parent()); } tree_items.pop_back(); } objectslist_tbw->setUpdatesEnabled(true); } QTreeWidgetItem *ModelObjectsWidget::getTreeItem(BaseObject *object) { if(object) { QTreeWidgetItemIterator itr(objectstree_tw); BaseObject *aux_obj=nullptr; QTreeWidgetItem *item=nullptr; while(*itr) { aux_obj=reinterpret_cast((*itr)->data(0,Qt::UserRole).value()); if(aux_obj==object) { item=*itr; break; } ++itr; } return(item); } else return(nullptr); } void ModelObjectsWidget::selectCreatedObject(BaseObject *obj) { updateObjectsView(); QTreeWidgetItem *item=getTreeItem(obj); if(item) { objectstree_tw->blockSignals(true); objectstree_tw->setItemSelected(item, true); objectstree_tw->setCurrentItem(item); objectstree_tw->scrollToItem(item); selected_object=obj; select_tb->setFocus(); objectstree_tw->blockSignals(false); } } pgmodeler-0.9.2/libpgmodeler_ui/src/modelobjectswidget.h000066400000000000000000000122751360462764600235050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelObjectsWidget \brief Implements a widget that permits an tree and list view of all model objects. */ #ifndef MODEL_OBJECTS_WIDGET_H #define MODEL_OBJECTS_WIDGET_H #include #include "ui_modelobjectswidget.h" #include "modelwidget.h" #include "messagebox.h" #include "objectfinderwidget.h" class ModelObjectsWidget: public QWidget, public Ui::ModelObjectsWidget { private: Q_OBJECT /*! \brief Indicates if the widget must be used as a simplified view (without the most interactions). The purpose to use it as simplified view is to be serve as a object pick commonly used on the object selectors. See ObjectSelectorWidget for details. */ bool simplified_view, /*! \brief Indicates if the object tree state must be saved, this means, that the current item expansion is memorized and can be restored at any moment via restoreTreeState() method */ save_tree_state, /*! \brief Allow the object creation in simplified mode by using the "New [object type]" popup menu. This flag is ignored if the model object widget is used in the complete mode since the main purpose of the widget is to allow the object management */ enable_obj_creation; //! \brief Stores the reference to the object currently selected on the tree/list BaseObject *selected_object; /*! \brief Stores the initial splitter size to be used in conjunction with the object type visualization buttons */ QSettings widgets_conf; //! \brief Reference model widget. This is the object used to populate the tree and list ModelWidget *model_wgt; //! \brief Reference database model. This is the object used to populate the tree and list DatabaseModel *db_model; //! \brief Stores which object types are visible on the view map visible_objs_map; //! \brief Updates only a schema tree starting from the 'root' item void updateSchemaTree(QTreeWidgetItem *root); /*! \brief Updates only a table / foreign table tree starting from the 'root' item. * table_type must be ObjectType::Table or ObjectType::ForeignTable */ void updateTableTree(QTreeWidgetItem *root, BaseObject *schema, ObjectType table_type); //! \brief Updates only a view tree starting from the 'root' item void updateViewTree(QTreeWidgetItem *root, BaseObject *schema); //! \brief Updates only the permission tree related to the specified object void updatePermissionTree(QTreeWidgetItem *root, BaseObject *object); //! \brief Updates the whole database object tree void updateDatabaseTree(void); //! \brief Updates the whole object list void updateObjectsList(void); //! \brief Returns an item from the tree related to the specified object reference QTreeWidgetItem *getTreeItem(BaseObject *object); //! \brief Generates a QVariant containing the passed object reference as data QVariant generateItemValue(BaseObject *object); QTreeWidgetItem *createItemForObject(BaseObject *object, QTreeWidgetItem *root=nullptr, bool update_perms=true); void mouseMoveEvent(QMouseEvent *); void resizeEvent(QResizeEvent *); void closeEvent(QCloseEvent *); void showEvent(QShowEvent *); bool eventFilter(QObject *object, QEvent *event); public: ModelObjectsWidget(bool simplified_view=false, QWidget * parent = nullptr); BaseObject *getSelectedObject(void); //! \brief Enables the object creation in simplified view by exposing the popup menu "New [object]" void enableObjectCreation(bool value); protected: //! \brief Saves the currently expanded items on the specified vector void saveTreeState(vector &tree_items); //! \brief Restores the tree at a previous state when the specified items were expanded void restoreTreeState(vector &tree_items); //! \brief Defines if the widget must save/restore the tree state automaticaly void saveTreeState(bool value); public slots: void setModel(ModelWidget *model_wgt); void setModel(DatabaseModel *db_model); void changeObjectsView(void); void updateObjectsView(void); void setObjectVisible(ObjectType obj_type, bool visible); void close(void); void hide(void); private slots: void setObjectVisible(QListWidgetItem *item); void setAllObjectsVisible(bool value); void selectObject(void); void showObjectMenu(void); void editObject(void); void collapseAll(void); void filterObjects(void); void selectCreatedObject(BaseObject *obj); signals: void s_visibilityChanged(BaseObject *,bool); void s_visibilityChanged(bool); friend class MainWindow; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modeloverviewwidget.cpp000066400000000000000000000247661360462764600242650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modeloverviewwidget.h" #include "modelwidget.h" ModelOverviewWidget::ModelOverviewWidget(QWidget *parent) : QWidget(parent, Qt::WindowCloseButtonHint | Qt::Tool) { setupUi(this); scrollarea = nullptr; this->model=nullptr; zoom_factor=1; curr_resize_factor=ResizeFactor; this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QVBoxLayout *vbox = new QVBoxLayout; scrollarea=new QScrollArea(frame); scrollarea->setWidgetResizable(true); scrollarea->setFrameStyle(QFrame::Box); scrollarea->setFrameShadow(QFrame::Plain); scrollarea->setVisible(false); vbox->addWidget(scrollarea); vbox->setContentsMargins(0,0,0,0); frame->setLayout(vbox); label->setStyleSheet("QLabel#label{ border: 0px; }"); } void ModelOverviewWidget::show(ModelWidget *model) { if(this->model) { disconnect(this->model, nullptr, this, nullptr); disconnect(this->model->viewport, nullptr, this, nullptr); disconnect(this->model->scene, nullptr, this, nullptr); } this->model=model; if(this->model) { connect(this->model, SIGNAL(s_objectCreated(void)), this, SLOT(updateOverview(void))); connect(this->model, SIGNAL(s_objectRemoved(void)), this, SLOT(updateOverview(void))); connect(this->model, SIGNAL(s_objectsMoved(void)), this, SLOT(updateOverview(void))); connect(this->model, SIGNAL(s_objectModified(void)), this, SLOT(updateOverview(void))); connect(this->model, SIGNAL(s_zoomModified(double)), this, SLOT(updateZoomFactor(double))); connect(this->model, SIGNAL(s_modelResized(void)), this, SLOT(resizeOverview(void))); connect(this->model, SIGNAL(s_modelResized(void)), this, SLOT(resizeWindowFrame(void))); connect(this->model, SIGNAL(s_modelResized(void)), this, SLOT(updateOverview(void))); connect(this->model->viewport->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(resizeWindowFrame(void))); connect(this->model->viewport->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(resizeWindowFrame(void))); connect(this->model->scene, SIGNAL(selectionChanged(void)), this, SLOT(updateOverview(void))); connect(this->model->scene, SIGNAL(sceneRectChanged(QRectF)),this, SLOT(resizeOverview(void))); connect(this->model->scene, SIGNAL(sceneRectChanged(QRectF)),this, SLOT(updateOverview(void))); this->resizeOverview(); this->updateZoomFactor(this->model->getCurrentZoom()); this->updateOverview(true); this->move(this->model->geometry().right() - this->width(), this->model->geometry().bottom() - this->height()); frame->installEventFilter(this); } this->raise(); QWidget::show(); } void ModelOverviewWidget::closeEvent(QCloseEvent *event) { model=nullptr; emit s_overviewVisible(false); QWidget::closeEvent(event); } void ModelOverviewWidget::showEvent(QShowEvent *event) { emit s_overviewVisible(true); QWidget::showEvent(event); } bool ModelOverviewWidget::eventFilter(QObject *object, QEvent *event) { if(object == frame && event->type()==QEvent::Wheel) { QWheelEvent *w_event = static_cast(event); QPoint dt_angle = w_event->angleDelta(); if(dt_angle.y() < 0) model->applyZoom(model->getCurrentZoom() - ModelWidget::ZoomIncrement); else model->applyZoom(model->getCurrentZoom() + ModelWidget::ZoomIncrement); return(false); } return(QWidget::eventFilter(object, event)); } void ModelOverviewWidget::updateOverview(void) { this->updateOverview(false); } void ModelOverviewWidget::updateOverview(bool force_update) { if(this->model && (this->isVisible() || force_update)) { QPixmap pix; QApplication::setOverrideCursor(Qt::WaitCursor); //Creates a pixmap with the size of the scene pix=QPixmap(pixmap_size); //Draw the scene onto the pixmap QPainter p(&pix); if(!p.isActive()) { label->setPixmap(QPixmap()); label->setText(trUtf8("Failed to generate the overview image.\nThe requested size %1 x %2 was too big and there was not enough memory to allocate!") .arg(pixmap_size.width()).arg(pixmap_size.height())); frame->setEnabled(false); } else { frame->setEnabled(true); p.setRenderHints(QPainter::Antialiasing, false); p.setRenderHints(QPainter::TextAntialiasing, false); this->model->scene->render(&p, pix.rect(), scene_rect.toRect()); //Resizes the pixmap to the previous configured QSize label->setPixmap(pix.scaled(curr_size.toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); } label->resize(curr_size.toSize()); QApplication::restoreOverrideCursor(); } } void ModelOverviewWidget::resizeWindowFrame(void) { if(this->model) { QSizeF size; double factor=curr_resize_factor/zoom_factor; QScrollBar *h_scroll=this->model->viewport->horizontalScrollBar(), *v_scroll=this->model->viewport->verticalScrollBar(); //Resizes the window frame based upon the model's viewport dimensions size=this->model->viewport->geometry().size(); size.setWidth(size.width() * factor); size.setHeight(size.height() * factor); window_frm->resize(size.toSize()); //Set the frame position based upon the viewport scroll bar values window_frm->move(QPoint(h_scroll->value() * factor - (scrollarea->isVisible() ? scrollarea->horizontalScrollBar()->value() : 0), v_scroll->value() * factor - (scrollarea->isVisible() ? scrollarea->verticalScrollBar()->value() : 0))); if(scrollarea->isVisible()) { if(window_frm->geometry().bottom() > frame->geometry().bottom()) scrollarea->verticalScrollBar()->setValue(scrollarea->verticalScrollBar()->value() + (scrollarea->verticalScrollBar()->maximum() * 0.30)); else if(window_frm->geometry().top() < 0) scrollarea->verticalScrollBar()->setValue(scrollarea->verticalScrollBar()->value() - (scrollarea->verticalScrollBar()->maximum() * 0.30)); if(window_frm->geometry().right() > frame->geometry().right()) scrollarea->horizontalScrollBar()->setValue(scrollarea->horizontalScrollBar()->value() + (scrollarea->horizontalScrollBar()->maximum() * 0.30)); else if(window_frm->geometry().left() < 0) scrollarea->horizontalScrollBar()->setValue(scrollarea->horizontalScrollBar()->value() - (scrollarea->horizontalScrollBar()->maximum() * 0.30)); } } } void ModelOverviewWidget::resizeOverview(void) { if(this->model) { QDesktopWidget desktop; QRect screen_rect=desktop.screenGeometry(desktop.primaryScreen()); //Make an initial calculation of the overview window size scene_rect=this->model->scene->sceneRect(); curr_size=scene_rect.size(); curr_size.setWidth(curr_size.width() * ResizeFactor); curr_size.setHeight(curr_size.height() * ResizeFactor); //If the size exceeds the screen's width or height in 90% if(curr_size.width() > screen_rect.width() * 0.90 || curr_size.height() > screen_rect.height() * 0.90) { int max_val = std::max(scene_rect.width(), scene_rect.height()); //Reduce the resize factor and recalculates the new size if(max_val >= 16384) { curr_resize_factor=screen_rect.width()/static_cast(max_val); pixmap_size.setWidth(scene_rect.size().width() * (curr_resize_factor * 10)); pixmap_size.setHeight(scene_rect.size().height() * (curr_resize_factor * 10)); } else { curr_resize_factor=ResizeFactor/2; pixmap_size=scene_rect.size().toSize(); } curr_size=scene_rect.size(); curr_size.setWidth(curr_size.width() * curr_resize_factor); curr_size.setHeight(curr_size.height() * curr_resize_factor); } else { curr_resize_factor=ResizeFactor; pixmap_size=scene_rect.size().toSize(); } QSize size = curr_size.toSize(); bool show_scrollarea = false; if(curr_size.width() > screen_rect.width() * 0.90 ) { size.setWidth(screen_rect.width() * 0.90); show_scrollarea = true; } if(curr_size.height() > screen_rect.height() * 0.90) { size.setHeight(screen_rect.height() * 0.90); show_scrollarea = true; } if(show_scrollarea && !scrollarea->isVisible()) { frame->setStyleSheet("QFrame#frame{ border: 0px; }"); frame->layout()->removeWidget(label); frame->layout()->addWidget(scrollarea); scrollarea->setVisible(true); scrollarea->setWidget(label); window_frm->setParent(scrollarea); } else if(!show_scrollarea) { frame->setStyleSheet(""); scrollarea->setVisible(false); scrollarea->takeWidget(); frame->layout()->removeWidget(scrollarea); frame->layout()->addWidget(label); window_frm->setParent(frame); } window_frm->setVisible(true); this->resize(size); this->setMaximumSize(size); this->setMinimumSize(size); } } void ModelOverviewWidget::updateZoomFactor(double zoom) { this->zoom_factor=zoom; this->resizeWindowFrame(); } void ModelOverviewWidget::mouseDoubleClickEvent(QMouseEvent *) { this->close(); } void ModelOverviewWidget::mouseMoveEvent(QMouseEvent *event) { if(!frame->isEnabled()) return; if(event->buttons()==Qt::LeftButton) { QRect rect=window_frm->geometry(), rect1; int width = 0, height = 0, x=event->x(), y=event->y() + scrollarea->verticalScrollBar()->value(); width=rect.width()/2; height=rect.height()/2; //Configures a rectangle having as central point the event position rect.setLeft(x - width); rect.setTop(y - height); rect.setRight(x + width); rect.setBottom(y + height); rect1=label->geometry(); this->model->viewport->horizontalScrollBar()->setValue(ceil(zoom_factor * scene_rect.width() * (rect.x()/static_cast(rect1.width())))); this->model->viewport->verticalScrollBar()->setValue(ceil(zoom_factor * scene_rect.height() * (rect.y()/static_cast(rect1.height())))); } } void ModelOverviewWidget::mousePressEvent(QMouseEvent *event) { if(event->button()==Qt::LeftButton) { window_frm->setCursor(QCursor(Qt::OpenHandCursor)); this->setCursor(QCursor(Qt::OpenHandCursor)); } } void ModelOverviewWidget::mouseReleaseEvent(QMouseEvent *event) { if(event->button()==Qt::LeftButton) { window_frm->setCursor(QCursor(Qt::ArrowCursor)); this->setCursor(QCursor(Qt::ArrowCursor)); } } pgmodeler-0.9.2/libpgmodeler_ui/src/modeloverviewwidget.h000066400000000000000000000054551360462764600237240ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelOverviewWidget \brief Implements the model overview widget operations. */ #ifndef MODEL_OVERVIEW_WIDGET_H #define MODEL_OVERVIEW_WIDGET_H #include #include "exception.h" #include "ui_modeloverviewwidget.h" #include "modelwidget.h" class ModelOverviewWidget: public QWidget, public Ui::ModelOverviewWidget { private: Q_OBJECT QScrollArea *scrollarea; //! \brief Model which object are drawn on the overview widget ModelWidget *model; //! \brief Zoom factor applied to the visualization double zoom_factor, //! \brief Store the current calculated resize factor curr_resize_factor; //! \brief Current overview window size QSizeF curr_size; //! \brief Current scene rectangle QRectF scene_rect; QSize pixmap_size; //! \brief Resize factor applied to overview widgets (default: 20% of the scene original size) static constexpr double ResizeFactor=0.20; void mouseDoubleClickEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); bool eventFilter(QObject *object, QEvent *event); /*! \brief Updates the overview with the last modifications on the scene. The bool parameter is used to force the update even if the overview widget is not visible */ void updateOverview(bool force_update); public: ModelOverviewWidget(QWidget *parent = nullptr); public slots: //! \brief Updates the overview (only if the widget is visible) void updateOverview(void); //! \brief Resizes the frame that represents the visualization window void resizeWindowFrame(void); //! \brief Resizes the whole overview widget void resizeOverview(void); //! \brief Updates the overview zoom factor void updateZoomFactor(double zoom); //! \brief Shows the overview specifying the model to be drawn void show(ModelWidget *model); signals: //! \brief Signal emitted whenever the overview window change the visibility void s_overviewVisible(bool); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelrestorationform.cpp000066400000000000000000000106071360462764600244350ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelrestorationform.h" #include "pgmodeleruins.h" ModelRestorationForm::ModelRestorationForm(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { setupUi(this); PgModelerUiNs::configureWidgetFont(message_lbl, PgModelerUiNs::MediumFontFactor); keep_models_ht=new HintTextWidget(keep_models_hint, this); keep_models_ht->setText(keep_models_chk->statusTip()); connect(restore_btn, SIGNAL(clicked(void)), this, SLOT(accept(void))); connect(cancel_btn, SIGNAL(clicked(void)), this, SLOT(reject(void))); connect(tmp_files_tbw, SIGNAL(itemSelectionChanged()), this, SLOT(enableRestoration(void))); } QStringList ModelRestorationForm::getTemporaryModels(void) { //Returns if there is some .dbm file on the tmp dir return(QDir(GlobalAttributes::TemporaryDir, QString("*.dbm"), QDir::Name, QDir::Files | QDir::NoDotAndDotDot).entryList()); } int ModelRestorationForm::exec(void) { QStringList file_list=this->getTemporaryModels(), tmp_info; QFileInfo info; QTableWidgetItem *item=nullptr; QFile input; QString buffer, filename; QRegExp regexp=QRegExp("(\\insertRow(tmp_files_tbw->rowCount()); for(col=0; col < tmp_info.size(); col++) { item=new QTableWidgetItem; item->setText(tmp_info.at(col)); item->setData(Qt::UserRole, filename); item->setSelected(true); tmp_files_tbw->setItem(tmp_files_tbw->rowCount()-1, col, item); } file_list.pop_front(); buffer.clear(); tmp_info.clear(); } tmp_files_tbw->resizeColumnsToContents(); tmp_files_tbw->resizeRowsToContents(); return(QDialog::exec()); } bool ModelRestorationForm::hasTemporaryModels(void) { return(!this->getTemporaryModels().isEmpty()); } void ModelRestorationForm::removeTemporaryFiles(void) { QDir tmp_file; QStringList tmp_files = QDir(GlobalAttributes::TemporaryDir, QString("*.dbm;*.dbk;*.omf;*.sql;*.log"), QDir::Name, QDir::Files | QDir::NoDotAndDotDot).entryList(); for(auto &file : tmp_files) tmp_file.remove(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + file); } void ModelRestorationForm::removeTemporaryModels(void) { QStringList file_list=this->getTemporaryModels(); QDir tmp_file; for(auto &file : file_list) tmp_file.remove(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + file); } void ModelRestorationForm::removeTemporaryModel(const QString &tmp_model) { QDir tmp_file; QString file=QFileInfo(tmp_model).fileName(); tmp_file.remove(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + file); } void ModelRestorationForm::enableRestoration(void) { restore_btn->setEnabled(!tmp_files_tbw->selectedItems().isEmpty()); } QStringList ModelRestorationForm::getSelectedModels(void) { QStringList list; QList items; items=tmp_files_tbw->selectedItems(); while(!items.isEmpty()) { list.push_back(items.front()->data(Qt::UserRole).toString()); items.pop_front(); } list.removeDuplicates(); return(list); } pgmodeler-0.9.2/libpgmodeler_ui/src/modelrestorationform.h000066400000000000000000000040041360462764600240740ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelRestorationForm \brief Implements the operation to retore models before a unexpected crash. */ #ifndef MODEL_RESTORATION_FORM_H #define MODEL_RESTORATION_FORM_H #include #include "hinttextwidget.h" #include "globalattributes.h" #include "ui_modelrestorationform.h" class ModelRestorationForm: public QDialog, public Ui::ModelRestorationForm { private: Q_OBJECT HintTextWidget * keep_models_ht; public: ModelRestorationForm(QWidget * parent = nullptr, Qt::WindowFlags f = Qt::Widget); //! \brief Returns the list of temporary files existant on tmp/ dir QStringList getTemporaryModels(void); //! \brief Returns the list of temporary files selected to be restored QStringList getSelectedModels(void); public slots: int exec(void); //! \brief Clears the tmp/ dir by removing all temporary files (*.dbm, *.dbk, *.omf, *.sql. *.log) void removeTemporaryFiles(void); //! \brief Clears the tmp/ dir removing all temporary models (*.dbm) void removeTemporaryModels(void); //! \brief Remove only the specified temp model void removeTemporaryModel(const QString &tmp_model); //! \brief Checks if there is at least one temporary file on tmp/ dir bool hasTemporaryModels(void); private slots: void enableRestoration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelsdiffhelper.cpp000066400000000000000000001153651360462764600235020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelsdiffhelper.h" #include #include "pgmodelerns.h" const vector ModelsDiffHelper::TableObjsIgnoredAttribs = { Attributes::Alias }; const vector ModelsDiffHelper::ObjectsIgnoredAttribs = { Attributes::MaxObjCount, Attributes::Protected, Attributes::SqlDisabled, Attributes::RectVisible, Attributes::FillColor, Attributes::FadedOut, Attributes::CollapseMode, Attributes::AttribsPage, Attributes::ExtAttribsPage, Attributes::Pagination, Attributes::Alias }; const vector ModelsDiffHelper::ObjectsIgnoredTags = { Attributes::Role, Attributes::Tablespace, Attributes::Collation, Attributes::Position, Attributes::AppendedSql, Attributes::PrependedSql }; ModelsDiffHelper::ModelsDiffHelper(void) { diff_canceled=false; pgsql_version=PgSqlVersions::DefaulVersion; source_model=imported_model=nullptr; resetDiffCounter(); diff_opts[OptKeepClusterObjs]=true; diff_opts[OptCascadeMode]=true; diff_opts[OptTruncateTables]=false; diff_opts[OptForceRecreation]=true; diff_opts[OptRecreateUnchangeble]=true; diff_opts[OptKeepObjectPerms]=true; diff_opts[OptReuseSequences]=true; diff_opts[OptPreserveDbName]=true; diff_opts[OptDontDropMissingObjs]=false; diff_opts[OptDropMissingColsConstr]=false; } ModelsDiffHelper::~ModelsDiffHelper(void) { destroyTempObjects(); } void ModelsDiffHelper::setDiffOption(unsigned opt_id, bool value) { if(opt_id > OptDropMissingColsConstr) throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(opt_id == OptDropMissingColsConstr) diff_opts[opt_id]=value & !diff_opts[OptDropMissingColsConstr]; else diff_opts[opt_id]=value; } void ModelsDiffHelper::setPgSQLVersion(const QString pgsql_ver) { this->pgsql_version=pgsql_ver; } void ModelsDiffHelper::resetDiffCounter(void) { diffs_counter[ObjectsDiffInfo::AlterObject]=0; diffs_counter[ObjectsDiffInfo::DropObject]=0; diffs_counter[ObjectsDiffInfo::CreateObject]=0; diffs_counter[ObjectsDiffInfo::IgnoreObject]=0; } QString ModelsDiffHelper::getDiffDefinition(void) { return(diff_def); } void ModelsDiffHelper::setModels(DatabaseModel *src_model, DatabaseModel *imp_model) { source_model=src_model; imported_model=imp_model; } unsigned ModelsDiffHelper::getDiffTypeCount(unsigned diff_type) { if(diff_type >= ObjectsDiffInfo::NoDifference) throw Exception(ErrorCode::RefElementInvalidIndex ,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(diffs_counter[diff_type]); } void ModelsDiffHelper::diffModels(void) { try { if(!source_model || !imported_model) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); //First, we need to detect the objects to be dropped diffModels(ObjectsDiffInfo::DropObject); //Second, we will check the objects to be created or modified diffModels(ObjectsDiffInfo::CreateObject); if(diff_canceled) emit s_diffCanceled(); else { processDiffInfos(); emit s_diffFinished(); } } catch(Exception &e) { emit s_diffAborted(Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo())); } destroyTempObjects(); resetDiffCounter(); } void ModelsDiffHelper::cancelDiff(void) { diff_canceled=true; } void ModelsDiffHelper::diffTables(PhysicalTable *src_table, PhysicalTable *imp_table, unsigned diff_type) { ObjectType types[2]={ ObjectType::Column, ObjectType::Constraint }; vector *tab_objs=nullptr; Constraint *constr=nullptr; PhysicalTable *ref_tab=nullptr, *comp_tab=nullptr; BaseObject *aux_obj=nullptr; if(diff_type==ObjectsDiffInfo::DropObject) { /* In case of DROP, the reference table is the one from the database and the compared table is the one from model */ ref_tab=imp_table; comp_tab=src_table; } else if(diff_type==ObjectsDiffInfo::CreateObject || diff_type==ObjectsDiffInfo::AlterObject) { ref_tab=src_table; comp_tab=imp_table; } for(unsigned i=0; i < 2 && !diff_canceled; i++) { tab_objs=ref_tab->getObjectList(types[i]); for(auto &tab_obj : *tab_objs) { //Get the object from the compared table aux_obj=comp_tab->getObject(tab_obj->getName(), tab_obj->getObjectType()); constr=dynamic_cast(tab_obj); //Ignoring object with sql disabled or check constraints added by generalizations if(tab_obj->isSQLDisabled() || (constr && constr->isAddedByGeneralization() && constr->getConstraintType()==ConstraintType::Check)) { generateDiffInfo(ObjectsDiffInfo::IgnoreObject, tab_obj); } else { /* If the current info is ALTER or CREATE, only objects created by generalization or columns created by common relationships will be considered on the comparison. Also, foreign keys are discarded here, since they will be compared on the main comparison at diffModels() */ if(aux_obj && diff_type!=ObjectsDiffInfo::DropObject && ((tab_obj->isAddedByGeneralization() || !tab_obj->isAddedByLinking() || (aux_obj->getObjectType()==ObjectType::Column && tab_obj->isAddedByLinking())) || (constr && constr->getConstraintType()!=ConstraintType::ForeignKey))) { //If there are some differences on the XML code of the objects if(tab_obj->isCodeDiffersFrom(aux_obj, TableObjsIgnoredAttribs)) generateDiffInfo(ObjectsDiffInfo::AlterObject, tab_obj, aux_obj); } /* If the object does not exists it will generate a drop info and the original one (tab_obj) was not included by generalization or partitioning (to avoid drop inherited/copied columns) */ else if(!aux_obj && !tab_obj->isAddedByGeneralization() && !tab_obj->isAddedByCopy()) { if(diff_type!=ObjectsDiffInfo::DropObject || (diff_type==ObjectsDiffInfo::DropObject && !diff_opts[OptDontDropMissingObjs]) || (diff_type==ObjectsDiffInfo::DropObject && diff_opts[OptDropMissingColsConstr])) generateDiffInfo(diff_type, tab_obj); else generateDiffInfo(ObjectsDiffInfo::IgnoreObject, tab_obj); } } if(diff_canceled) break; } } } void ModelsDiffHelper::diffModels(unsigned diff_type) { if(diff_canceled) return; try { map obj_order; BaseObject *object=nullptr, *aux_object=nullptr; ObjectType obj_type; QString obj_name; unsigned idx=0, factor=0, prog=0; DatabaseModel *aux_model=nullptr; bool objs_differs=false, xml_differs=false; if(diff_type==ObjectsDiffInfo::DropObject) { /* For DROP detection, we must gather the objects from the database in order to check if they exists on the model. The object drop order here is the inverse of the creation order on the database */ obj_order=imported_model->getCreationOrder(SchemaParser::SqlDefinition, true); aux_model=source_model; factor=25; } else if(diff_type==ObjectsDiffInfo::CreateObject || diff_type==ObjectsDiffInfo::AlterObject) { /* For creation or modification of objects the order followed is the same as the creation order on the source model */ obj_order=source_model->getCreationOrder(SchemaParser::SqlDefinition, true, true); aux_model=imported_model; factor=50; prog=50; } for(auto &obj_itr : obj_order) { object=obj_itr.second; obj_type=object->getObjectType(); idx++; /* If this checking the following objects are discarded: 1) ObjectType::ObjBaseRelationship objects 2) Objects which SQL code is disabled or system objects 3) Cluster objects such as roles and tablespaces (when the operatoin is DROP and keep_cluster_objs is true) */ if(obj_type!=ObjectType::BaseRelationship && !object->isSystemObject() && !object->isSQLDisabled() && ((diff_type==ObjectsDiffInfo::DropObject && (!diff_opts[OptKeepClusterObjs] || (diff_opts[OptKeepClusterObjs] && obj_type!=ObjectType::Role && obj_type!=ObjectType::Tablespace))) || (diff_type!=ObjectsDiffInfo::DropObject))) { emit s_progressUpdated(prog + ((idx/static_cast(obj_order.size())) * factor), trUtf8("Processing object `%1' (%2)...").arg(object->getSignature()).arg(object->getTypeName()), object->getObjectType()); //Processing objects that are not database, table child object (they are processed further) if(obj_type!=ObjectType::Database && !TableObject::isTableObject(obj_type)) { /* Processing permissions. If the operation is DROP and keep_obj_perms is true the * the permission is ignored */ if(obj_type==ObjectType::Permission && ((diff_type==ObjectsDiffInfo::DropObject && !diff_opts[OptKeepObjectPerms]) || (diff_type==ObjectsDiffInfo::CreateObject && (aux_model->getPermissionIndex(dynamic_cast(object), true) < 0 || !diff_opts[OptKeepObjectPerms])))) generateDiffInfo(diff_type, object); //Processing relationship (in this case only generalization and patitioning ones are considered) else if(obj_type==ObjectType::Relationship) { PhysicalTable *ref_tab=nullptr, *rec_tab=nullptr; Relationship *rel=dynamic_cast(object); rec_tab=dynamic_cast(aux_model->getObject(rel->getReceiverTable()->getName(true), {ObjectType::Table, ObjectType::ForeignTable})); if(rel->getRelationshipType()==BaseRelationship::RelationshipGen || rel->getRelationshipType()==BaseRelationship::RelationshipPart) { Relationship *aux_rel = nullptr; ref_tab = dynamic_cast(aux_model->getObject(rel->getReferenceTable()->getName(true), {ObjectType::Table, ObjectType::ForeignTable})); aux_rel = dynamic_cast(aux_model->getRelationship(ref_tab, rec_tab)); /* If the receiver table exists on the model generates a info for the relationship, otherwise, the generalization will be created automatically when the table is created (see table's code defintion) */ if(rec_tab && !aux_rel) generateDiffInfo(diff_type, rel); /* Special case for partitioning: we detach (drop) and reattach (create) the partition * if the partition bound expression differs from a model to another. This is done only * if the receiver table (partition) exists in the imported model. */ else if(rel->getRelationshipType()==BaseRelationship::RelationshipPart && rec_tab && aux_model == imported_model && aux_rel && rel->getPartitionBoundingExpr().simplified() != aux_rel->getPartitionBoundingExpr().simplified()) { generateDiffInfo(ObjectsDiffInfo::DropObject, rel); generateDiffInfo(ObjectsDiffInfo::CreateObject, rel); } } } else if(obj_type!=ObjectType::Permission) { //Get the object from the database obj_name=object->getSignature(); aux_object=aux_model->getObject(obj_name, obj_type); //Special case for many-to-many relationships if(obj_type==ObjectType::Table && !aux_object) aux_object=getRelNNTable(obj_name, aux_model); if(diff_type != ObjectsDiffInfo::DropObject && aux_object) { /* Try to get a diff from the retrieve object and the current object, * comparing only basic attributes like schema, tablespace and owner * this is why the BaseObject::getAlterDefinition is called */ objs_differs=!aux_object->BaseObject::getAlterDefinition(object).isEmpty(); //If the objects does not differ, try to compare their XML definition if(!objs_differs) xml_differs=object->isCodeDiffersFrom(aux_object, ObjectsIgnoredAttribs, ObjectsIgnoredTags); //If a difference was detected between the objects if(objs_differs || xml_differs) { generateDiffInfo(ObjectsDiffInfo::AlterObject, object, aux_object); //If the object is a table, do additional comparision between their child objects if((!diff_opts[OptForceRecreation] || diff_opts[OptRecreateUnchangeble]) && PhysicalTable::isPhysicalTable(object->getObjectType())) { PhysicalTable *tab=dynamic_cast(object), *aux_tab=dynamic_cast(aux_object); diffTables(tab, aux_tab, ObjectsDiffInfo::DropObject); diffTables(tab, aux_tab, ObjectsDiffInfo::CreateObject); } objs_differs=xml_differs=false; } } else if(!aux_object) { if(diff_type != ObjectsDiffInfo::DropObject || (diff_type == ObjectsDiffInfo::DropObject && !diff_opts[OptDontDropMissingObjs])) generateDiffInfo(diff_type, object); else generateDiffInfo(ObjectsDiffInfo::IgnoreObject, object); } } } //Comparison for constraints (fks), triggers, rules, indexes else if(TableObject::isTableObject(obj_type)) diffTableObject(dynamic_cast(object), diff_type); //Comparison between model db and the imported db else if(diff_type==ObjectsDiffInfo::CreateObject) { if(!source_model->getAlterDefinition(imported_model).isEmpty()) generateDiffInfo(ObjectsDiffInfo::AlterObject, source_model, imported_model); } if(diff_canceled) break; } else { generateDiffInfo(ObjectsDiffInfo::IgnoreObject, object); emit s_progressUpdated(prog + ((idx/static_cast(obj_order.size())) * factor), trUtf8("Skipping object `%1' (%2)...").arg(object->getSignature()).arg(object->getTypeName()), object->getObjectType()); if(diff_canceled) break; } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void ModelsDiffHelper::diffTableObject(TableObject *tab_obj, unsigned diff_type) { BaseTable *base_tab=nullptr, *aux_base_tab=nullptr; ObjectType obj_type=tab_obj->getObjectType(); QString tab_name, obj_name=tab_obj->getName(true); BaseObject *aux_tab_obj=nullptr; //Get the parent table of the object base_tab=tab_obj->getParentTable(); tab_name=base_tab->getSignature(); //If the operation is a DROP, try to get the table from the source mode if(diff_type==ObjectsDiffInfo::DropObject) { aux_base_tab=dynamic_cast(source_model->getObject(tab_name, base_tab->getObjectType())); //If the table was not found, try to find it between the many-to-many relationships if(!aux_base_tab) aux_base_tab=dynamic_cast(getRelNNTable(tab_name, source_model)); } else if(diff_type==ObjectsDiffInfo::CreateObject || diff_type==ObjectsDiffInfo::AlterObject) { aux_base_tab=dynamic_cast(imported_model->getObject(tab_name, base_tab->getObjectType())); //If the table was not found, try to find it between the many-to-many relationships if(!aux_base_tab) aux_base_tab=dynamic_cast(getRelNNTable(obj_name, imported_model)); } if(aux_base_tab) { if(obj_type==ObjectType::Constraint) { PhysicalTable *aux_table=dynamic_cast(aux_base_tab); aux_tab_obj=aux_table->getObject(obj_name, obj_type); } else aux_tab_obj=aux_base_tab->getObject(obj_name, obj_type); } if(!aux_tab_obj) { if(diff_type!=ObjectsDiffInfo::DropObject || (diff_type==ObjectsDiffInfo::DropObject && !diff_opts[OptDontDropMissingObjs])) generateDiffInfo(diff_type, tab_obj); else generateDiffInfo(ObjectsDiffInfo::IgnoreObject, tab_obj); } else if(diff_type!=ObjectsDiffInfo::DropObject && tab_obj->isCodeDiffersFrom(aux_tab_obj, TableObjsIgnoredAttribs)) generateDiffInfo(ObjectsDiffInfo::AlterObject, tab_obj, aux_tab_obj); } BaseObject *ModelsDiffHelper::getRelNNTable(const QString &obj_name, DatabaseModel *model) { vector *rels=model->getObjectList(ObjectType::Relationship); Relationship *rel=nullptr; BaseObject *tab=nullptr; for(auto &obj : *rels) { rel=dynamic_cast(obj); if(rel->getRelationshipType()==BaseRelationship::RelationshipNn && rel->getGeneratedTable() && rel->getGeneratedTable()->getSignature()==obj_name) { tab=rel->getGeneratedTable(); break; } } return(tab); } void ModelsDiffHelper::generateDiffInfo(unsigned diff_type, BaseObject *object, BaseObject *old_object) { try { if(object) { ObjectsDiffInfo diff_info; /* If the info is for ALTER and there is a DROP info on the list, * the object will be recreated instead of modified */ if((!diff_opts[OptForceRecreation] || diff_opts[OptRecreateUnchangeble]) && diff_type==ObjectsDiffInfo::AlterObject && isDiffInfoExists(ObjectsDiffInfo::DropObject, old_object, nullptr) && !isDiffInfoExists(ObjectsDiffInfo::CreateObject, object, nullptr)) { diff_info=ObjectsDiffInfo(ObjectsDiffInfo::CreateObject, object, nullptr); diff_infos.push_back(diff_info); diffs_counter[ObjectsDiffInfo::CreateObject]++; emit s_objectsDiffInfoGenerated(diff_info); } else if(!isDiffInfoExists(diff_type, object, old_object)) { Column *col=dynamic_cast(object), *old_col=dynamic_cast(old_object); /* Special case for columns marked with ALTER. * If the type of them is "serial" or similar then a sequence will be created and the * type of the column changed to "integer" or similar, this because the ALTER command * for columns don't accept the type "serial" */ if(diff_type==ObjectsDiffInfo::AlterObject && col && old_col && (col->getType()!=old_col->getType() && col->getType().isSerialType())) { Column *aux_col=new Column; Sequence *seq=new Sequence; BaseTable *tab=col->getParentTable(); QString seq_name=QString("%1_%2_seq").arg(tab->getName()).arg(col->getName()); if(seq_name.length() > BaseObject::ObjectNameMaxLength) seq_name.chop(seq_name.length() - BaseObject::ObjectNameMaxLength); seq->setName(seq_name); seq->setOwner(tab->getOwner()); seq->setSchema(tab->getSchema()); //Configure an auxiliary column with the same values of the original one (*aux_col)=(*col); aux_col->setDefaultValue(QString()); //Setting the type as the alias of the serial type aux_col->setType(aux_col->getType().getAliasType()); //Assigns the sequence to the column in order to configure the default value correctly aux_col->setSequence(seq); /* Creates a new ALTER info with the created column onlly if we don't need to reuse sequences * or if the sequence reusing is enabled but the type of the columns aren't equivalent or even * the types are equivalent but the sequences used by each columns aren't the same */ if(!diff_opts[OptReuseSequences] || (diff_opts[OptReuseSequences] && (!col->getType().getAliasType().isEquivalentTo(old_col->getType()) || (old_col->getSequence() && old_col->getSequence()->getSignature() != seq->getSignature())))) { diff_info=ObjectsDiffInfo(ObjectsDiffInfo::AlterObject, aux_col, col); diff_infos.push_back(diff_info); diffs_counter[ObjectsDiffInfo::AlterObject]++; emit s_objectsDiffInfoGenerated(diff_info); } if(!diff_opts[OptReuseSequences] || imported_model->getObjectIndex(seq->getSignature(), ObjectType::Sequence) < 0) { //Creates a CREATE info with the sequence diff_info=ObjectsDiffInfo(ObjectsDiffInfo::CreateObject, seq, nullptr); diff_infos.push_back(diff_info); diffs_counter[ObjectsDiffInfo::CreateObject]++; emit s_objectsDiffInfoGenerated(diff_info); } else if(diff_opts[OptReuseSequences]) { //Removing DROP infos related to the sequence that will be reused vector::iterator itr=diff_infos.begin(), itr_end=diff_infos.end(); while(itr!=itr_end) { if(itr->getDiffType()==ObjectsDiffInfo::DropObject && itr->getObject()->getObjectType()==ObjectType::Sequence && itr->getObject()->getSignature()==seq->getSignature()) { diff_infos.erase(itr); break; } itr++; } } /* Stores the created objects in the temp list in order to be destroyed * at the end of the process. */ tmp_objects.push_back(aux_col); tmp_objects.push_back(seq); } else { diff_info=ObjectsDiffInfo(diff_type, object, old_object); diff_infos.push_back(diff_info); diffs_counter[diff_type]++; emit s_objectsDiffInfoGenerated(diff_info); } /* If the info is for DROP, generate the drop for referer objects of the one marked to be dropped */ if((!diff_opts[OptForceRecreation] || diff_opts[OptRecreateUnchangeble]) && diff_type==ObjectsDiffInfo::DropObject) { vector ref_objs; ObjectType obj_type=object->getObjectType(); imported_model->getObjectReferences(object, ref_objs); for(auto &obj : ref_objs) { /* Avoiding columns to be dropped when a sequence linked to them is dropped too. This because a column can be a reference to a sequence so to avoid drop and recreate that column this one will not be erased, unless the column does not exists in the model anymore */ if((obj_type==ObjectType::Sequence && obj->getObjectType()!=ObjectType::Column) && (obj_type!=ObjectType::Sequence && obj->getObjectType()!=ObjectType::BaseRelationship)) generateDiffInfo(diff_type, obj); if(diff_canceled) break; } } } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } bool ModelsDiffHelper::isDiffInfoExists(unsigned diff_type, BaseObject *object, BaseObject *old_object, bool exact_match) { bool found_diff=false; ObjectsDiffInfo aux_diff(diff_type, object, old_object); for(ObjectsDiffInfo diff : diff_infos) { if((exact_match && diff==aux_diff) || (!exact_match && ((object && diff.getObject()==object) || (old_object && diff.getOldObject()==old_object)))) { found_diff=true; break; } } return(found_diff); } void ModelsDiffHelper::processDiffInfos(void) { BaseObject *object=nullptr; Relationship *rel=nullptr; map drop_objs, create_objs, alter_objs, truncate_tabs, create_fks, create_constrs; vector drop_vect, create_vect, drop_cols; unsigned diff_type, schema_id=0, idx=0; ObjectType obj_type; map::reverse_iterator ritr, ritr_end; attribs_map attribs; QString alter_def, no_inherit_def, inherit_def, set_perms, unset_perms, col_drop_def, curr_pgsql_ver = BaseObject::getPgSQLVersion(); SchemaParser schparser; Type *type=nullptr; vector types; Constraint *constr=nullptr; Column *col=nullptr, *aux_col=nullptr; PhysicalTable *parent_tab=nullptr; bool skip_obj=false; QStringList sch_names; try { //Overriding the global PostgreSQL version so the diff code can match the destination server version BaseObject::setPgSQLVersion(pgsql_version); if(!diff_infos.empty()) emit s_progressUpdated(0, trUtf8("Processing diff infos...")); //Reuniting the schema names to inject a SET search_path command for(auto &schema : *imported_model->getObjectList(ObjectType::Schema)) sch_names.push_back(schema->getName(true)); //Separating the base types for(ObjectsDiffInfo diff : diff_infos) { type=dynamic_cast(diff.getObject()); if(type && type->getConfiguration()==Type::BaseType) { type->convertFunctionParameters(); types.push_back(type); } } for(ObjectsDiffInfo diff : diff_infos) { diff_type=diff.getDiffType(); object=diff.getObject(); obj_type=object->getObjectType(); rel=dynamic_cast(object); constr=dynamic_cast(object); col=dynamic_cast(object); emit s_progressUpdated((idx++/static_cast(diff_infos.size())) * 100, trUtf8("Processing `%1' info for object `%2' (%3)...") .arg(diff.getDiffTypeString()).arg(object->getSignature()).arg(object->getTypeName()), obj_type); /* Preliminary verification for check constraints: there is the need to check if the constraint is added by generalization or if this is not the case if it already exists in a ancestor table of its parent, this avoid the generation of commands to create or drop an inherited constraint raising errors when export the diff */ if(constr && constr->getConstraintType()==ConstraintType::Check) { parent_tab=dynamic_cast(constr->getParentTable()); skip_obj=constr->isAddedByGeneralization(); for(unsigned i=0; i < parent_tab->getAncestorTableCount() && !skip_obj; i++) skip_obj=(parent_tab->getAncestorTable(i)->getConstraint(constr->getName())!=nullptr); if(skip_obj) continue; } //Igoring any operation done over inherited columns else if(col) { parent_tab=dynamic_cast(col->getParentTable()); skip_obj=col->isAddedByGeneralization(); for(unsigned i=0; i < parent_tab->getAncestorTableCount() && !skip_obj; i++) { aux_col=parent_tab->getAncestorTable(i)->getColumn(col->getName()); skip_obj=(aux_col && aux_col->getType().getAliasType()==col->getType()); } if(skip_obj) continue; } //Generating the DROP commands if(diff_type==ObjectsDiffInfo::DropObject) { if(rel && (rel->getRelationshipType()==BaseRelationship::RelationshipGen || rel->getRelationshipType()==BaseRelationship::RelationshipPart)) { //Undoing inheritances no_inherit_def+=rel->getAlterRelationshipDefinition(true); } else if(obj_type==ObjectType::Permission) //Unsetting permissions unset_perms+=object->getDropDefinition(diff_opts[OptCascadeMode]); else { //Ordinary drop commands for any object except columns if(obj_type!=ObjectType::Column) drop_objs[object->getObjectId()]=getCodeDefinition(object, true); else { /* Special case for columns: due to cases like inheritance there is the the need to drop the columns in the normal order of creation to avoid error like 'drop inherited column' or wrong propagation of drop on all child tables. */ drop_cols.push_back(object); } } } //Generating the CREATE commands else if(diff_type==ObjectsDiffInfo::CreateObject) { if(rel && (rel->getRelationshipType()==BaseRelationship::RelationshipGen || rel->getRelationshipType()==BaseRelationship::RelationshipPart)) { //Creating inheritances inherit_def+=rel->getAlterRelationshipDefinition(false); } else if(obj_type==ObjectType::Permission) //Setting permissions set_perms+=object->getCodeDefinition(SchemaParser::SqlDefinition); else { /* Special case for constaints: the creation commands for these objects are appended at the very end of create commands secion. Primary keys, unique keys, check constraints and exclude constraints are created after foreign keys */ if(object->getObjectType()==ObjectType::Constraint) { if(dynamic_cast(object)->getConstraintType()==ConstraintType::ForeignKey) create_fks[object->getObjectId()]=getCodeDefinition(object, false); else create_constrs[object->getObjectId()]=getCodeDefinition(object, false); } else { create_objs[object->getObjectId()]=getCodeDefinition(object, false); if(obj_type==ObjectType::Schema) sch_names.push_back(object->getName(true)); } } } //Generating the ALTER commands else if(diff_type==ObjectsDiffInfo::AlterObject) { //Recreating the object instead of generating an ALTER command for it if((diff_opts[OptForceRecreation] && obj_type!=ObjectType::Database) && (!diff_opts[OptRecreateUnchangeble] || (diff_opts[OptRecreateUnchangeble] && !object->acceptsAlterCommand() && diff.getObject()->getCodeDefinition(SchemaParser::SqlDefinition).simplified()!= diff.getOldObject()->getCodeDefinition(SchemaParser::SqlDefinition).simplified()))) { recreateObject(object, drop_vect, create_vect); //Generating the drop for the object's reference for(auto &obj : drop_vect) drop_objs[obj->getObjectId()]=getCodeDefinition(obj, true); //Generating the create for the object's reference for(auto &obj : create_vect) { //The there is no ALTER info registered for an object's reference if(!isDiffInfoExists(ObjectsDiffInfo::AlterObject, nullptr, obj, false)) { /* Special case for constraints, their code will be appeded to a separated variable in order to create them at the end of diff buffer */ if(obj->getObjectType()==ObjectType::Constraint) { if(dynamic_cast(obj)->getConstraintType()==ConstraintType::ForeignKey) create_fks[obj->getObjectId()]=getCodeDefinition(obj, false); else create_constrs[obj->getObjectId()]=getCodeDefinition(obj, false); } else create_objs[obj->getObjectId()]=getCodeDefinition(obj, false); } } drop_vect.clear(); create_vect.clear(); } else { if(diff.getOldObject()) alter_def=diff.getOldObject()->getAlterDefinition(object); if(obj_type == ObjectType::Database && diff_opts[OptPreserveDbName]) alter_def.remove(QRegExp(QString("(ALTER)( )+(DATABASE)( )+(%1)( )+(RENAME)( )+(TO)(.)*(\\n)").arg(diff.getOldObject()->getSignature()))); if(!alter_def.isEmpty()) { alter_objs[object->getObjectId()]=alter_def; /* If the object is a column checks if the types of the columns are differents, generating a TRUNCATE TABLE for the parent table */ if(obj_type==ObjectType::Column && diff_opts[OptTruncateTables]) { Column *src_col=dynamic_cast(object), *old_col=dynamic_cast(diff.getOldObject()); Table *tab=dynamic_cast
(src_col->getParentTable()); if(tab && ((old_col->getType().isSerialType() && !src_col->getType().isEquivalentTo(old_col->getType().getAliasType())) || (!old_col->getType().isSerialType() && !src_col->getType().isEquivalentTo(old_col->getType()))) && truncate_tabs.count(tab->getObjectId())==0) { truncate_tabs[tab->getObjectId()]=tab->getTruncateDefinition(diff_opts[OptCascadeMode]); } } } } } } //Creating the shell types declaration right below on the DDL that creates their schemas for(Type *type : types) { schema_id=type->getSchema()->getObjectId(); if(create_objs.count(schema_id)!=0) create_objs[schema_id]+=type->getCodeDefinition(SchemaParser::SqlDefinition, true); else attribs[Attributes::CreateCmds]+=type->getCodeDefinition(SchemaParser::SqlDefinition, true); type->convertFunctionParameters(true); } //Generating the drop command for columns for(BaseObject *col : drop_cols) col_drop_def+=getCodeDefinition(col, true); diff_def.clear(); if(!drop_objs.empty() || !create_objs.empty() || !alter_objs.empty() || !create_fks.empty() || !create_constrs.empty() || !inherit_def.isEmpty() || !no_inherit_def.isEmpty() || !set_perms.isEmpty() || !col_drop_def.isEmpty()) { unsigned create_objs_count=create_objs.size() + create_constrs.size() + create_fks.size(); bool has_diffs=false; sch_names.removeDuplicates(); has_diffs=(create_objs_count!=0 || alter_objs.size()!=0 || drop_objs.size()!=0); //Attributes used on the diff schema file attribs[Attributes::HasChanges]=Attributes::True; attribs[Attributes::PgModelerVersion]=GlobalAttributes::PgModelerVersion; attribs[Attributes::DbModel]=source_model->getName(); attribs[Attributes::Database]=imported_model->getName(); attribs[Attributes::Date]=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); attribs[Attributes::Connection]=imported_model->getName(); attribs[Attributes::Change]=QString::number(alter_objs.size()); attribs[Attributes::Create]=QString::number(create_objs_count); attribs[Attributes::Drop]=QString::number(drop_objs.size()); attribs[Attributes::Truncate]=QString::number(truncate_tabs.size()); attribs[Attributes::AlterCmds]=QString(); attribs[Attributes::DropCmds]=QString(); attribs[Attributes::CreateCmds]=QString(); attribs[Attributes::TruncateCmds]=QString(); attribs[Attributes::ConstrDefs]=QString(); attribs[Attributes::FkDefs]=QString(); attribs[Attributes::UnsetPerms]=unset_perms; attribs[Attributes::SetPerms]=set_perms; attribs[Attributes::Function]=(has_diffs && source_model->getObjectCount(ObjectType::Function)!=0 ? Attributes::True : QString()); attribs[Attributes::SearchPath]=(has_diffs ? sch_names.join(',') : QString()); ritr=drop_objs.rbegin(); ritr_end=drop_objs.rend(); attribs[Attributes::DropCmds]+=no_inherit_def; while(ritr!=ritr_end) { attribs[Attributes::DropCmds]+=ritr->second; ritr++; } attribs[Attributes::DropCmds]+=col_drop_def; for(auto &itr : create_objs) attribs[Attributes::CreateCmds]+=itr.second; attribs[Attributes::CreateCmds]+=inherit_def; for(auto &itr : create_constrs) attribs[Attributes::ConstrDefs]+=itr.second; for(auto &itr : create_fks) attribs[Attributes::FkDefs]+=itr.second; for(auto &itr : truncate_tabs) attribs[Attributes::TruncateCmds]+=itr.second; for(auto &itr : alter_objs) attribs[Attributes::AlterCmds]+=itr.second; //Generating the whole diff buffer schparser.setPgSQLVersion(pgsql_version); diff_def=schparser.getCodeDefinition(GlobalAttributes::SchemasRootDir + GlobalAttributes::DirSeparator + GlobalAttributes::AlterSchemaDir + GlobalAttributes::DirSeparator + Attributes::Diff + GlobalAttributes::SchemaExt, attribs); } if(diff_def.isEmpty()) emit s_progressUpdated(100, trUtf8("No differences between the model and database.")); else emit s_progressUpdated(100, trUtf8("Preparing diff code...")); //Restoring the global PostgreSQL version BaseObject::setPgSQLVersion(curr_pgsql_ver); } catch(Exception &e) { BaseObject::setPgSQLVersion(curr_pgsql_ver); for(Type *type : types) type->convertFunctionParameters(true); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString ModelsDiffHelper::getCodeDefinition(BaseObject *object, bool drop_cmd) { try { TableObject *tab_obj=dynamic_cast(object); QString cmd; /* For columns and constraints it is needed to force the generation of ALTER commands on the parent table */ if(tab_obj && (tab_obj->getObjectType()==ObjectType::Column || tab_obj->getObjectType()==ObjectType::Constraint)) { bool gen_alter=false; PhysicalTable *table=dynamic_cast(tab_obj->getParentTable()); gen_alter=table->isGenerateAlterCmds(); table->setGenerateAlterCmds(true); if(drop_cmd) cmd=tab_obj->getDropDefinition(diff_opts[OptCascadeMode]); else cmd=tab_obj->getCodeDefinition(SchemaParser::SqlDefinition); table->setGenerateAlterCmds(gen_alter); } else { if(drop_cmd) cmd=object->getDropDefinition(diff_opts[OptCascadeMode]); else cmd=object->getCodeDefinition(SchemaParser::SqlDefinition); } return(cmd); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void ModelsDiffHelper::destroyTempObjects(void) { BaseObject *tmp_obj=nullptr; while(!tmp_objects.empty()) { tmp_obj=tmp_objects.back(); tmp_objects.pop_back(); delete(tmp_obj); } diff_infos.clear(); } void ModelsDiffHelper::recreateObject(BaseObject *object, vector &drop_objs, vector &create_objs) { if(object && object->getObjectType()!=ObjectType::BaseRelationship && object->getObjectType()!=ObjectType::Relationship && object->getObjectType()!=ObjectType::Database) { vector ref_objs; BaseObject *aux_obj=nullptr; /* If the specified object is not a table's child object, try to get an object from database which name is the same as 'object' */ if(!TableObject::isTableObject(object->getObjectType())) aux_obj=imported_model->getObject(object->getSignature(), object->getObjectType()); else { TableObject *tab_obj=dynamic_cast(object); if(tab_obj->getParentTable()) { /* If the object is a table's child object, first we get a table from the database which name is the same as the 'object' parent table's name. Sencond, we try to get a child object from that table using the same name as the 'object' */ BaseTable *tab=dynamic_cast(imported_model->getObject(tab_obj->getParentTable()->getSignature(), tab_obj->getParentTable()->getObjectType())); aux_obj=tab->getObject(tab_obj->getName(true), tab_obj->getObjectType()); } } //Get all references to the retrieved object on the database imported_model->getObjectReferences(aux_obj, ref_objs, false, true); /* If the to-be recreate object is a constraint check if it's a pk, if so, the fk's linked to it need to be recreated as well */ if(aux_obj->getObjectType()==ObjectType::Constraint) { Constraint *constr=dynamic_cast(aux_obj); if(constr->getConstraintType()==ConstraintType::PrimaryKey) { unsigned i=0, col_cnt=constr->getColumnCount(Constraint::SourceCols); vector ref_aux; Constraint *aux_constr=nullptr; for(i=0; i < col_cnt; i++) { //Get the objects referencing the source columns of the pk imported_model->getObjectReferences(constr->getColumn(i, Constraint::SourceCols), ref_aux, false, true); //Selecting only fks from the references list for(BaseObject *obj : ref_aux) { aux_constr=dynamic_cast(obj); if(aux_constr && aux_constr->getConstraintType()==ConstraintType::ForeignKey) ref_objs.push_back(aux_constr); } } } } /* Register a drop info for the object only if there is no drop registered previously, avoiding multiple drop statments for the same object */ if(aux_obj && !isDiffInfoExists(ObjectsDiffInfo::DropObject, aux_obj, nullptr)) drop_objs.push_back(aux_obj); /* Register a create info for the object only if there is no drop or create registered previously, avoiding wrongly recreating the object */ if(!isDiffInfoExists(ObjectsDiffInfo::DropObject, aux_obj, nullptr) && !isDiffInfoExists(ObjectsDiffInfo::CreateObject, aux_obj, nullptr)) create_objs.push_back(object); //Executing the recreation of the object's references for(auto &obj : ref_objs) recreateObject(obj, drop_objs, create_objs); } } pgmodeler-0.9.2/libpgmodeler_ui/src/modelsdiffhelper.h000066400000000000000000000175171360462764600231470ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class DatabaseModelsDiffHelper \brief Implements the operations to compare and generate a diff between two database models. */ #ifndef MODELS_DIFF_HELPER_H #define MODELS_DIFF_HELPER_H #include #include "databasemodel.h" #include "objectsdiffinfo.h" class ModelsDiffHelper: public QObject { private: Q_OBJECT //! \brief List of attributes ignored when comparing XML code of table children objects static const vector TableObjsIgnoredAttribs, //! \brief List of attributes ignored when comparing XML code of database objects ObjectsIgnoredAttribs, //! \brief List of tags ignored when comparing XML code of database objects ObjectsIgnoredTags; //! \brief Stores the SQL code that represents the diff between model and database QString diff_def, //! \brief PostgreSQL version used to generate the diff pgsql_version; //! \brief Indicates if the diff was cancelled by user bool diff_canceled, //!brief Diff options. See OPT_??? constants diff_opts[10]; //! \brief Stores the count of objects to be dropped, changed or created unsigned diffs_counter[4]; //! \brief Reference model from which all changes are generated DatabaseModel *source_model, //! \brief Model which is compared to the source one *imported_model; //! \brief Stores all generated diff information during the process vector diff_infos; //! \brief Stores all temporary objects created during the diff process vector tmp_objects; /*! note The parameter diff_type in any methods below is one of the values in ObjectsDiffInfo::CREATE_OBJECT|ALTER_OBJECT|DROP_OBJECT */ //! \brief Compares two tables storing the diff between them in the diff_infos vector. void diffTables(PhysicalTable *src_table, PhysicalTable *imp_table, unsigned diff_type); //! \brief Compares the two models storing the diff between them in the diff_infos vector. void diffModels(unsigned diff_type); /*! \brief Compares the specified table object against the ones on the source model or imported model depending on the diff_type parameter. */ void diffTableObject(TableObject *tab_obj, unsigned diff_type); //! \brief Creates a diff info instance storing in o diff_infos vector void generateDiffInfo(unsigned diff_type, BaseObject *object, BaseObject *old_object=nullptr); /*! \brief Processes the generated diff infos resulting in a SQL buffer with the needed commands to synchronize both model and database */ void processDiffInfos(void); /*! \brief Generates the proper DROP and CREATE for the specified object and its references. This method is used when the force_recreation is true and the object in the parameter is marked with an ALTER_OBJECT */ void recreateObject(BaseObject *object, vector &drop_objs, vector &create_objs); /*! \brief Returns if a diff information exists for the object. The exact_match parameter is used to force the comparison of all values on the paramenter against the diff infos. When false the exact_match parameter considers one of parameters object or old_object to be used (if not null) */ bool isDiffInfoExists(unsigned diff_type, BaseObject *object, BaseObject *old_object, bool exact_match = true); /*! \brief Generate the proper code definition for the table's child objects. If drop_cmd is true a DROP command will be generated otherwise a CREATE is generated. */ QString getCodeDefinition(BaseObject *object, bool drop_cmd); //! \brief Destroy the temporary objects and clears the diff info list void destroyTempObjects(void); BaseObject *getRelNNTable(const QString &obj_name, DatabaseModel *model); public: static constexpr unsigned OptKeepClusterObjs=0, //! \brief Indicates if any DROP/TRUNCATE generated must be in cascade mode OptCascadeMode=1, //! \brief Forces the recreation of any object maked as ALTER in the output OptForceRecreation=2, //! \brief Recreates only objects that can't be modified using ALTER commands OptRecreateUnchangeble=3, //! \brief Generate a TRUNCATE command for every table which columns was modified in their data types OptTruncateTables=4, //! \brief Indicates if permissions must be preserved on database OptKeepObjectPerms=5, /*! \brief Indicates that existing sequences must be reused in serial columns. Since serial columns are converted into integer and a new sequence created and assigned as nextval(sequence) default value for those columns, if reuse is enabled, new sequences will not be created instead the ones which name matches the column's default value will be reused */ OptReuseSequences=6, //! \brief Indicates to not generate and execute commands to rename the destination database OptPreserveDbName=7, /*! \brief Indicates to not generate and execute commands to drop missing objects. For instance, if user try to diff a partial model against the original database DROP commands will be generated, this option will avoid this situation and preserve the missing (not imported) objects. */ OptDontDropMissingObjs=8, /*! \brief Indicates to generate and execute commands to drop missing columns and constraints. For instance, if user try to diff a partial model against the original database and the OPT_DONT_DROP_MISSING_OBJS is set, DROP commands will not be generated, except for columns and constraints. This option is only considered in the process when OPT_DONT_DROP_MISSING_OBJS is enabled. */ OptDropMissingColsConstr=9; ModelsDiffHelper(void); ~ModelsDiffHelper(void); /*! \brief Configures the models to be compared. It is assumed that src_model is the reference model from which all changes must be collected and applied to the database. The imp_model is the database model that represents the current arrange of the database. */ void setModels(DatabaseModel *src_model, DatabaseModel *imp_model); //! \brief Toggles a diff option throught the OPT_xxx constants void setDiffOption(unsigned opt_id, bool value); //! \brief Configures the PostgreSQL version used in the diff generation void setPgSQLVersion(const QString pgsql_ver); //! \brief Returns the count of diff infos of the specified diff_type unsigned getDiffTypeCount(unsigned diff_type); //! \brief Reset all the diff info counters in order to restart the diff process void resetDiffCounter(void); //! \brief Returns the diff containing all the SQL commands needed to synchronize the model and database QString getDiffDefinition(void); public slots: void diffModels(void); void cancelDiff(void); signals: //! \brief This singal is emitted whenever the diff progress changes void s_progressUpdated(int progress, QString msg, ObjectType obj_type=ObjectType::BaseObject); //! \brief This signal is emited when the diff has finished void s_diffFinished(void); //! \brief This signal is emited when the diff has been canceled void s_diffCanceled(void); //! \brief This signal is emited when the diffhas encountered a critical error (only in thread mode) void s_diffAborted(Exception e); //! \brief This signal is emitted when a diff info is generated void s_objectsDiffInfoGenerated(ObjectsDiffInfo diff_info); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelvalidationhelper.cpp000066400000000000000000000567101360462764600245370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelvalidationhelper.h" ModelValidationHelper::ModelValidationHelper(void) { warn_count=error_count=progress=0; db_model=nullptr; conn=nullptr; valid_canceled=fix_mode=use_tmp_names=false; export_thread=new QThread; export_helper.moveToThread(export_thread); connect(export_thread, SIGNAL(started(void)), &export_helper, SLOT(exportToDBMS(void))); connect(&export_helper, SIGNAL(s_progressUpdated(int,QString, ObjectType,QString,bool)), this, SLOT(redirectExportProgress(int,QString,ObjectType,QString,bool))); connect(&export_helper, SIGNAL(s_exportFinished(void)), this, SLOT(emitValidationFinished(void))); connect(&export_helper, SIGNAL(s_exportAborted(Exception)), this, SLOT(captureThreadError(Exception))); } ModelValidationHelper::~ModelValidationHelper(void) { export_thread->quit(); export_thread->wait(); delete(export_thread); } void ModelValidationHelper::generateValidationInfo(unsigned val_type, BaseObject *object, vector refs) { if(!refs.empty() || val_type==ValidationInfo::MissingExtension || (val_type==ValidationInfo::BrokenRelConfig && std::find(inv_rels.begin(), inv_rels.end(), object)==inv_rels.end())) { //Configures a validation info ValidationInfo info=ValidationInfo(val_type, object, refs); error_count++; val_infos.push_back(info); if(val_type==ValidationInfo::BrokenRelConfig) inv_rels.push_back(object); //Emit the signal containing the info emit s_validationInfoGenerated(info); } } void ModelValidationHelper::resolveConflict(ValidationInfo &info) { try { vector refs=info.getReferences(); BaseObject *obj=nullptr; //Resolving broken references by swaping the object ids if(info.getValidationType()==ValidationInfo::BrokenReference || info.getValidationType()==ValidationInfo::SpObjBrokenReference) { BaseObject *info_obj=info.getObject(), *aux_obj=nullptr; unsigned obj_id=info_obj->getObjectId(); if(info.getValidationType()==ValidationInfo::BrokenReference) { //Search for the object with the minor id while(!refs.empty() && !valid_canceled) { //For commom broken reference, check if the object id is greater than the reference id if(obj_id > refs.back()->getObjectId()) { obj=refs.back(); } //Swap the id of the validation object and the found object (minor id) if(obj) { TableObject *tab_obj=dynamic_cast(obj); if(!tab_obj) { BaseObject::swapObjectsIds(info_obj, obj, true); aux_obj=info_obj; emit s_objectIdChanged(obj); } else if(tab_obj && tab_obj->getParentTable()==info_obj) { BaseObject::updateObjectId(tab_obj); emit s_objectIdChanged(tab_obj); } } if(aux_obj && BaseTable::isBaseTable(aux_obj->getObjectType())) { vector base_rels=db_model->getRelationships(dynamic_cast(aux_obj)); for(auto &rel : base_rels) { if(rel->getObjectId() < aux_obj->getObjectId()) { BaseObject::updateObjectId(rel); emit s_objectIdChanged(rel); } } } refs.pop_back(); obj=nullptr; obj_id=info_obj->getObjectId(); } } else { BaseObject::updateObjectId(info_obj); } emit s_objectIdChanged(info_obj); } //Resolving no unique name by renaming the constraints/indexes else if(info.getValidationType()==ValidationInfo::NoUniqueName) { unsigned suffix=1; QString new_name; BaseTable *table=nullptr; ObjectType obj_type; BaseObject *obj=info.getObject(); TableObject *tab_obj=nullptr; /* If the last element of the referrer objects is a table or view the info object itself need to be renamed since tables and views will not be renamed */ bool rename_obj=BaseTable::isBaseTable(refs.back()->getObjectType()); if(rename_obj) { table=dynamic_cast(dynamic_cast(obj)->getParentTable()); obj_type=obj->getObjectType(); do { //Configures a new name for the object [name]_[suffix] new_name=QString("%1_%2").arg(obj->getName()).arg(suffix); suffix++; } //Generates a new name until no object is found on parent table while(table->getObjectIndex(new_name, obj_type) >= 0); //Renames the object obj->setName(new_name); table->setModified(true); } //Renaming the referrer objects while(!refs.empty() && !valid_canceled) { obj_type=refs.back()->getObjectType(); tab_obj=dynamic_cast(refs.back()); //Tables and view aren't renamed only table child objects (constraints, indexes) if(tab_obj && !tab_obj->isAddedByRelationship()) { table=dynamic_cast(tab_obj->getParentTable()); do { //Configures a new name for the object [name]_[suffix] new_name=QString("%1_%2").arg(tab_obj->getName()).arg(suffix); suffix++; } //Generates a new name until no object is found on parent table while(table->getObjectIndex(new_name, obj_type) >= 0); //Renames the referrer object tab_obj->setName(new_name); table->setModified(true); } refs.pop_back(); } } //Resolving the absence of postgis extension else if(info.getValidationType()==ValidationInfo::MissingExtension && !db_model->getExtension(QString("postgis"))) { Extension *extension = new Extension(); extension->setName(QString("postgis")); db_model->addExtension(extension); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } bool ModelValidationHelper::isValidationCanceled(void) { return(valid_canceled); } unsigned ModelValidationHelper::getWarningCount(void) { return(warn_count); } unsigned ModelValidationHelper::getErrorCount(void) { return(error_count); } void ModelValidationHelper::redirectExportProgress(int prog, QString msg, ObjectType obj_type, QString cmd, bool is_code_gen) { if(!export_thread->isRunning()) return; progress=41 + (prog * 0.55); if(progress > 99) progress=99; emit s_progressUpdated(progress, msg, obj_type, cmd, is_code_gen); } void ModelValidationHelper::setValidationParams(DatabaseModel *model, Connection *conn, const QString &pgsql_ver, bool use_tmp_names) { if(!model) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); fix_mode=false; valid_canceled=false; val_infos.clear(); inv_rels.clear(); this->db_model=model; this->conn=conn; this->pgsql_ver=pgsql_ver; this->use_tmp_names=use_tmp_names; export_helper.setExportToDBMSParams(this->db_model, conn, pgsql_ver, false, false, false, true, use_tmp_names); } void ModelValidationHelper::switchToFixMode(bool value) { fix_mode=value; } bool ModelValidationHelper::isInFixMode() { return(fix_mode); } void ModelValidationHelper::validateModel(void) { if(!db_model) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { ObjectType types[]={ ObjectType::Role, ObjectType::Tablespace, ObjectType::Schema, ObjectType::Language, ObjectType::Function, ObjectType::Type, ObjectType::Domain, ObjectType::Sequence, ObjectType::Operator, ObjectType::OpFamily, ObjectType::OpClass, ObjectType::Collation, ObjectType::Table, ObjectType::Extension, ObjectType::View, ObjectType::Relationship, ObjectType::ForeignDataWrapper, ObjectType::ForeignServer, ObjectType::GenericSql, ObjectType::ForeignTable }, aux_types[]={ ObjectType::Table, ObjectType::ForeignTable, ObjectType::View }, tab_obj_types[]={ ObjectType::Constraint, ObjectType::Index }, obj_type; unsigned i, i1, cnt, aux_cnt=sizeof(aux_types)/sizeof(ObjectType), count=sizeof(types)/sizeof(ObjectType), count1=sizeof(tab_obj_types)/sizeof(ObjectType); BaseObject *object=nullptr, *refer_obj=nullptr; vector refs, refs_aux, *obj_list=nullptr, aux_tables; vector::iterator itr; TableObject *tab_obj=nullptr; PhysicalTable *table=nullptr, *ref_tab=nullptr, *recv_tab=nullptr; BaseTable *base_tab = nullptr; Constraint *constr=nullptr; Column *col=nullptr; Relationship *rel=nullptr; map > dup_objects; map >::iterator mitr; QString name, signal_msg=QString("`%1' (%2)"); bool postgis_exists = db_model->getObjectIndex(QString("postgis"), ObjectType::Extension) >= 0; warn_count=error_count=progress=0; val_infos.clear(); valid_canceled=false; /* Step 1: Validating broken references. This situation happens when a object references another which id is smaller than the id of the first one. */ for(i=0; i < count && !valid_canceled; i++) { obj_list=db_model->getObjectList(types[i]); itr=obj_list->begin(); while(itr!=obj_list->end() && !valid_canceled) { object=(*itr); obj_type=object->getObjectType(); refs_aux.clear(); itr++; //Excluding the validation of system objects (created automatically) if(!object->isSystemObject()) { emit s_objectProcessed(signal_msg.arg(object->getName()).arg(object->getTypeName()), object->getObjectType()); /* Special validation case: For generalization and copy relationships validates the ids of participant tables. Reference table cannot own an id greater thant receiver table */ if(obj_type==ObjectType::Relationship) { rel=dynamic_cast(object); if(rel->getRelationshipType()==Relationship::RelationshipGen || rel->getRelationshipType()==Relationship::RelationshipDep || rel->getRelationshipType()==Relationship::RelationshipPart) { recv_tab=rel->getReceiverTable(); ref_tab=rel->getReferenceTable(); if(ref_tab->getObjectId() > recv_tab->getObjectId()) { object=ref_tab; refs_aux.push_back(recv_tab); } } } else { db_model->getObjectReferences(object, refs); while(!refs.empty() && !valid_canceled) { //Checking if the referrer object is a table object. In this case its parent table is considered tab_obj=dynamic_cast(refs.back()); constr=dynamic_cast(tab_obj); col=dynamic_cast(tab_obj); /* If the current referrer object has an id less than reference object's id * then it will be pushed into the list of invalid references. The only exception is * for foreign keys that are discarded from any validation since they are always created * at end of code defintion being free of any reference breaking. */ if(object != refs.back() && ( ((col || (constr && constr->getConstraintType()!=ConstraintType::ForeignKey)) && (tab_obj->getParentTable()->getObjectId() <= object->getObjectId())) || (!constr && refs.back()->getObjectId() <= object->getObjectId())) ) { if(col || constr) refer_obj=tab_obj->getParentTable(); else refer_obj=refs.back(); refs_aux.push_back(refer_obj); } refs.pop_back(); } /* Validating a special object. The validation made here is to check if the special object * (constraint/index/trigger/view) references a column added by a relationship and * that relationship is being created after the creation of the special object */ if(BaseTable::isBaseTable(obj_type) || obj_type == ObjectType::GenericSql) { vector tab_aux_types={ ObjectType::Constraint, ObjectType::Trigger, ObjectType::Index }; vector *tab_objs; vector ref_cols; vector rels; BaseObject *rel=nullptr; View *view=nullptr; GenericSQL *gen_sql=nullptr; Constraint *constr=nullptr; table=dynamic_cast(object); view=dynamic_cast(object); gen_sql = dynamic_cast(object); if(table) { /* Checking the table children objects if they references some columns added by relationship. * If so, the id of the relationships are swapped with the child object if the first is created * after the latter. */ for(auto &obj_tp : tab_aux_types) { tab_objs = table->getObjectList(obj_tp); if(!tab_objs) continue; for(auto &tab_obj : (*tab_objs)) { ref_cols.clear(); rels.clear(); if(!tab_obj->isAddedByRelationship()) { if(obj_tp==ObjectType::Constraint) { constr=dynamic_cast(tab_obj); if(constr->getConstraintType()!=ConstraintType::PrimaryKey) ref_cols=constr->getRelationshipAddedColumns(); } else if(obj_tp==ObjectType::Trigger) ref_cols=dynamic_cast(tab_obj)->getRelationshipAddedColumns(); else ref_cols=dynamic_cast(tab_obj)->getRelationshipAddedColumns(); } //Getting the relationships that owns the columns for(auto &ref_col : ref_cols) { rel=ref_col->getParentRelationship(); if(rel->getObjectId() > tab_obj->getObjectId() && std::find(rels.begin(), rels.end(), rel)==rels.end()) rels.push_back(rel); } generateValidationInfo(ValidationInfo::SpObjBrokenReference, tab_obj, rels); } } } else if(view) { ref_cols=view->getRelationshipAddedColumns(); //Getting the relationships that owns the columns for(auto &ref_col : ref_cols) { rel=ref_col->getParentRelationship(); if(rel->getObjectId() > object->getObjectId() && std::find(rels.begin(), rels.end(), rel)==rels.end()) rels.push_back(rel); } generateValidationInfo(ValidationInfo::SpObjBrokenReference, object, rels); } else { Column *col = nullptr; for(auto &ref_obj : gen_sql->getReferencedObjects()) { col = dynamic_cast(ref_obj); if(!col || !col->isAddedByRelationship()) continue; rel = col->getParentRelationship(); if(rel->getObjectId() > object->getObjectId() && std::find(rels.begin(), rels.end(), rel) == rels.end()) rels.push_back(rel); } generateValidationInfo(ValidationInfo::SpObjBrokenReference, object, rels); } } } generateValidationInfo(ValidationInfo::BrokenReference, object, refs_aux); } } //Emit a signal containing the validation progress progress=((i+1)/static_cast(count))*20; emit s_progressUpdated(progress, QString()); } /* Step 2: Validating name conflitcs between primary keys, unique keys, exclude constraints and indexs of all tables/foreign talbes/views. The tables/views names are checked too. */ aux_tables = *db_model->getObjectList(ObjectType::Table); aux_tables.insert(aux_tables.end(), db_model->getObjectList(ObjectType::View)->begin(), db_model->getObjectList(ObjectType::View)->end()); itr = aux_tables.begin(); //Searching the model's tables and gathering all the constraints and index while(itr != aux_tables.end() && !valid_canceled) { base_tab = dynamic_cast(*itr); emit s_objectProcessed(signal_msg.arg(base_tab->getName()).arg(base_tab->getTypeName()), base_tab->getObjectType()); itr++; for(i=0; i < count1 && !valid_canceled; i++) { cnt=base_tab->getObjectCount(tab_obj_types[i]); for(i1=0; i1 < cnt && !valid_canceled; i1++) { //Get the table object (constraint or index) tab_obj=dynamic_cast(base_tab->getObject(i1, tab_obj_types[i])); //Configures the full name of the object including the parent name name=tab_obj->getParentTable()->getSchema()->getName(true) + QString(".") + tab_obj->getName(true); name.remove('"'); //Trying to convert the object to constraint constr=dynamic_cast(tab_obj); /* If the object is an index or a primary key, unique or exclude constraint, * insert the object on duplicated objects map */ if((!constr || (constr && (constr->getConstraintType()==ConstraintType::PrimaryKey || constr->getConstraintType()==ConstraintType::Unique || constr->getConstraintType()==ConstraintType::Exclude)))) dup_objects[name].push_back(tab_obj); } } } /* Inserting the tables and views to the map in order to check if there are * other table objects that conflicts with them */ for(i=0; i < aux_cnt && !valid_canceled; i++) { obj_list=db_model->getObjectList(aux_types[i]); itr=obj_list->begin(); while(itr!=obj_list->end() && !valid_canceled) { dup_objects[(*itr)->getName(true).remove('"')].push_back(*itr); itr++; } } //Checking the map of duplicated objects mitr=dup_objects.begin(); i=1; while(mitr!=dup_objects.end() && !valid_canceled) { /* If the vector of the current map element has more the one object indicates the duplicity thus generates a validation info */ if(mitr->second.size() > 1) { refs.assign(mitr->second.begin() + 1, mitr->second.end()); generateValidationInfo(ValidationInfo::NoUniqueName, mitr->second.front(), refs); refs.clear(); } //Emit a signal containing the validation progress progress=20 + ((i/static_cast(dup_objects.size()))*20); emit s_progressUpdated(progress, QString()); i++; mitr++; } // Step 3: Checking if columns of any table is using GiS data types and the postgis extension is not created. if(!postgis_exists) { vector tabs; tabs.assign(db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); tabs.insert(tabs.end(), db_model->getObjectList(ObjectType::ForeignTable)->begin(), db_model->getObjectList(ObjectType::ForeignTable)->end()); itr=tabs.begin(); i=0; while(itr!=tabs.end() && !valid_canceled) { table = dynamic_cast(*itr); itr++; for(auto &obj : *table->getObjectList(ObjectType::Column)) { col = dynamic_cast(obj); if(col->getType().isGiSType()) generateValidationInfo(ValidationInfo::MissingExtension, col, {}); } progress=30 + ((i/static_cast(obj_list->size()))*20); } } /* Step 4: Checking if there are some invalidated relationship. In some cases, specially with identifier and generalization relationships, the columns aren't correctly propagated due to creation order and special behavior of those objects. Thus, in order to keep all columns synchonized it is need to make this step and change the relationship creation order if needed. This step is executed only when there is no validation infos generated because for each broken relationship there is the need to do a revalidation of all relationships */ if(val_infos.empty()) { obj_list=db_model->getObjectList(ObjectType::Relationship); itr=db_model->getObjectList(ObjectType::Relationship)->begin(); while(itr!=obj_list->end() && !valid_canceled) { progress=40 + ((i/static_cast(obj_list->size()))*20); if(dynamic_cast(*itr)->isInvalidated()) generateValidationInfo(ValidationInfo::BrokenRelConfig, *itr, {}); itr++; } } if(!valid_canceled && !fix_mode) { //Step 3 (optional): Validating the SQL code onto a local DBMS. //Case the connection isn't specified indicates that the SQL validation will not be executed if(!conn) { //Emit a signal indicating the final progress emitValidationFinished(); } //SQL validation only occurs when the model is completely validated. else { //If there is no errors start the dbms export thread if(error_count==0) { export_thread->start(); emit s_sqlValidationStarted(); } else { warn_count++; emitValidationFinished(); emit s_validationInfoGenerated(ValidationInfo(trUtf8("There are pending errors! SQL validation will not be executed."))); } } } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelValidationHelper::applyFixes(void) { if(fix_mode) { bool validate_rels=false, found_broken_rels=false; while(!val_infos.empty() && !valid_canceled && !found_broken_rels) { for(unsigned i=0; i < val_infos.size() && !valid_canceled; i++) { if(!validate_rels) validate_rels=(val_infos[i].getValidationType()==ValidationInfo::BrokenReference || val_infos[i].getValidationType()==ValidationInfo::SpObjBrokenReference || val_infos[i].getValidationType()==ValidationInfo::NoUniqueName || val_infos[i].getValidationType()==ValidationInfo::MissingExtension); /* Checking if a broken relatinship is found, when this is the case all the pending validation info will not be analyzed until no broken relationship is found */ if(!found_broken_rels) found_broken_rels=(val_infos[i].getValidationType()==ValidationInfo::BrokenRelConfig); if(!valid_canceled) resolveConflict(val_infos[i]); } emit s_fixApplied(); if(!valid_canceled && !found_broken_rels) validateModel(); } if(!valid_canceled && (found_broken_rels || val_infos.empty())) { //Emits a signal indicating that the relationships must revalidated if(validate_rels || found_broken_rels) emit s_relsValidationRequested(); fix_mode=false; } } } void ModelValidationHelper::cancelValidation(void) { valid_canceled=true; fix_mode=false; val_infos.clear(); export_helper.cancelExport(); emitValidationCanceled(); } void ModelValidationHelper::captureThreadError(Exception e) { ValidationInfo val_info(e); export_thread->quit(); export_thread->wait(); warn_count++; /* Indicates the model invalidation only when there are validation warnings (broken refs. or no unique name) sql errors are ignored since validator cannot fix SQL related problems */ db_model->setInvalidated(error_count > 0); emit s_validationInfoGenerated(val_info); if(val_info.getValidationType()==ValidationInfo::SqlValidationError) emit s_validationFinished(); } void ModelValidationHelper::emitValidationCanceled(void) { db_model->setInvalidated(!export_thread->isRunning()); export_thread->quit(); export_thread->wait(); emit s_validationInfoGenerated(ValidationInfo(trUtf8("Operation canceled by the user."))); emit s_validationCanceled(); } void ModelValidationHelper::emitValidationFinished(void) { export_thread->quit(); /* Indicates the model invalidation only when there are validation warnings (broken refs. or no unique name) sql errors are ignored since validator cannot fix SQL related problems */ db_model->setInvalidated(error_count > 0); emit s_validationFinished(); progress=100; emit s_progressUpdated(progress,QString()); } pgmodeler-0.9.2/libpgmodeler_ui/src/modelvalidationhelper.h000066400000000000000000000111101360462764600241650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelValidationHelper \brief Implements the base operations to validate models */ #ifndef MODEL_VALIDATION_HELPER_H #define MODEL_VALIDATION_HELPER_H #include #include "validationinfo.h" #include "databasemodel.h" #include "connection.h" #include "modelexporthelper.h" class ModelValidationHelper: public QObject { private: Q_OBJECT //! \brief Reference database model DatabaseModel *db_model; //! \brief Connection used to validate model on DBMS Connection *conn; //! \brief Selected PostgreSQL syntax to validate model on DBMS QString pgsql_ver; //! \brief DBMS export helper used to execute SQL code validation ModelExportHelper export_helper; QThread *export_thread; //! \brief Warning and error counters unsigned warn_count, error_count; //! \brief Validation progress int progress; //! \brief Indicates if the validation was canceled by the user bool valid_canceled, //! \brief Indicates if the validation is on fix mode. fix_mode, use_tmp_names; /*! \brief Stores the validation infos generated during validation steps. This vector is read when applying fixes */ vector val_infos; //! \brief Stores the analyzed relationship marked as invalidated vector inv_rels; void generateValidationInfo(unsigned val_type, BaseObject *object, vector refs); public: ModelValidationHelper(void); ~ModelValidationHelper(void); /*! \brief Validates the specified model. If a connection is specifies executes the SQL validation directly on DBMS */ void setValidationParams(DatabaseModel *model, Connection *conn=nullptr, const QString &pgsql_ver=QString(), bool use_tmp_names=false); //! \brief Switch the validator to fix mode void switchToFixMode(bool value); //! \brief Returns if the validator is on fix mode bool isInFixMode(void); //! \brief Returns the error count (only when executing SQL validation) unsigned getErrorCount(void); //! \brief Returns the warning count unsigned getWarningCount(void); //! \brief Try to resolve the conflict specified by validation info void resolveConflict(ValidationInfo &info); bool isValidationCanceled(void); private slots: void redirectExportProgress(int prog, QString msg, ObjectType obj_type, QString cmd, bool is_code_gen); void captureThreadError(Exception e); void emitValidationCanceled(void); void emitValidationFinished(void); public slots: void validateModel(void); void applyFixes(void); void cancelValidation(void); signals: //! \brief This signal is emitted when a validation info is generated void s_validationInfoGenerated(ValidationInfo val_info); //! \brief This signal is emitted when the validation progress changes void s_progressUpdated(int prog, QString msg, ObjectType obj_type=ObjectType::BaseObject, QString cmd=QString(), bool is_code_gen=false); //! \brief This signal is emitted when the object is processed by the validator void s_objectProcessed(QString obj_name, ObjectType obj_type); //! \brief This signal is emitted when the validation was sucessfully finished void s_validationFinished(void); //! \brief This signal is emitted when the validation was canceled by user void s_validationCanceled(void); //! \brief This signal is emitted when the dbms export thread start to run void s_sqlValidationStarted(void); //! \brief This signal is emitted when the validator applied some fix on validation info void s_fixApplied(void); //! \brief This signal is emitted when the validator changes some objects id by swapping or update operations void s_objectIdChanged(BaseObject *object); /*! \brief This signal is emitted when the validator need the validation of relationship. This process must be performed outside the current thread, this explains the usage of this signal */ void s_relsValidationRequested(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelvalidationwidget.cpp000066400000000000000000000552761360462764600245510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "modelvalidationwidget.h" #include "configurationform.h" #include "pgmodeleruins.h" ModelValidationWidget::ModelValidationWidget(QWidget *parent): QWidget(parent) { try { setupUi(this); htmlitem_del=new HtmlItemDelegate(this); output_trw->setItemDelegateForColumn(0, htmlitem_del); version_cmb->addItem(trUtf8("Autodetect")); version_cmb->addItems(PgSqlVersions::AllVersions); options_frm->setVisible(false); curr_step=0; validation_thread=nullptr; validation_helper=nullptr; this->setModel(nullptr); sql_validation_ht=new HintTextWidget(sql_validation_hint, this); sql_validation_ht->setText(sql_validation_chk->statusTip()); use_unique_names_ht=new HintTextWidget(use_unique_names_hint, this); use_unique_names_ht->setText(use_tmp_names_chk->statusTip()); connect(hide_tb, SIGNAL(clicked(void)), this, SLOT(hide(void))); connect(clear_btn, SIGNAL(clicked(void)), this, SLOT(clearOutput(void))); connect(options_btn, SIGNAL(toggled(bool)), options_frm, SLOT(setVisible(bool))); connect(sql_validation_chk, SIGNAL(toggled(bool)), connections_cmb, SLOT(setEnabled(bool))); connect(sql_validation_chk, SIGNAL(toggled(bool)), version_cmb, SLOT(setEnabled(bool))); connect(sql_validation_chk, SIGNAL(toggled(bool)), use_tmp_names_chk, SLOT(setEnabled(bool))); connect(validate_btn, SIGNAL(clicked(void)), this, SLOT(validateModel(void))); connect(fix_btn, SIGNAL(clicked(void)), this, SLOT(applyFixes(void))); connect(cancel_btn, SIGNAL(clicked(void)), this, SLOT(cancelValidation(void))); connect(connections_cmb, SIGNAL(activated(int)), this, SLOT(editConnections())); connect(swap_ids_btn, SIGNAL(clicked(void)), this, SLOT(swapObjectsIds(void))); connect(sql_validation_chk, &QCheckBox::toggled, [&](){ configureValidation(); clearOutput(); }); connect(use_tmp_names_chk, &QCheckBox::toggled, [&](){ configureValidation(); clearOutput(); }); connect(connections_cmb, &QComboBox::currentTextChanged, [&](){ configureValidation(); clearOutput(); }); connect(version_cmb, &QComboBox::currentTextChanged, [&](){ configureValidation(); clearOutput(); }); ConnectionsConfigWidget::fillConnectionsComboBox(connections_cmb, true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } bool ModelValidationWidget::eventFilter(QObject *object, QEvent *event) { QMouseEvent *m_event=dynamic_cast(event); //Executes the search when user press enter/return on the pattern field if(m_event && m_event->buttons() == Qt::RightButton) { QLabel *label = dynamic_cast(object); if(label->hasSelectedText()) { label->setContextMenuPolicy(Qt::DefaultContextMenu); } else { label->setContextMenuPolicy(Qt::NoContextMenu); selectObject(); } } return(QWidget::eventFilter(object, event)); } void ModelValidationWidget::createThread(void) { if(!validation_thread) { validation_thread=new QThread(this); validation_helper=new ModelValidationHelper; validation_helper->moveToThread(validation_thread); connect(validation_thread, &QThread::started, [&](){ output_trw->setUniformRowHeights(true); }); connect(validation_thread, &QThread::finished, [&](){ output_trw->setUniformRowHeights(false); }); connect(validation_thread, SIGNAL(started(void)), validation_helper, SLOT(validateModel(void))); connect(validation_thread, SIGNAL(started(void)), validation_helper, SLOT(applyFixes(void))); connect(validation_thread, SIGNAL(finished(void)), this, SLOT(updateGraphicalObjects(void))); connect(validation_thread, SIGNAL(finished(void)), this, SLOT(destroyThread(void))); connect(validation_helper, SIGNAL(s_validationInfoGenerated(ValidationInfo)), this, SLOT(updateValidation(ValidationInfo)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_progressUpdated(int,QString,ObjectType,QString,bool)), this, SLOT(updateProgress(int,QString,ObjectType,QString,bool)), Qt::BlockingQueuedConnection); connect(validation_helper, SIGNAL(s_objectProcessed(QString,ObjectType)), this, SLOT(updateObjectName(QString,ObjectType)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_validationFinished(void)), this, SLOT(reenableValidation(void)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_validationCanceled(void)), this, SLOT(reenableValidation(void)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_sqlValidationStarted(void)), this, SLOT(handleSQLValidationStarted(void)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_fixApplied(void)), this, SLOT(clearOutput(void)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_fixApplied(void)), prog_info_wgt, SLOT(show(void)), Qt::QueuedConnection); connect(validation_helper, SIGNAL(s_relsValidationRequested(void)), this, SLOT(validateRelationships(void))); connect(validation_helper, &ModelValidationHelper::s_validationCanceled, [&](){ emit s_validationCanceled(); }); connect(validation_helper, &ModelValidationHelper::s_fixApplied, [&](){ emit s_fixApplied(); }); connect(validation_helper, &ModelValidationHelper::s_objectIdChanged, [&](BaseObject *obj) { BaseGraphicObject *graph_obj=dynamic_cast(obj); if(graph_obj) graph_objects.push_back(graph_obj); }); } } void ModelValidationWidget::destroyThread(bool force) { if(validation_thread && (force || validation_helper->getErrorCount()==0)) { validation_thread->wait(); delete(validation_thread); delete(validation_helper); validation_thread=nullptr; validation_helper=nullptr; } } void ModelValidationWidget::hide(void) { QWidget::hide(); emit s_visibilityChanged(false); } void ModelValidationWidget::reenableValidation(void) { if(!validation_helper->isInFixMode()) { validation_thread->quit(); model_wgt->setEnabled(true); validate_btn->setEnabled(true); cancel_btn->setEnabled(false); fix_btn->setEnabled(model_wgt->getDatabaseModel()->isInvalidated()); clear_btn->setEnabled(true); options_btn->setEnabled(true); options_frm->setEnabled(true); ico_lbl->setVisible(false); object_lbl->setVisible(false); swap_ids_btn->setEnabled(true); emit s_validationInProgress(false); } } void ModelValidationWidget::emitValidationInProgress(void) { clearOutput(); emit s_validationInProgress(true); ico_lbl->setVisible(true); object_lbl->setVisible(true); prog_info_wgt->setVisible(true); validate_btn->setEnabled(false); options_btn->setEnabled(false); model_wgt->setEnabled(false); cancel_btn->setEnabled(true); options_frm->setEnabled(false); swap_ids_btn->setEnabled(false); } void ModelValidationWidget::clearOutput(void) { output_trw->clear(); clear_btn->setEnabled(false); prog_info_wgt->setVisible(false); fix_btn->setEnabled(false); validation_prog_pb->setValue(0); warn_lbl->setEnabled(false); error_lbl->setEnabled(false); warn_count_lbl->setText(QString("%1").arg(0)); error_count_lbl->setText(QString("%1").arg(0)); } void ModelValidationWidget::cancelValidation(void) { validation_helper->cancelValidation(); validation_thread->quit(); cancel_btn->setEnabled(false); } void ModelValidationWidget::setModel(ModelWidget *model_wgt) { bool enable=model_wgt!=nullptr; this->model_wgt=model_wgt; output_trw->setEnabled(enable); validate_btn->setEnabled(enable); options_btn->setEnabled(enable); options_frm->setEnabled(enable); fix_btn->setEnabled(false); swap_ids_btn->setEnabled(enable); curr_step=0; clearOutput(); destroyThread(true); } bool ModelValidationWidget::isValidationRunning(void) { return(validation_thread && validation_thread->isRunning()); } void ModelValidationWidget::updateValidation(ValidationInfo val_info) { if(validation_thread && val_info.getValidationType()!=ValidationInfo::ValidationAborted && !validation_thread->isRunning() && validation_helper->isValidationCanceled()) return; QTreeWidgetItem *item=new QTreeWidgetItem, *item1=nullptr, *item2=nullptr; QLabel *label=new QLabel, *label1=nullptr, *label2=nullptr; vector refs; BaseTable *table=nullptr; TableObject *tab_obj=nullptr; QString ref_name; BaseObject *ref_obj=nullptr; label->installEventFilter(this); label->setTextInteractionFlags(Qt::TextSelectableByMouse); if(val_info.getValidationType()==ValidationInfo::BrokenReference) label->setText(trUtf8("The object %1 (%2) [id: %3] is being referenced by %4 object(s) before its creation.") .arg(val_info.getObject()->getName(true).remove('"')) .arg(val_info.getObject()->getTypeName()) .arg(val_info.getObject()->getObjectId()) .arg(val_info.getReferences().size())); else if(val_info.getValidationType()==ValidationInfo::SpObjBrokenReference) { QString str_aux; if(TableObject::isTableObject(val_info.getObject()->getObjectType())) { TableObject *tab_obj=dynamic_cast(val_info.getObject()); str_aux=QString(" owned by table %1 ").arg(tab_obj->getParentTable()->getName(true).remove('"')); } label->setText(trUtf8("The object %1 (%2) [id: %3]%4 is referencing columns created by %5 relationship(s) but is created before them.") .arg(val_info.getObject()->getName(true).remove('"')) .arg(val_info.getObject()->getTypeName()) .arg(val_info.getObject()->getObjectId()) .arg(str_aux) .arg(val_info.getReferences().size())); } else if(val_info.getValidationType()==ValidationInfo::NoUniqueName) { tab_obj=dynamic_cast(val_info.getObject()); if(tab_obj) { table=tab_obj->getParentTable(); ref_name=table->getName(true).remove('"') + QString(".") + val_info.getObject()->getName(true).remove('"'); } else ref_name=val_info.getObject()->getName(true).remove('"'); label->setText(trUtf8("The object %1 (%2) has a name that conflicts with %3 object name(s).") .arg(ref_name) .arg(val_info.getObject()->getTypeName()) .arg(val_info.getReferences().size())); } else if(val_info.getValidationType()==ValidationInfo::BrokenRelConfig) label->setText(trUtf8("The relationship %1 [id: %2] is in a permanent invalidation state and needs to be relocated.") .arg(val_info.getObject()->getName(true).remove('"')) .arg(val_info.getObject()->getObjectId())); else if(val_info.getValidationType()==ValidationInfo::SqlValidationError) label->setText(trUtf8("SQL validation failed due to the error(s) below. NOTE: Errors during SQL validation don't invalidate the model but may affect operations like export and diff.")); else if(val_info.getValidationType() == ValidationInfo::MissingExtension) { Column *col = dynamic_cast(val_info.getObject()); label->setText(trUtf8("The column %1 on %2 (%3) is referencing the geospatial data type %4 but the postgis extension is not present in the model!") .arg(col->getName()) .arg(col->getParentTable()->getSignature(true)) .arg(BaseObject::getTypeName(ObjectType::Table)) .arg(~col->getType())); } else label->setText(val_info.getErrors().at(0)); /* Store the reference of the object in order to allow opening the editing form when the user clicks the item on the output * So the needed fixes can be done manually */ item->setData(1, Qt::UserRole, QVariant::fromValue(reinterpret_cast(val_info.getObject()))); if(val_info.getValidationType()==ValidationInfo::SqlValidationError || val_info.getValidationType()==ValidationInfo::ValidationAborted) { QStringList errors=val_info.getErrors(); item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); validation_prog_pb->setValue(validation_prog_pb->maximum()); reenableValidation(); if(val_info.getValidationType()==ValidationInfo::SqlValidationError) { //Adding all the sql errors into the output pane while(!errors.isEmpty()) { item1=new QTreeWidgetItem(item); label1=new QLabel; label1->setTextInteractionFlags(Qt::TextSelectableByMouse); label1->setText(errors.back()); label1->setTextInteractionFlags(Qt::TextSelectableByMouse); output_trw->setItemWidget(item1, 0, label1); errors.pop_back(); } } } else { item->setIcon(0, QPixmap(PgModelerUiNs::getIconPath("msgbox_erro"))); if(val_info.getValidationType()==ValidationInfo::BrokenRelConfig) { PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("HINT: try to swap the relationship by another ones that somehow are linked to it through generated columns or constraints to solve this issue. Note that other objects may be lost in the swap process."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), item); } else if(val_info.getValidationType()==ValidationInfo::MissingExtension) { PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("HINT: Create the extension in the model or let it be created by applying the needed fixes."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), item); } else { //Listing the referrer object on output pane refs=val_info.getReferences(); while(!refs.empty()) { ref_obj = refs.back(); item1=new QTreeWidgetItem(item); label1=new QLabel; label1->setTextInteractionFlags(Qt::TextSelectableByMouse); label1->installEventFilter(this); item1->setIcon(0, QPixmap(PgModelerUiNs::getIconPath(ref_obj->getSchemaName()))); /* Store the reference of the referrer object in order to allow opening the editing form when the user clicks the item on the output * So the needed fixes can be done manually */ item1->setData(1, Qt::UserRole, QVariant::fromValue(reinterpret_cast(ref_obj))); tab_obj=dynamic_cast(ref_obj); ref_name=ref_obj->getName(true); if(tab_obj) ref_name=dynamic_cast(ref_obj)->getParentTable()->getName(true) + QString(".") + ref_name; if(val_info.getValidationType()==ValidationInfo::NoUniqueName) { //If the referrer object is a table object, concatenates the parent table name if(tab_obj) { if(tab_obj->isAddedByRelationship()) { QPalette pal; item2=new QTreeWidgetItem(item1); label2=new QLabel; label2->setTextInteractionFlags(Qt::TextSelectableByMouse); pal.setColor(QPalette::Text, QColor(255,0,0)); label2->setPalette(pal); label2->setText(trUtf8("The above object was created by a relationship. Change the name pattern on it's generator relationship. Fix will not be applied!")); output_trw->setItemWidget(item2, 0, label2); item1->setExpanded(true); } } label1->setText(trUtf8("Conflicting object: %1 (%2).") .arg(ref_name.remove('"')) .arg(ref_obj->getTypeName())); } else { if(val_info.getValidationType()==ValidationInfo::SpObjBrokenReference) label1->setText(trUtf8("Relationship: %1 [id: %2].") .arg(ref_name.remove('"')) .arg(ref_obj->getObjectId())); else { label1->setText(trUtf8("Referrer object: %1 (%2) [id: %3].") .arg(ref_name.remove('"')) .arg(ref_obj->getTypeName()) .arg(ref_obj->getObjectId())); } } output_trw->setItemWidget(item1, 0, label1); refs.pop_back(); } } } output_trw->addTopLevelItem(item); output_trw->setItemWidget(item, 0, label); item->setExpanded(false); //Stores the validatin on the current tree item item->setData(0, Qt::UserRole, QVariant::fromValue(val_info)); warn_lbl->setEnabled(validation_helper->getWarningCount() > 0); error_lbl->setEnabled(validation_helper->getErrorCount() > 0); warn_count_lbl->setText(QString("%1").arg(validation_helper->getWarningCount())); error_count_lbl->setText(QString("%1").arg(validation_helper->getErrorCount())); output_trw->setItemHidden(item, false); output_trw->scrollToBottom(); if(val_info.getValidationType()==ValidationInfo::SqlValidationError) emit s_validationFinished(validation_helper->getErrorCount() != 0); } void ModelValidationWidget::validateModel(void) { createThread(); configureValidation(); emitValidationInProgress(); validation_helper->switchToFixMode(false); validation_thread->start(); } void ModelValidationWidget::applyFixes(void) { emitValidationInProgress(); validation_helper->switchToFixMode(true); disconnect(validation_thread, SIGNAL(started(void)), validation_helper, SLOT(validateModel(void))); validation_thread->start(); connect(validation_thread, SIGNAL(started(void)), validation_helper, SLOT(validateModel(void))); } void ModelValidationWidget::updateProgress(int prog, QString msg, ObjectType obj_type, QString cmd, bool is_code_gen) { if(validation_thread && (!validation_thread->isRunning() || validation_helper->isValidationCanceled())) return; QTreeWidgetItem *item=nullptr; validation_prog_pb->setValue(prog); if(prog >= 100 && validation_helper->getErrorCount()==0 && validation_helper->getWarningCount()==0) { error_lbl->setEnabled(false); error_count_lbl->setText(QString::number(0)); fix_btn->setEnabled(false); if(sql_validation_chk->isChecked() && connections_cmb->currentIndex() <= 0) { warn_lbl->setEnabled(true); warn_count_lbl->setText(QString::number(1)); PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("SQL validation not executed! No connection defined."), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); } else { warn_lbl->setEnabled(false); warn_count_lbl->setText(QString::number(0)); } PgModelerUiNs::createOutputTreeItem(output_trw, trUtf8("Database model successfully validated."), QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); emit s_validationFinished(validation_helper->getErrorCount() != 0); } else if(!msg.isEmpty()) { QPixmap ico; msg=PgModelerUiNs::formatMessage(msg); if(obj_type!=ObjectType::BaseObject) ico=QPixmap(PgModelerUiNs::getIconPath(obj_type)); else if(!cmd.isEmpty()) ico=QPixmap(PgModelerUiNs::getIconPath("sqlcmd")); else ico=QPixmap(PgModelerUiNs::getIconPath("msgbox_info")); if(is_code_gen) { ico_lbl->setPixmap(ico); object_lbl->setText(msg); } else { ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("codigosql"))); object_lbl->setText(trUtf8("Running SQL commands on server...")); item=PgModelerUiNs::createOutputTreeItem(output_trw, msg, ico, nullptr, false); if(!cmd.isEmpty()) PgModelerUiNs::createOutputTreeItem(output_trw, cmd, QPixmap(), item, false); } } } void ModelValidationWidget::updateObjectName(QString obj_name, ObjectType obj_type) { object_lbl->setText(trUtf8("Processing object: %1").arg(PgModelerUiNs::formatMessage(obj_name))); ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(obj_type))); } void ModelValidationWidget::configureValidation(void) { if(model_wgt && validation_helper) { Connection *conn=nullptr; QString ver; //Get the connection only the checkbox is checked. if(sql_validation_chk->isChecked() && connections_cmb->currentIndex() > 0 && connections_cmb->currentIndex()!=connections_cmb->count()-1) { conn=reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value()); ver=(version_cmb->currentIndex() > 0 ? version_cmb->currentText() : QString()); } validation_helper->setValidationParams(model_wgt->getDatabaseModel(), conn, ver, use_tmp_names_chk->isChecked()); } } void ModelValidationWidget::resizeEvent(QResizeEvent *event) { Qt::ToolButtonStyle style=Qt::ToolButtonTextBesideIcon; if(event->size().width() < this->baseSize().width()) style=Qt::ToolButtonIconOnly; if(validate_btn->toolButtonStyle()!=style) { validate_btn->setToolButtonStyle(style); fix_btn->setToolButtonStyle(style); clear_btn->setToolButtonStyle(style); cancel_btn->setToolButtonStyle(style); options_btn->setToolButtonStyle(style); swap_ids_btn->setToolButtonStyle(style); } } void ModelValidationWidget::validateRelationships(void) { try { model_wgt->getDatabaseModel()->validateRelationships(); model_wgt->setModified(true); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } void ModelValidationWidget::updateGraphicalObjects(void) { if(!graph_objects.empty()) { vector::iterator end; std::sort(graph_objects.begin(), graph_objects.end()); end=std::unique(graph_objects.begin(), graph_objects.end()); graph_objects.erase(end, graph_objects.end()); while(!graph_objects.empty()) { graph_objects.back()->setModified(true); graph_objects.pop_back(); } emit s_graphicalObjectsUpdated(); } } void ModelValidationWidget::editConnections(void) { if(connections_cmb->currentIndex()==connections_cmb->count()-1) { ConnectionsConfigWidget::openConnectionsConfiguration(connections_cmb, true); emit s_connectionsUpdateRequest(); } } void ModelValidationWidget::handleSQLValidationStarted(void) { options_btn->setEnabled(false); clear_btn->setEnabled(false); options_frm->setEnabled(false); } void ModelValidationWidget::swapObjectsIds(void) { BaseForm parent_form(this); SwapObjectsIdsWidget *swap_ids_wgt=new SwapObjectsIdsWidget; swap_ids_wgt->setModel(model_wgt->getDatabaseModel()); parent_form.setMainWidget(swap_ids_wgt); GeneralConfigWidget::restoreWidgetGeometry(&parent_form, swap_ids_wgt->metaObject()->className()); parent_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&parent_form, swap_ids_wgt->metaObject()->className()); } void ModelValidationWidget::selectObject(void) { QTreeWidgetItem *item = output_trw->currentItem(); if(item && !validation_thread->isRunning()) { BaseObject *selected_obj=reinterpret_cast(item->data(1, Qt::UserRole).value()); if(selected_obj && QApplication::mouseButtons() == Qt::RightButton) { model_wgt->configureObjectMenu(selected_obj); model_wgt->showObjectMenu(); } } } pgmodeler-0.9.2/libpgmodeler_ui/src/modelvalidationwidget.h000066400000000000000000000072601360462764600242040ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelValidationWidget \brief Implements the operations to display to the user the validation operation performed by ValidationHelper */ #ifndef MODEL_VALIDATION_WIDGET_H #define MODEL_VALIDATION_WIDGET_H #include "ui_modelvalidationwidget.h" #include "connection.h" #include "modelwidget.h" #include "modelvalidationhelper.h" #include "swapobjectsidswidget.h" #include "htmlitemdelegate.h" #include "hinttextwidget.h" /* Declaring the ValidationInfo class as a Qt metatype in order to permit that instances of the class be used as data of QVariant and QMetaType */ #include Q_DECLARE_METATYPE(ValidationInfo) class ModelValidationWidget: public QWidget, public Ui::ModelValidationWidget { private: Q_OBJECT HintTextWidget *sql_validation_ht, *use_unique_names_ht; //! \brief Custom delegate used to paint html texts in output tree HtmlItemDelegate *htmlitem_del; //! \brief Reference model widget ModelWidget *model_wgt; //! \brief Object that handles the model validation steps ModelValidationHelper *validation_helper; //! \brief Current fix step int curr_step; //! \brief Thread used to control the validation helper QThread *validation_thread; /*! \brief Stores the graphical objects that have their ids changed so that in the end of the validation they can be updated to reflect the new id in the tooltips and forms */ vector graph_objects; void emitValidationInProgress(void); //! \brief Creates a new validation thread void createThread(void); void configureValidation(void); void selectObject(void); protected: void resizeEvent(QResizeEvent *event); bool eventFilter(QObject *object, QEvent *event); public: ModelValidationWidget(QWidget * parent = nullptr); //! \brief Sets the database model to work on void setModel(ModelWidget *model_wgt); //! \brief Returns if there is a validation in progress bool isValidationRunning(void); private slots: void applyFixes(void); void updateValidation(ValidationInfo val_info); void updateProgress(int prog, QString msg, ObjectType obj_type, QString cmd, bool is_code_gen); void updateObjectName(QString obj_name, ObjectType obj_type); void reenableValidation(void); void cancelValidation(void); void validateRelationships(void); void destroyThread(bool force=false); void updateGraphicalObjects(void); void editConnections(void); void handleSQLValidationStarted(void); void swapObjectsIds(void); public slots: void hide(void); void clearOutput(void); void validateModel(void); signals: void s_visibilityChanged(bool); void s_validationInProgress(bool); void s_validationFinished(bool); void s_validationCanceled(void); void s_fixApplied(void); void s_graphicalObjectsUpdated(void); /*! \brief This signal is emitted whenever the user changes the connections settings within this widget without use the main configurations dialog */ void s_connectionsUpdateRequest(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/modelwidget.cpp000066400000000000000000005276321360462764600224760ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "baseform.h" #include "modelwidget.h" #include "sourcecodewidget.h" #include "databasewidget.h" #include "schemawidget.h" #include "rolewidget.h" #include "tablespacewidget.h" #include "languagewidget.h" #include "functionwidget.h" #include "castwidget.h" #include "conversionwidget.h" #include "domainwidget.h" #include "aggregatewidget.h" #include "sequencewidget.h" #include "operatorwidget.h" #include "operatorfamilywidget.h" #include "operatorclasswidget.h" #include "typewidget.h" #include "viewwidget.h" #include "textboxwidget.h" #include "columnwidget.h" #include "constraintwidget.h" #include "rulewidget.h" #include "triggerwidget.h" #include "indexwidget.h" #include "relationshipwidget.h" #include "tablewidget.h" #include "taskprogresswidget.h" #include "objectdepsrefswidget.h" #include "objectrenamewidget.h" #include "permissionwidget.h" #include "collationwidget.h" #include "extensionwidget.h" #include "customsqlwidget.h" #include "tagwidget.h" #include "eventtriggerwidget.h" #include "pgmodeleruins.h" #include "swapobjectsidswidget.h" #include "genericsqlwidget.h" #include "policywidget.h" #include "tabledatawidget.h" #include "generalconfigwidget.h" #include "foreigndatawrapperwidget.h" #include "foreignserverwidget.h" #include "usermappingwidget.h" vector ModelWidget::copied_objects; vector ModelWidget::cutted_objects; bool ModelWidget::cut_operation=false; bool ModelWidget::save_restore_pos=true; bool ModelWidget::disable_render_smooth=false; bool ModelWidget::simple_obj_creation=true; ModelWidget *ModelWidget::src_model=nullptr; double ModelWidget::min_object_opacity=0.10; constexpr unsigned ModelWidget::BreakVertNinetyDegrees; constexpr unsigned ModelWidget::BreakHorizNinetyDegrees; constexpr unsigned ModelWidget::BreakVert2NinetyDegrees; constexpr unsigned ModelWidget::BreakHoriz2NinetyDegrees; ModelWidget::ModelWidget(QWidget *parent) : QWidget(parent) { QFont font; QLabel *label=nullptr; QGridLayout *grid=nullptr; QAction *action=nullptr; QString str_ico; QStringList rel_types_cod={QString("11"), QString("1n"), QString("nn"), QString("dep"), QString("gen"), QString("part") }; unsigned i, rel_types_id[]={ BaseRelationship::Relationship11, BaseRelationship::Relationship1n, BaseRelationship::RelationshipNn, BaseRelationship::RelationshipDep, BaseRelationship::RelationshipGen, BaseRelationship::RelationshipPart}; vector types_vect = BaseObject::getObjectTypes(true, { ObjectType::Database, ObjectType::Permission, ObjectType::BaseRelationship}); current_zoom=1; modified=panning_mode=false; new_obj_type=ObjectType::BaseObject; //Generating a temporary file name for the model QTemporaryFile tmp_file; //Configuring the template mask which includes the full path to temporary dir tmp_file.setFileTemplate(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + QString("model_XXXXXX") + QString(".dbm")); tmp_file.open(); tmp_filename=tmp_file.fileName(); tmp_file.close(); protected_model_frm=new QFrame(this); protected_model_frm->setGeometry(QRect(20, 10, 500, 25)); protected_model_frm->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); protected_model_frm->setMinimumSize(QSize(0, 25)); protected_model_frm->setFrameShape(QFrame::StyledPanel); protected_model_frm->setFrameShadow(QFrame::Raised); protected_model_frm->setVisible(false); label=new QLabel(protected_model_frm); label->setMinimumSize(QSize(20, 20)); label->setMaximumSize(QSize(20, 20)); label->setScaledContents(true); label->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); grid=new QGridLayout; grid->addWidget(label, 0, 0, 1, 1); label=new QLabel(protected_model_frm); font.setBold(false); font.setItalic(false); font.setUnderline(false); font.setWeight(50); font.setStrikeOut(false); font.setKerning(true); label->setFont(font); label->setWordWrap(true); label->setText(trUtf8("ATTENTION: The database model is protected! Operations that could modify it are disabled!")); PgModelerUiNs::configureWidgetFont(label, PgModelerUiNs::MediumFontFactor); grid->addWidget(label, 0, 1, 1, 1); protected_model_frm->setLayout(grid); protected_model_frm->adjustSize(); db_model=new DatabaseModel(this); xmlparser=db_model->getXMLParser(); op_list=new OperationList(db_model); scene=new ObjectsScene; scene->setSceneRect(QRectF(0,0,2000,2000)); scene->installEventFilter(this); viewport=new QGraphicsView(scene); updateRenderHints(); viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //Force the scene to be drawn from the left to right and from top to bottom viewport->setAlignment(Qt::AlignLeft | Qt::AlignTop); viewport->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); viewport->setCacheMode(QGraphicsView::CacheBackground); viewport->centerOn(0,0); viewport->setMouseTracking(true); grid=new QGridLayout; grid->addWidget(protected_model_frm, 0,0,1,1); grid->addWidget(viewport, 1,0,1,1); this->setLayout(grid); magnifier_frm = new QFrame(this); magnifier_frm->setVisible(false); magnifier_frm->installEventFilter(this); magnifier_frm->setMouseTracking(true); magnifier_frm->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); magnifier_frm->setGeometry(0,0, 500 * BaseObjectView::getFontFactor() * BaseObjectView::getScreenDpiFactor(), 500 * BaseObjectView::getFontFactor() * BaseObjectView::getScreenDpiFactor()); magnifier_frm->setCursor(Qt::CrossCursor); QColor c1, c2; BaseObjectView::getFillStyle(Attributes::ObjSelection, c1, c2); c1.setAlpha(50); magnifier_frm->setStyleSheet(QString("background-color: %1; border: 1px solid %2;") .arg(c1.name(QColor::HexArgb)) .arg(BaseObjectView::getBorderStyle(Attributes::ObjSelection).color().name(QColor::HexArgb))); magnifier_area_lbl = new QLabel(this); magnifier_area_lbl->raise(); magnifier_area_lbl->setAutoFillBackground(false); magnifier_area_lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); magnifier_area_lbl->setStyleSheet(QString("background-color: #C8f0f0f0;\ border: 1px solid #C8808080;")); magnifier_area_lbl->setVisible(false); magnifier_area_lbl->setGeometry(magnifier_frm->geometry()); magnifier_area_lbl->setCursor(Qt::BlankCursor); magnifier_area_lbl->installEventFilter(this); magnifier_area_lbl->setMouseTracking(true); zoom_info_lbl=new QLabel(this); zoom_info_lbl->raise(); zoom_info_lbl->setAutoFillBackground(false); zoom_info_lbl->setText(QString("Zoom: 100%")); zoom_info_lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); zoom_info_lbl->setStyleSheet(QString("color: #C8000000; \ background-color: #C8FFFF80;\ border: 1px solid #C8B16351;")); font=zoom_info_lbl->font(); font.setBold(true); font.setPointSizeF(12); zoom_info_lbl->setFont(font); zoom_info_lbl->adjustSize(); zoom_info_lbl->setVisible(false); zoom_info_timer.setInterval(3000); action_edit_data=new QAction(QIcon(PgModelerUiNs::getIconPath("editdata")), trUtf8("Edit data"), this); action_source_code=new QAction(QIcon(PgModelerUiNs::getIconPath("codigosql")), trUtf8("Source"), this); action_source_code->setShortcut(QKeySequence(trUtf8("Alt+S"))); action_source_code->setToolTip(trUtf8("Show object source code")); action_edit=new QAction(QIcon(PgModelerUiNs::getIconPath("editar")), trUtf8("Properties"), this); action_edit->setShortcut(QKeySequence(trUtf8("Space"))); action_edit->setToolTip(trUtf8("Edit the object properties")); action_protect=new QAction(QIcon(PgModelerUiNs::getIconPath("bloqobjeto")), trUtf8("Protect"), this); action_unprotect=new QAction(QIcon(PgModelerUiNs::getIconPath("desbloqobjeto")), trUtf8("Unprotect"), this); action_protect->setToolTip(trUtf8("Protects object(s) from modifications")); action_remove=new QAction(QIcon(PgModelerUiNs::getIconPath("excluir")), trUtf8("Delete"), this); action_remove->setShortcut(QKeySequence(trUtf8("Del"))); action_remove->setMenuRole(QAction::NoRole); action_cascade_del=new QAction(QIcon(PgModelerUiNs::getIconPath("delcascade")), trUtf8("Del. cascade"), this); action_cascade_del->setShortcut(QKeySequence(trUtf8("Shift+Del"))); action_cascade_del->setMenuRole(QAction::NoRole); action_select_all=new QAction(QIcon(PgModelerUiNs::getIconPath("seltodos")), trUtf8("Select all"), this); action_select_all->setToolTip(trUtf8("Selects all the graphical objects in the model")); action_select_all->setMenu(&select_all_menu); action_convert_relnn=new QAction(QIcon(PgModelerUiNs::getIconPath("convrelnn")), trUtf8("Convert"), this); action_copy=new QAction(QIcon(PgModelerUiNs::getIconPath("copiar")), trUtf8("Copy"), this); action_copy->setShortcut(QKeySequence(trUtf8("Ctrl+C"))); action_copy->setMenuRole(QAction::NoRole); action_paste=new QAction(QIcon(PgModelerUiNs::getIconPath("colar")), trUtf8("Paste"), this); action_paste->setShortcut(QKeySequence(trUtf8("Ctrl+V"))); action_paste->setMenuRole(QAction::NoRole); action_cut=new QAction(QIcon(PgModelerUiNs::getIconPath("recortar")), trUtf8("Cut"), this); action_cut->setShortcut(QKeySequence(trUtf8("Ctrl+X"))); action_cut->setMenuRole(QAction::NoRole); action_deps_refs=new QAction(QIcon(PgModelerUiNs::getIconPath("depsrefs")), trUtf8("Deps && Referrers"), this); action_new_object=new QAction(QIcon(PgModelerUiNs::getIconPath("novoobjeto")), trUtf8("New"), this); action_new_object->setToolTip(trUtf8("Add a new object in the model")); action_quick_actions=new QAction(QIcon(PgModelerUiNs::getIconPath("quickactions")), trUtf8("Quick"), this); action_quick_actions->setToolTip(trUtf8("Quick action for the selected object")); action_quick_actions->setMenu(&quick_actions_menu); action_rename=new QAction(QIcon(PgModelerUiNs::getIconPath("rename")), trUtf8("Rename"), this); action_rename->setShortcut(QKeySequence(trUtf8("F2"))); action_rename->setToolTip(trUtf8("Quick rename the object")); action_moveto_schema=new QAction(QIcon(PgModelerUiNs::getIconPath("movetoschema")), trUtf8("Move to schema"), this); action_moveto_schema->setMenu(&schemas_menu); action_moveto_layer=new QAction(QIcon(PgModelerUiNs::getIconPath("movetolayer")), trUtf8("Move to layer"), this); action_moveto_layer->setMenu(&layers_menu); action_set_tag=new QAction(QIcon(PgModelerUiNs::getIconPath("tag")), trUtf8("Set tag"), this); action_set_tag->setMenu(&tags_menu); action_edit_perms=new QAction(QIcon(PgModelerUiNs::getIconPath("permission")), trUtf8("Edit permissions"), this); action_edit_perms->setShortcut(QKeySequence(trUtf8("Ctrl+E"))); action_change_owner=new QAction(QIcon(PgModelerUiNs::getIconPath("changeowner")), trUtf8("Change owner"), this); action_change_owner->setMenu(&owners_menu); action_sel_sch_children=new QAction(QIcon(PgModelerUiNs::getIconPath("seltodos")), trUtf8("Select children"), this); action_sel_tagged_tabs=new QAction(QIcon(PgModelerUiNs::getIconPath("seltodos")), trUtf8("Select tagged"), this); action_select_object=new QAction(QIcon(PgModelerUiNs::getIconPath("movimentado")), trUtf8("Select"), this); action_parent_rel=new QAction(QIcon(PgModelerUiNs::getIconPath("relationship")), trUtf8("Open relationship"), this); action_append_sql=new QAction(QIcon(PgModelerUiNs::getIconPath("sqlappend")), trUtf8("Custom SQL"), this); action_append_sql->setShortcut(QKeySequence(trUtf8("Alt+Q"))); action_create_seq_col=new QAction(QIcon(PgModelerUiNs::getIconPath("sequence")), trUtf8("Convert to sequence"), this); action_conv_int_serial=new QAction(QIcon(PgModelerUiNs::getIconPath("sequence")), trUtf8("Convert to serial"), this); action_break_rel_line=new QAction(QIcon(PgModelerUiNs::getIconPath("breakrelline")), trUtf8("Break line"), this); action_remove_rel_points=new QAction(QIcon(PgModelerUiNs::getIconPath("removepoints")), trUtf8("Remove points"), this); action_enable_sql=new QAction(QIcon(PgModelerUiNs::getIconPath("codigosql")), trUtf8("Enable SQL"), this); action_disable_sql=new QAction(QIcon(PgModelerUiNs::getIconPath("disablesql")), trUtf8("Disable SQL"), this); action_duplicate=new QAction(QIcon(PgModelerUiNs::getIconPath("duplicate")), trUtf8("Duplicate"), this); action_duplicate->setShortcut(QKeySequence(trUtf8("Ctrl+D"))); action_duplicate->setMenuRole(QAction::NoRole); action_pagination=new QAction(QIcon(PgModelerUiNs::getIconPath("pagination")), trUtf8("Pagination"), this); action_pagination->setMenu(&pagination_menu); action = pagination_menu.addAction(trUtf8("Enable")); action->setData(true); connect(action, SIGNAL(triggered(bool)), this, SLOT(togglePagination())); action = pagination_menu.addAction(trUtf8("Disable")); action->setData(false); connect(action, SIGNAL(triggered(bool)), this, SLOT(togglePagination())); action_collapse_mode=new QAction(QIcon(PgModelerUiNs::getIconPath("collapse")), trUtf8("Collapse"), this); action_no_collapse_attribs=new QAction(trUtf8("Not collapsed"), this); action_no_collapse_attribs->setData(enum_cast(CollapseMode::NotCollapsed)); action_collapse_ext_attribs=new QAction(trUtf8("Extended attributes"), this); action_collapse_ext_attribs->setData(enum_cast(CollapseMode::ExtAttribsCollapsed)); action_collpase_all_attribs=new QAction(trUtf8("All attributes"), this); action_collpase_all_attribs->setData(enum_cast(CollapseMode::AllAttribsCollapsed)); action_jump_to_table=new QAction(QIcon(PgModelerUiNs::getIconPath("jumptotable")), trUtf8("Jump to table"), this); action_jump_to_table->setMenu(&jump_to_tab_menu); toggle_attrs_menu.addAction(action_no_collapse_attribs); toggle_attrs_menu.addAction(action_collapse_ext_attribs); toggle_attrs_menu.addAction(action_collpase_all_attribs); action_collapse_mode->setMenu(&toggle_attrs_menu); action_schemas_rects=new QAction(QIcon(PgModelerUiNs::getIconPath("schemarect")), trUtf8("Schemas rectangles"), this); action_show_schemas_rects=new QAction(trUtf8("Show"), this); action_hide_schemas_rects=new QAction(trUtf8("Hide"), this); toggle_sch_rects_menu.addAction(action_show_schemas_rects); toggle_sch_rects_menu.addAction(action_hide_schemas_rects); action_schemas_rects->setMenu(&toggle_sch_rects_menu); action_fade=new QAction(QIcon(PgModelerUiNs::getIconPath("fade")), trUtf8("Fade in/out"), this); action_fade_in=new QAction(QIcon(PgModelerUiNs::getIconPath("fadein")), trUtf8("Fade in"), this); action_fade_out=new QAction(QIcon(PgModelerUiNs::getIconPath("fadeout")), trUtf8("Fade out"), this); action_fade_rels_in=new QAction(QIcon(PgModelerUiNs::getIconPath("fadein")), trUtf8("Fade in"), this); action_fade_rels_out=new QAction(QIcon(PgModelerUiNs::getIconPath("fadeout")), trUtf8("Fade out"), this); fade_rels_menu.addAction(action_fade_rels_in); fade_rels_menu.addAction(action_fade_rels_out); action_fade_rels=new QAction(QIcon(PgModelerUiNs::getIconPath("relationship_grp")), trUtf8("Relationships"), this); action_fade_rels->setMenu(&fade_rels_menu); action_fade->setMenu(&fade_menu); action_fade_in->setMenu(&fade_in_menu); action_fade_out->setMenu(&fade_out_menu); action_edit_creation_order=new QAction(QIcon(PgModelerUiNs::getIconPath("swapobjs")), trUtf8("Swap ids"), this); action_edit_creation_order->setToolTip(trUtf8("Edit the objects creation order by swapping their ids")); connect(action_edit_creation_order, SIGNAL(triggered(bool)), this, SLOT(swapObjectsIds())); action=new QAction(QIcon(PgModelerUiNs::getIconPath("breakline_90dv")), trUtf8("90° (vertical)"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(breakRelationshipLine(void))); action->setData(QVariant::fromValue(BreakVertNinetyDegrees)); break_rel_menu.addAction(action); action=new QAction(QIcon(PgModelerUiNs::getIconPath("breakline_90dh")), trUtf8("90° (horizontal)"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(breakRelationshipLine(void))); action->setData(QVariant::fromValue(BreakHorizNinetyDegrees)); break_rel_menu.addAction(action); action=new QAction(QIcon(PgModelerUiNs::getIconPath("breakline_290dv")), trUtf8("90° + 90° (vertical)"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(breakRelationshipLine(void))); action->setData(QVariant::fromValue(BreakVert2NinetyDegrees)); break_rel_menu.addAction(action); action=new QAction(QIcon(PgModelerUiNs::getIconPath("breakline_290dh")), trUtf8("90° + 90° (horizontal)"), this); connect(action, SIGNAL(triggered(bool)), this, SLOT(breakRelationshipLine(void))); action->setData(QVariant::fromValue(BreakHoriz2NinetyDegrees)); break_rel_menu.addAction(action); action_break_rel_line->setMenu(&break_rel_menu); //Alocatting the object creation actions for(auto &type : types_vect) { actions_new_objects[type]=new QAction(QIcon(PgModelerUiNs::getIconPath(type)), BaseObject::getTypeName(type), this); actions_new_objects[type]->setData(QVariant(enum_cast(type))); connect(actions_new_objects[type], SIGNAL(triggered(bool)), this, SLOT(addNewObject(void))); } // Configuring the submenu of database level objects action_database_category = new QAction(QIcon(PgModelerUiNs::getIconPath(ObjectType::Database)), trUtf8("Database object"), this); action_database_category->setMenu(&database_category_menu); types_vect = BaseObject::getChildObjectTypes(ObjectType::Database); for(auto &type : types_vect) database_category_menu.addAction(actions_new_objects[type]); // Configuring the submenu of schema level objects action_schema_category = new QAction(QIcon(PgModelerUiNs::getIconPath(ObjectType::Schema)), trUtf8("Schema object"), this); action_schema_category->setMenu(&schema_category_menu); types_vect = BaseObject::getChildObjectTypes(ObjectType::Schema); for(auto &type : types_vect) schema_category_menu.addAction(actions_new_objects[type]); //Creating the relationship submenu rels_menu=new QMenu(this); actions_new_objects[ObjectType::Relationship]->setMenu(rels_menu); for(int i=0; i < rel_types_cod.size(); i++) { str_ico=BaseObject::getSchemaName(ObjectType::Relationship) + rel_types_cod[i]; action=new QAction(QIcon(PgModelerUiNs::getIconPath(str_ico)), BaseRelationship::getRelationshipTypeName(rel_types_id[i], false), this); //Storing a unique identifier for the relationship type action->setData(QVariant(enum_cast(ObjectType::Relationship) + rel_types_id[i])); connect(action, SIGNAL(triggered(bool)), this, SLOT(addNewObject(void))); rels_menu->addAction(action); } new_obj_overlay_wgt=new NewObjectOverlayWidget(this); new_obj_overlay_wgt->setObjectName(QString("new_obj_overlay_wgt")); new_obj_overlay_wgt->setVisible(false); vector graph_types = { ObjectType::BaseObject, ObjectType::Schema, ObjectType::Table, ObjectType::ForeignTable, ObjectType::View, ObjectType::Relationship, ObjectType::Textbox }; QStringList labels = { trUtf8("All objects"), trUtf8("Schemas"), trUtf8("Tables"), trUtf8("Foreign Tables"), trUtf8("Views"), trUtf8("Relationships"), trUtf8("Textboxes") }; i=0; for(auto &obj_type : graph_types) { if(obj_type == ObjectType::BaseObject) { action=new QAction(labels[i++], this); action->setShortcut(QKeySequence(trUtf8("Ctrl+A"))); select_all_menu.addAction(action); select_all_menu.addSeparator(); } else { action=new QAction(QIcon(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(obj_type) + QString("_grp"))), labels[i++], this); select_all_menu.addAction(action); } action->setData(QVariant(enum_cast(obj_type))); connect(action, SIGNAL(triggered(bool)), this, SLOT(selectAllObjects())); } connect(action_edit_data, SIGNAL(triggered(bool)), this, SLOT(editTableData())); connect(&zoom_info_timer, SIGNAL(timeout()), zoom_info_lbl, SLOT(hide())); connect(action_source_code, SIGNAL(triggered(bool)), this, SLOT(showSourceCode(void))); connect(action_edit, SIGNAL(triggered(bool)),this,SLOT(editObject(void))); connect(action_protect, SIGNAL(triggered(bool)),this,SLOT(protectObject(void))); connect(action_unprotect, SIGNAL(triggered(bool)),this,SLOT(protectObject(void))); connect(action_select_all, SIGNAL(triggered(bool)),this,SLOT(selectAllObjects(void))); connect(action_convert_relnn, SIGNAL(triggered(bool)), this, SLOT(convertRelationshipNN(void))); connect(action_deps_refs, SIGNAL(triggered(bool)), this, SLOT(showDependenciesReferences(void))); connect(action_copy, SIGNAL(triggered(bool)),this,SLOT(copyObjects(void))); connect(action_paste, SIGNAL(triggered(bool)),this,SLOT(pasteObjects(void))); connect(action_cut, SIGNAL(triggered(bool)),this,SLOT(cutObjects(void))); connect(action_duplicate, SIGNAL(triggered(bool)),this,SLOT(duplicateObject(void))); connect(action_rename, SIGNAL(triggered(bool)), this, SLOT(renameObject(void))); connect(action_edit_perms, SIGNAL(triggered(bool)), this, SLOT(editPermissions(void))); connect(action_sel_sch_children, SIGNAL(triggered(bool)), this, SLOT(selectSchemaChildren(void))); connect(action_sel_tagged_tabs, SIGNAL(triggered(bool)), this, SLOT(selectTaggedTables(void))); connect(action_select_object, SIGNAL(triggered(bool)), this, SLOT(highlightObject(void))); connect(action_parent_rel, SIGNAL(triggered(bool)), this, SLOT(editObject(void))); connect(action_append_sql, SIGNAL(triggered(bool)), this, SLOT(editCustomSQL(void))); connect(action_create_seq_col, SIGNAL(triggered(bool)), this, SLOT(createSequenceFromColumn(void))); connect(action_conv_int_serial, SIGNAL(triggered(bool)), this, SLOT(convertIntegerToSerial(void))); connect(action_remove_rel_points, SIGNAL(triggered(bool)), this, SLOT(removeRelationshipPoints(void))); connect(action_enable_sql, SIGNAL(triggered(bool)), this, SLOT(toggleObjectSQL(void))); connect(action_disable_sql, SIGNAL(triggered(bool)), this, SLOT(toggleObjectSQL(void))); connect(action_remove, &QAction::triggered, [&](){ removeObjects(false); }); connect(action_cascade_del, &QAction::triggered, [&](){ removeObjects(true); }); connect(action_fade_in, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsIn())); connect(action_fade_out, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsOut())); connect(action_fade_rels_in, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsIn())); connect(action_fade_rels_out, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsOut())); connect(action_collapse_ext_attribs, SIGNAL(triggered(bool)), this, SLOT(setCollapseMode())); connect(action_collpase_all_attribs, SIGNAL(triggered(bool)), this, SLOT(setCollapseMode())); connect(action_no_collapse_attribs, SIGNAL(triggered(bool)), this, SLOT(setCollapseMode())); connect(action_show_schemas_rects, SIGNAL(triggered(bool)), this, SLOT(toggleSchemasRectangles())); connect(action_hide_schemas_rects, SIGNAL(triggered(bool)), this, SLOT(toggleSchemasRectangles())); connect(db_model, SIGNAL(s_objectAdded(BaseObject*)), this, SLOT(handleObjectAddition(BaseObject *))); connect(db_model, SIGNAL(s_objectRemoved(BaseObject*)), this, SLOT(handleObjectRemoval(BaseObject *))); connect(scene, SIGNAL(s_objectsMoved(bool)), this, SLOT(handleObjectsMovement(bool))); connect(scene, SIGNAL(s_objectModified(BaseGraphicObject*)), this, SLOT(handleObjectModification(BaseGraphicObject*))); connect(scene, SIGNAL(s_objectDoubleClicked(BaseGraphicObject*)), this, SLOT(handleObjectDoubleClick(BaseGraphicObject*))); connect(scene, SIGNAL(s_popupMenuRequested(BaseObject*)), this, SLOT(configureObjectMenu(BaseObject *))); connect(scene, SIGNAL(s_popupMenuRequested(void)), this, SLOT(showObjectMenu(void))); connect(scene, SIGNAL(s_objectSelected(BaseGraphicObject*,bool)), this, SLOT(configureObjectSelection(void))); connect(scene, SIGNAL(s_childrenSelectionChanged()), this, SLOT(configureObjectSelection(void))); connect(scene, SIGNAL(s_objectsSelectedInRange(void)), this, SLOT(configureObjectSelection(void))); connect(scene, &ObjectsScene::s_collapseModeChanged, [&](){ modified = true; }); connect(scene, &ObjectsScene::s_paginationToggled, [&](){ modified = true; }); connect(scene, &ObjectsScene::s_currentPageChanged, [&](){ modified = true; }); connect(scene, &ObjectsScene::s_objectsMovedLayer, [&](){ modified = true; }); connect(scene, SIGNAL(s_layersChanged()), this, SLOT(updateModelLayers())); connect(scene, SIGNAL(s_activeLayersChanged()), this, SLOT(updateModelLayers())); connect(scene, SIGNAL(s_popupMenuRequested(BaseObject*)), new_obj_overlay_wgt, SLOT(hide())); connect(scene, SIGNAL(s_popupMenuRequested(void)), new_obj_overlay_wgt, SLOT(hide())); connect(scene, SIGNAL(s_objectSelected(BaseGraphicObject*,bool)), new_obj_overlay_wgt, SLOT(hide())); connect(scene, SIGNAL(s_childrenSelectionChanged()), new_obj_overlay_wgt, SLOT(hide())); connect(scene, SIGNAL(s_objectsScenePressed(Qt::MouseButtons)), new_obj_overlay_wgt, SLOT(hide())); viewport->installEventFilter(this); viewport->horizontalScrollBar()->installEventFilter(this); viewport->verticalScrollBar()->installEventFilter(this); } ModelWidget::~ModelWidget(void) { /* If there are copied/cutted objects that belongs to the database model being destroyed, then the cut/copy operation are cancelled by emptying the lists, avoiding crashes when trying to paste them */ if((!copied_objects.empty() && copied_objects[0]->getDatabase()==db_model) || (!cutted_objects.empty() && cutted_objects[0]->getDatabase()==db_model)) { cut_operation=false; copied_objects.clear(); cutted_objects.clear(); } popup_menu.clear(); new_object_menu.clear(); quick_actions_menu.clear(); schemas_menu.clear(); owners_menu.clear(); tags_menu.clear(); break_rel_menu.clear(); delete(viewport); delete(scene); delete(op_list); delete(db_model); } void ModelWidget::setModified(bool value) { this->modified=value; } void ModelWidget::resizeEvent(QResizeEvent *) { QRectF ret=scene->sceneRect(); //Validating the width and height of the scene, resizing if the dimension is invalid if(viewport->rect().width() > ret.width()) ret.setWidth(viewport->rect().width()); if(viewport->rect().height() > ret.height()) ret.setHeight(viewport->rect().height()); scene->setSceneRect(ret); zoom_info_lbl->move((this->width()/2) - (zoom_info_lbl->width()/2), (this->height()/2) - (zoom_info_lbl->height()/2)); magnifier_area_lbl->move(viewport->width() - magnifier_area_lbl->width(), viewport->height() - magnifier_area_lbl->height()); adjustOverlayPosition(); emit s_modelResized(); } bool ModelWidget::eventFilter(QObject *object, QEvent *event) { QWheelEvent *w_event=dynamic_cast(event); QKeyEvent *k_event=dynamic_cast(event); QGraphicsSceneMouseEvent *m_event = dynamic_cast(event); //Filters the Wheel event if it is raised by the viewport scrollbars if((object == viewport->horizontalScrollBar() || object == viewport->verticalScrollBar()) && event->type() == QEvent::Wheel && w_event->modifiers()==Qt::ControlModifier) { double zoom_inc = round(fabs(w_event->angleDelta().y())/120) * ZoomIncrement; if(w_event->angleDelta().y() < 0) this->applyZoom(this->current_zoom - zoom_inc); else this->applyZoom(this->current_zoom + zoom_inc); return(true); } else if(event->type() == QEvent::KeyPress && k_event->modifiers()==Qt::AltModifier) { this->keyPressEvent(k_event); return(true); } else if((object == magnifier_area_lbl || object == magnifier_frm) && (event->type() == QEvent::MouseMove || event->type() == QEvent::KeyRelease)) { if(event->type() == QEvent::MouseMove) updateMagnifierArea(); else if(k_event->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) showMagnifierArea(false); return(true); } else if(object == magnifier_frm && event->type() == QEvent::MouseButtonPress) { QGraphicsSceneMouseEvent *gm_event = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMousePress); QMouseEvent *m_event = dynamic_cast(event); showMagnifierArea(false); gm_event->setButton(m_event->button()); gm_event->setButtons(m_event->buttons()); gm_event->setScenePos(viewport->mapToScene(viewport->mapFromGlobal(QCursor::pos()))); qApp->postEvent(scene, gm_event); return(true); } else if(object == scene && m_event) { if(event->type() == QEvent::GraphicsSceneMouseMove) { emit s_sceneInteracted(m_event->scenePos()); emitSceneInteracted(); } //Forcing the panning mode using the middle mouse button if(m_event->buttons() == Qt::MiddleButton && event->type() == QEvent::GraphicsSceneMouseMove) { if(!panning_mode) { panning_mode = true; //Forcing the closed hand cursor because the default behavior of panning mode in QGraphicsView is to set an open hand cursor QApplication::setOverrideCursor(Qt::ClosedHandCursor); } QPointF pos = m_event->lastScreenPos() - m_event->screenPos(); int dx = viewport->horizontalScrollBar()->value() + pos.x(), dy = viewport->verticalScrollBar()->value() + pos.y(); viewport->horizontalScrollBar()->setValue(dx); viewport->verticalScrollBar()->setValue(dy); return (true); } else if(m_event->button() == Qt::NoButton && event->type() == QEvent::GraphicsSceneMouseMove) { if(magnifier_frm->isVisible()) updateMagnifierArea(); } //Activating the panning mode else if(m_event->button() == Qt::MiddleButton && event->type() == QEvent::GraphicsSceneMousePress) { viewport->setDragMode(QGraphicsView::ScrollHandDrag); QApplication::restoreOverrideCursor(); QApplication::setOverrideCursor(Qt::OpenHandCursor); return (true); } //Deactivating the panning mode else if(m_event->button() == Qt::MiddleButton && event->type() == QEvent::GraphicsSceneMouseRelease) { panning_mode = false; viewport->setDragMode(QGraphicsView::NoDrag); QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor(); return (true); } } return(QWidget::eventFilter(object, event)); } void ModelWidget::keyPressEvent(QKeyEvent *event) { //Cancels the insertion action when ESC is pressed if(event->key()==Qt::Key_Escape) { if(new_obj_overlay_wgt->isVisible()) new_obj_overlay_wgt->hide(); else { this->cancelObjectAddition(); if(!scene->isMovingObjects()) scene->clearSelection(); } } else if(event->key()==Qt::Key_N) { toggleNewObjectOverlay(); } else if(event->modifiers() == (Qt::ControlModifier | Qt::AltModifier) && current_zoom < 1) { showMagnifierArea(true); } } void ModelWidget::keyReleaseEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Control || event->key() == Qt::Key_Shift) { showMagnifierArea(false); } } void ModelWidget::mousePressEvent(QMouseEvent *event) { if(event->buttons()==Qt::LeftButton) { /* If the user is adding a graphical object, the left click will set the initial position and show the editing form related to the object type */ if(!simple_obj_creation && (BaseTable::isBaseTable(new_obj_type) || new_obj_type==ObjectType::Textbox)) { this->scene->enableRangeSelection(false); this->showObjectForm(new_obj_type, nullptr, nullptr, viewport->mapToScene(event->pos())); this->cancelObjectAddition(); this->scene->enableRangeSelection(true); } } } void ModelWidget::hideEvent(QHideEvent *) { magnifier_area_lbl->hide(); } bool ModelWidget::saveLastCanvasPosition(void) { if(save_restore_pos) { QScrollBar *hscroll=viewport->horizontalScrollBar(), *vscroll=viewport->verticalScrollBar(); QPoint pos=db_model->getLastPosition(); //Save the zoom or position only one of these attributes has changed if(db_model->getLastZoomFactor()!=current_zoom || pos.x()!=hscroll->value() || pos.y()!=vscroll->value()) { db_model->setLastPosition(QPoint(viewport->horizontalScrollBar()->value(), viewport->verticalScrollBar()->value())); db_model->setLastZoomFactor(this->current_zoom); return(true); } } return(false); } void ModelWidget::setUpdatesEnabled(bool value) { viewport->setUpdatesEnabled(value); QWidget::setUpdatesEnabled(value); } void ModelWidget::restoreLastCanvasPosition(void) { if(save_restore_pos) { QScrollBar *hscroll=viewport->horizontalScrollBar(), *vscroll=viewport->verticalScrollBar(); if(db_model->getLastZoomFactor()!=1.0) this->applyZoom(db_model->getLastZoomFactor()); hscroll->setValue(db_model->getLastPosition().x()); vscroll->setValue(db_model->getLastPosition().y()); scene->update(); } } void ModelWidget::applyZoom(double zoom) { if(zoom < MinimumZoom) zoom = MinimumZoom; else if(zoom > MaximumZoom) zoom = MaximumZoom; viewport->resetTransform(); viewport->scale(zoom, zoom); this->current_zoom=zoom; zoom_info_lbl->setText(trUtf8("Zoom: %1%").arg(QString::number(this->current_zoom * 100, 'g' , 3))); zoom_info_lbl->setVisible(true); zoom_info_timer.start(); emit s_zoomModified(zoom); } double ModelWidget::getCurrentZoom(void) { return(current_zoom); } void ModelWidget::handleObjectAddition(BaseObject *object) { BaseGraphicObject *graph_obj=dynamic_cast(object); if(graph_obj) { ObjectType obj_type=graph_obj->getObjectType(); QGraphicsItem *item=nullptr; switch(obj_type) { case ObjectType::ForeignTable: case ObjectType::Table: item=new TableView(dynamic_cast(graph_obj)); break; case ObjectType::View: item=new GraphicalView(dynamic_cast(graph_obj)); break; case ObjectType::Relationship: case ObjectType::BaseRelationship: item=new RelationshipView(dynamic_cast(graph_obj)); break; case ObjectType::Schema: if(!graph_obj->isSystemObject() || (graph_obj->isSystemObject() && graph_obj->getName()==QString("public"))) { item=new SchemaView(dynamic_cast(graph_obj)); } break; default: item=new StyledTextboxView(dynamic_cast(graph_obj)); break; } if(item) { scene->addItem(item); this->modified=true; } } } void ModelWidget::addNewObject(void) { QAction *action=dynamic_cast(sender()); if(action) { BaseObject *parent_obj=nullptr; ObjectType obj_type=static_cast(action->data().toUInt()); /* If the user wants to add a table object or a object inside a schema uses as parent object the selected object, because the user only can add these types after select a table or schema, respectively */ if(selected_objects.size()==1 && (TableObject::isTableObject(obj_type) || selected_objects[0]->getObjectType()==ObjectType::Schema)) parent_obj=selected_objects[0]; //Creating a table or view inside a schema if(parent_obj && parent_obj->getObjectType()==ObjectType::Schema && BaseTable::isBaseTable(obj_type)) { BaseObjectView *sch_graph=dynamic_cast(dynamic_cast(parent_obj)->getOverlyingObject()); QSizeF size = sch_graph->boundingRect().size(); QPointF pos, menu_pos = viewport->mapToScene(this->mapFromGlobal(popup_menu.pos())); QRectF rect = QRectF(sch_graph->pos(), size); //Uses the popup menu position if it is inside the bounding rectangle if(rect.contains(menu_pos)) pos=menu_pos; //Otherwise inserts the new object at the middle of bounding rect else pos=QPointF(sch_graph->pos().x() + (size.width()/2.0), sch_graph->pos().y() + (size.height()/2.0)); this->showObjectForm(obj_type, nullptr, parent_obj, pos); } else if(!BaseTable::isBaseTable(obj_type) && obj_type!=ObjectType::Textbox && obj_type <= ObjectType::BaseTable) this->showObjectForm(obj_type, nullptr, parent_obj); else { /* A small checking to enable the overlay widget to create relationships and other graphical objects without the user click on the canvas area */ if((obj_type > ObjectType::BaseObject && selected_objects.size()==2 && selected_objects.at(0)->getObjectType()==ObjectType::Table && selected_objects.at(1)->getObjectType()==ObjectType::Table)) { this->showObjectForm(obj_type); } else { //Simple table|view|textbox creation if(simple_obj_creation && (BaseTable::isBaseTable(obj_type) || obj_type==ObjectType::Textbox)) this->showObjectForm(obj_type, nullptr, parent_obj, viewport->mapToScene(viewport->rect().center())); else { //For the graphical object, changes the cursor icon until the user click on the model to show the editing form viewport->setCursor(QCursor(action->icon().pixmap(QSize(22,22)),0,0)); this->new_obj_type=obj_type; this->enableModelActions(false); /* If a single table is selected and the user triggered a relationship creation action via popup menu, * we force the enabling of the relationship creation steps. This will automatically selects the current table * as source table of the relationship */ if(selected_objects.size() == 1 && PhysicalTable::isPhysicalTable(selected_objects[0]->getObjectType()) && new_obj_type > ObjectType::BaseTable) configureObjectSelection(); } } } } } void ModelWidget::handleObjectRemoval(BaseObject *object) { BaseGraphicObject *graph_obj=dynamic_cast(object); if(graph_obj) { scene->removeItem(dynamic_cast(graph_obj->getOverlyingObject())); //Updates the parent schema if the removed object were a table or view if(graph_obj->getSchema() && (graph_obj->getObjectType()==ObjectType::Table || graph_obj->getObjectType()==ObjectType::View)) dynamic_cast(graph_obj->getSchema())->setModified(true); } this->modified=true; } void ModelWidget::handleObjectDoubleClick(BaseGraphicObject *object) { if(object) this->showObjectForm(object->getObjectType(), object, nullptr, object->getPosition()); else this->showObjectForm(ObjectType::Database, db_model); } void ModelWidget::handleObjectsMovement(bool end_moviment) { vector::iterator itr, itr_end; vector reg_tables; QList tables; BaseGraphicObject *obj=nullptr; Schema *schema=nullptr; itr=selected_objects.begin(); itr_end=selected_objects.end(); if(!end_moviment) { op_list->startOperationChain(); while(itr!=itr_end) { obj=dynamic_cast(*itr); itr++; if(!obj) continue; if(!dynamic_cast(obj) && (obj && !obj->isProtected())) { schema=dynamic_cast(obj); //Register the object if it is not a schema or a table already registered if(!schema && std::find(reg_tables.begin(), reg_tables.end(), obj)==reg_tables.end()) op_list->registerObject(obj, Operation::ObjectMoved); else if(schema) { //For schemas, when they are moved, the original position of tables are registered instead of the position of schema itself tables=dynamic_cast(schema->getOverlyingObject())->getChildren(); for(auto &tab : tables) { op_list->registerObject(tab->getUnderlyingObject(), Operation::ObjectMoved); //Registers the table on a auxiliary list to avoid multiple registration on operation history reg_tables.push_back(tab->getUnderlyingObject()); } } } } } else { vector schemas; while(itr!=itr_end) { obj = dynamic_cast(*itr); itr++; if(!obj) continue; if(BaseTable::isBaseTable(obj->getObjectType())) { Schema *schema=dynamic_cast(dynamic_cast(obj)->getSchema()); //Update the schema if this isn't done yet if(std::find(schemas.begin(),schemas.end(),schema)==schemas.end()) { schema->setModified(true); //Insert the updated schema to a list to avoid a second (unnecessary) update schemas.push_back(schema); } } } op_list->finishOperationChain(); this->modified=true; emit s_objectsMoved(); } } void ModelWidget::handleObjectModification(BaseGraphicObject *object) { op_list->registerObject(object, Operation::ObjectModified); this->modified=true; if(object->getSchema()) dynamic_cast(object->getSchema())->setModified(true); emit s_objectModified(); } void ModelWidget::emitSceneInteracted(void) { if(selected_objects.empty()) emit s_sceneInteracted(nullptr); else if(selected_objects.size() == 1) { BaseGraphicObject *base_obj = dynamic_cast(selected_objects[0]); TableObject *tab_obj=dynamic_cast(selected_objects[0]); if(base_obj) emit s_sceneInteracted(dynamic_cast(base_obj->getOverlyingObject())); else if(tab_obj) emit s_sceneInteracted(1, QRect()); else emit s_sceneInteracted(nullptr); } else emit s_sceneInteracted(selected_objects.size(), scene->itemsBoundingRect(true, true)); } void ModelWidget::configureObjectSelection(void) { QList items=scene->selectedItems(); BaseObjectView *item=nullptr; map objs_map; map::iterator itr; selected_objects.clear(); //Stores in a map each selected graphical object on the scene while(!items.isEmpty()) { //Only store object that can be converted to BaseObjectView item=dynamic_cast(items.front()); items.pop_front(); if(item) objs_map[item->getSelectionOrder()]=item; } itr=objs_map.begin(); while(itr!=objs_map.end()) { item=dynamic_cast(itr->second); selected_objects.push_back(item->getUnderlyingObject()); itr++; } /* Case the new_obj_type is a value greater the ObjectType::ObjBaseTable indicates that the user (un)selected a object using some "Relationship" action */ if(new_obj_type > ObjectType::BaseTable) { unsigned count=selected_objects.size(); ObjectType obj_type1, obj_type2; //If there is more than 2 object select cancel the operation if(count > 2 || count==0) this->cancelObjectAddition(); else if(count >=1 && count <=2) { //Get the selected objects types obj_type1=selected_objects[0]->getObjectType(); obj_type2=(count==2 ? selected_objects[1]->getObjectType() : ObjectType::BaseObject); //If there is only one selected object and this is a table, activates the relationship creation if(!scene->isRelationshipLineVisible() && count==1 && PhysicalTable::isPhysicalTable(obj_type1) && new_obj_type > ObjectType::BaseTable && QApplication::keyboardModifiers() == 0) { BaseGraphicObject *graph_obj=dynamic_cast(selected_objects[0]); BaseObjectView *object=dynamic_cast(graph_obj->getOverlyingObject()); scene->showRelationshipLine(true, QPointF(object->scenePos().x() + object->boundingRect().width()/2, object->scenePos().y() + object->boundingRect().height()/2)); } //If the user has selected object that are not tables, cancel the operation else if(!PhysicalTable::isPhysicalTable(obj_type1) || (!PhysicalTable::isPhysicalTable(obj_type2) && obj_type2 != ObjectType::BaseObject)) { this->cancelObjectAddition(); } /* Case there is only one selected object (table) and the SHIFT key is pressed too, creates a self-relationship. Case there is two selected objects, create a relationship between them */ else if((count==1 && PhysicalTable::isPhysicalTable(obj_type1) && QApplication::keyboardModifiers()==Qt::ShiftModifier) || (count==2 && PhysicalTable::isPhysicalTable(obj_type1) && PhysicalTable::isPhysicalTable(obj_type2))) { /* Forcing no signals to be emitted by the scene while the relationship is being configured to avoid this * method to be called unecessarily */ scene->blockSignals(true); this->showObjectForm(new_obj_type); scene->blockSignals(false); //Cancels the operation after showing the relationship editing form scene->clearSelection(); this->cancelObjectAddition(); } } } else this->configurePopupMenu(selected_objects); emitSceneInteracted(); } void ModelWidget::selectAllObjects(void) { QAction *act = qobject_cast(sender()); if(!act) return; ObjectType obj_type = static_cast(act->data().toUInt()); if(obj_type == ObjectType::BaseObject) { QPainterPath pth; pth.addRect(scene->sceneRect()); scene->blockItemsSignals(true); scene->setSelectionArea(pth); scene->blockItemsSignals(false); } else { BaseObjectView *obj_view = nullptr; vector objs = *db_model->getObjectList(obj_type); if(obj_type == ObjectType::Relationship) objs.insert(objs.end(), db_model->getObjectList(ObjectType::BaseRelationship)->begin(), db_model->getObjectList(ObjectType::BaseRelationship)->end()); for(auto &obj : objs) { obj_view = dynamic_cast(dynamic_cast(obj)->getOverlyingObject()); if(obj_view) { obj_view->blockSignals(true); obj_view->setSelected(true); obj_view->blockSignals(false); } } } configureObjectSelection(); } void ModelWidget::convertRelationshipNN(void) { Relationship *rel=reinterpret_cast(action_convert_relnn->data().value()); if(rel) { //Converts only Many-to-Many relationship if(rel->getRelationshipType()==Relationship::RelationshipNn) { Messagebox msg_box; msg_box.show(trUtf8("Do you really want to convert the relationship into an intermediate table?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { unsigned op_count=0; try { Relationship *rel1=nullptr, *rel2=nullptr; Table *tab=nullptr, *tab_nn=nullptr, *src_tab=dynamic_cast
(rel->getTable(Relationship::SrcTable)), *dst_tab=dynamic_cast
(rel->getTable(Relationship::DstTable)); Constraint *constr=nullptr, *aux_constr=nullptr, *pk=nullptr; Column *col=nullptr; bool src_mand=true, dst_mand=true; QString tab_name, xml_buf; QPointF pnt; unsigned i=1, idx, count, idx1, count1, x; vector fks; vector pk_cols; int attr_idx=-1; op_count=op_list->getCurrentSize(); //Stores the XML code definition for the table generated by the relationship tab_nn=dynamic_cast
(rel->getReceiverTable()); pk=tab_nn->getPrimaryKey(); if(!rel->isSelfRelationship()) { /* Checking if there is some attribute that is a pk too. If so, store their names in a list in order to create the pk further in this method */ count=pk->getColumnCount(Constraint::SourceCols); for(i=0; i < count; i++) { col=pk->getColumn(i, Constraint::SourceCols); attr_idx=rel->getObjectIndex(col); if(attr_idx >= 0) pk_cols.push_back(col->getName()); } } xml_buf=tab_nn->getCodeDefinition(SchemaParser::XmlDefinition); //Creates the table from the xml code xmlparser->restartParser(); xmlparser->loadXMLBuffer(xml_buf); tab=db_model->createTable(); tab_name=tab->getName(); //Forcing the creation of the single pk column if(rel->isSiglePKColumn()) { col=new Column; (*col)=(*pk->getColumn(0, Constraint::SourceCols)); col->setParentTable(nullptr); tab->addColumn(col); pk_cols.push_back(col->getName()); } if(rel->isSelfRelationship()) { //Copy the columns from the table generated by relationship to the newly created table count=tab_nn->getColumnCount(); for(idx=0; idx < count; idx++) { col=new Column; (*col)=(*tab_nn->getColumn(idx)); col->setParentTable(nullptr); tab->addColumn(col); } /* Copy the constraints from the table generated by relationship to the newly created table using the xml definition */ count=tab_nn->getConstraintCount(); for(idx=0; idx < count; idx++) { xml_buf=tab_nn->getConstraint(idx)->getCodeDefinition(SchemaParser::XmlDefinition,true); xmlparser->restartParser(); xmlparser->loadXMLBuffer(xml_buf); constr=db_model->createConstraint(tab); tab->addConstraint(constr); } tab->getForeignKeys(fks, false, src_tab); } else { //Copies the relationship attributes to the created table count=rel->getAttributeCount(); for(idx=0; idx < count; idx++) { col=new Column; (*col)=(*rel->getAttribute(idx)); col->setParentTable(nullptr); tab->addColumn(col); } //Copies the relationship constraints to the created table count=rel->getConstraintCount(); for(idx=0; idx < count; idx++) { constr=new Constraint; aux_constr=rel->getConstraint(idx); (*constr)=(*aux_constr); constr->removeColumns(); constr->setParentTable(nullptr); for(x=Constraint::SourceCols; x <= Constraint::ReferencedCols; x++) { count1=aux_constr->getColumnCount(x); for(idx1=0; idx1 < count1; idx1++) { col=tab->getColumn(aux_constr->getColumn(idx, x)->getName()); if(col) constr->addColumn(col, x); } } tab->addConstraint(constr); } } //Renames the table if there is other with the same name on the model avoiding conflicts tab->setName(tab_name); tab->setName(PgModelerNs::generateUniqueName(tab, *db_model->getObjectList(ObjectType::Table))); op_list->startOperationChain(); //Removes the many-to-many relationship from the model op_list->registerObject(rel, Operation::ObjectRemoved); //The default position for the table will be the middle point between the relationship participant tables pnt.setX((src_tab->getPosition().x() + dst_tab->getPosition().x())/2.0); pnt.setY((src_tab->getPosition().y() + dst_tab->getPosition().y())/2.0); tab->setPosition(pnt); //Adds the new table to the model db_model->addObject(tab); op_list->registerObject(tab, Operation::ObjectCreated); if(rel->isSelfRelationship()) { //For self relationships register the created foreign keys on the operation list while(!fks.empty()) { op_list->registerObject(fks.back(), Operation::ObjectCreated, -1, fks.back()->getParentTable()); fks.pop_back(); } } //If not self relationship creates two 1:n relationships else { //Creating the pk based upon the attributes of the relationship if(!pk_cols.empty()) { aux_constr=new Constraint; for(QString pk_col : pk_cols) aux_constr->addColumn(tab->getColumn(pk_col), Constraint::SourceCols); aux_constr->setName(PgModelerNs::generateUniqueName(tab, *tab->getObjectList(ObjectType::Constraint), false, QString("_pk"))); tab->addConstraint(aux_constr); op_list->registerObject(aux_constr, Operation::ObjectCreated, -1, tab); } /* Creates a one-to-many relationship that links the source table of the many-to-many rel. to the created table The relationship will be identifier if the single pk column attribute of the original relationship is false */ rel1=new Relationship(Relationship::Relationship1n, src_tab, tab, src_mand, false, !rel->isSiglePKColumn()); db_model->addRelationship(rel1); op_list->registerObject(rel1, Operation::ObjectCreated); /*Creates a one-to-many relationship that links the destination table of the many-to-many rel. to the created table The relationship will be identifier if the single pk column attribute of the original relationship is false */ rel2=new Relationship(Relationship::Relationship1n, dst_tab, tab, dst_mand, false, !rel->isSiglePKColumn()); db_model->addRelationship(rel2); op_list->registerObject(rel2, Operation::ObjectCreated); } op_list->finishOperationChain(); //Removes the n:n relationship after convert it db_model->removeObject(rel); emit s_objectCreated(); } catch(Exception &e) { if(op_count < op_list->getCurrentSize()) { unsigned qtd=op_list->getCurrentSize()-op_count; op_list->ignoreOperationChain(true); for(unsigned i=0; i < qtd; i++) { op_list->undoOperation(); op_list->removeLastOperation(); } op_list->ignoreOperationChain(false); } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } } } } void ModelWidget::loadModel(const QString &filename) { TaskProgressWidget task_prog_wgt(this); try { connect(db_model, SIGNAL(s_objectLoaded(int,QString,unsigned)), &task_prog_wgt, SLOT(updateProgress(int,QString,unsigned))); task_prog_wgt.addIcon(enum_cast(ObjectType::BaseObject), QPixmap(PgModelerUiNs::getIconPath("design"))); task_prog_wgt.setWindowTitle(trUtf8("Loading database model")); task_prog_wgt.show(); db_model->loadModel(filename); this->filename=filename; this->adjustSceneSize(); this->updateObjectsOpacity(); scene->blockSignals(true); for(auto &layer : db_model->getLayers()) scene->addLayer(layer); scene->setActiveLayers(db_model->getActiveLayers()); scene->blockSignals(false); task_prog_wgt.close(); protected_model_frm->setVisible(db_model->isProtected()); this->modified=false; } catch(Exception &e) { task_prog_wgt.close(); this->modified=false; throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::adjustSceneSize(void) { QRectF scene_rect, objs_rect; scene_rect=scene->sceneRect(); objs_rect=scene->itemsBoundingRect(); if(scene_rect.width() < objs_rect.left() + objs_rect.width()) scene_rect.setWidth(objs_rect.left() + objs_rect.width()); if(scene_rect.height() < objs_rect.top() + objs_rect.height()) scene_rect.setHeight(objs_rect.top() + objs_rect.height()); scene->setSceneRect(scene_rect); viewport->centerOn(0,0); if(ObjectsScene::isAlignObjectsToGrid()) { scene->alignObjectsToGrid(); db_model->setObjectsModified({ ObjectType::Relationship, ObjectType::BaseRelationship }); } emit s_sceneInteracted(scene_rect.size()); } void ModelWidget::printModel(QPrinter *printer, bool print_grid, bool print_page_nums) { if(printer) { bool show_grid, align_objs, show_delims; unsigned page_cnt, page, h_page_cnt, v_page_cnt, h_pg_id, v_pg_id; vector pages; QRectF margins; QPrinter::PaperSize paper_size_id; QPrinter::Orientation orient; QSizeF paper_size, custom_p_size; QSize page_size; QPen pen; QFont font; QPointF top_left, top_right, bottom_left, bottom_right, h_top_mid, h_bottom_mid, v_left_mid, v_right_mid, dx, dy, dx1, dy1; //Make a backup of the current grid options show_grid = ObjectsScene::isShowGrid(); align_objs = ObjectsScene::isAlignObjectsToGrid(); show_delims = ObjectsScene::isShowPageDelimiters(); //Reconfigure the grid options based upon the passed settings ObjectsScene::setGridOptions(print_grid, align_objs, false); scene->update(); scene->clearSelection(); //Get the page size based on the printer settings ObjectsScene::getPaperConfiguration(paper_size_id, orient, margins, custom_p_size); paper_size=printer->paperSize(QPrinter::Point); if(paper_size_id!=QPrinter::Custom) paper_size-=margins.size(); //Get the pages rect for printing pages=scene->getPagesForPrinting(paper_size, margins.size(), h_page_cnt, v_page_cnt); page_size=printer->pageRect().size(); //Creates a painter to draw the model directly on the printer QPainter painter(printer); painter.setRenderHint(QPainter::Antialiasing); font.setPointSizeF(7.5); pen.setColor(QColor(120,120,120)); pen.setWidthF(1.0); //Calculates the auxiliary points to draw the page delimiter lines top_left.setX(0); top_left.setY(0); top_right.setX(page_size.width()); top_right.setY(0); bottom_left.setX(0); bottom_left.setY(page_size.height()); bottom_right.setX(top_right.x()); bottom_right.setY(bottom_left.y()); h_top_mid.setX(page_size.width()/2); h_top_mid.setY(0); h_bottom_mid.setX(h_top_mid.x()); h_bottom_mid.setY(bottom_right.y()); v_left_mid.setX(top_left.x()); v_left_mid.setY(page_size.height()/2); v_right_mid.setX(top_right.x()); v_right_mid.setY(v_left_mid.y()); dx.setX(margins.left()); dx1.setX(margins.width()); dy.setY(margins.top()); dy1.setY(margins.height()); page_cnt=pages.size(); for(page=0, h_pg_id=0, v_pg_id=0; page < page_cnt; page++) { //Render the current page on the printer scene->render(&painter, QRect(), pages[page]); //Print the current page number is this option is marked if(print_page_nums) { painter.setPen(QColor(120,120,120)); painter.drawText(-margins.left(), -margins.top(), QString("%1").arg(page+1)); } //Print the guide lines at corners of the page painter.setPen(pen); if(h_pg_id==0 && v_pg_id==0) { painter.drawLine(top_left, top_left + dx); painter.drawLine(top_left, top_left + dy); } if(h_pg_id==h_page_cnt-1 && v_pg_id==0) { painter.drawLine(top_right, top_right - dx1); painter.drawLine(top_right, top_right + dy); } if(h_pg_id==0 && v_pg_id==v_page_cnt-1) { painter.drawLine(bottom_left, bottom_left + dx); painter.drawLine(bottom_left, bottom_left - dy1); } if(h_pg_id==h_page_cnt-1 && v_pg_id==v_page_cnt-1) { painter.drawLine(bottom_right, bottom_right - dx1); painter.drawLine(bottom_right, bottom_right - dy1); } if(h_pg_id >=1 && h_pg_id < h_page_cnt-1 && v_pg_id==0) { painter.drawLine(h_top_mid, h_top_mid - dx1); painter.drawLine(h_top_mid, h_top_mid + dx); } if(h_pg_id >=1 && h_pg_id < h_page_cnt-1 && v_pg_id==v_page_cnt-1) { painter.drawLine(h_bottom_mid, h_bottom_mid - dx1); painter.drawLine(h_bottom_mid, h_bottom_mid + dx); } if(v_pg_id >=1 && v_pg_id < v_page_cnt-1 && h_pg_id==0) { painter.drawLine(v_left_mid, v_left_mid - dy1); painter.drawLine(v_left_mid, v_left_mid + dy); } if(v_pg_id >=1 && v_pg_id < v_page_cnt-1 && h_pg_id==h_page_cnt-1) { painter.drawLine(v_right_mid, v_right_mid - dy1); painter.drawLine(v_right_mid, v_right_mid + dy); } h_pg_id++; if(h_pg_id==h_page_cnt) { h_pg_id=0; v_pg_id++; } if(page < page_cnt-1) printer->newPage(); } //Restore the grid option backup ObjectsScene::setGridOptions(show_grid, align_objs, show_delims); scene->update(); } } void ModelWidget::updateRenderHints(void) { viewport->setRenderHint(QPainter::Antialiasing, !disable_render_smooth); viewport->setRenderHint(QPainter::TextAntialiasing, !disable_render_smooth); viewport->setRenderHint(QPainter::SmoothPixmapTransform, !disable_render_smooth); } void ModelWidget::update(void) { updateRenderHints(); scene->update(); QWidget::update(); } void ModelWidget::saveModel(void) { saveModel(this->filename); } void ModelWidget::saveModel(const QString &filename) { TaskProgressWidget task_prog_wgt(this); QString bkpfile; QTemporaryFile tmpfile; bool exists = QFile::exists(filename); try { connect(db_model, SIGNAL(s_objectLoaded(int,QString,unsigned)), &task_prog_wgt, SLOT(updateProgress(int,QString,unsigned))); task_prog_wgt.setWindowTitle(trUtf8("Saving database model")); task_prog_wgt.show(); /* If the original file exists we need to make a back first to avoid * in order to recover it in case of failures */ if(exists) { // Generate a temporary backup file tmpfile.setAutoRemove(false); tmpfile.setFileTemplate(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + QString("%1_XXXXXX.dbk").arg(this->db_model->getName())); tmpfile.open(); bkpfile = tmpfile.fileName(); tmpfile.close(); tmpfile.remove(); /* Copy the original database model file prior to the saving to store * its last state in a safe place (temporary storage of the tool ~/.config/pgmodeler by default */ QFile::copy(filename, bkpfile); // Remove the original filename before create a new one in the same path QFile::remove(filename); } saveLastCanvasPosition(); db_model->saveModel(filename, SchemaParser::XmlDefinition); this->filename=filename; task_prog_wgt.close(); disconnect(db_model, nullptr, &task_prog_wgt, nullptr); this->modified=false; /* Doing a final check to the file regarding its size. * If we have a zero-byte file something went wrong during the saving process (disk failure, thread errors, etc) * so we raise an error to the user and restore the backup file to its original path */ if(QFileInfo(filename).size() == 0) throw Exception(Exception::getErrorMessage(ErrorCode::ModelFileInvalidSize).arg(filename).arg(bkpfile), ErrorCode::ModelFileInvalidSize,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(exists) QFile::remove(bkpfile); } catch(Exception &e) { if(exists && QFile::exists(bkpfile)) { QFile::remove(filename); QFile::copy(bkpfile, filename); } task_prog_wgt.close(); disconnect(db_model, nullptr, &task_prog_wgt, nullptr); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } QString ModelWidget::getFilename(void) { return(this->filename); } QString ModelWidget::getTempFilename(void) { return(this->tmp_filename); } int ModelWidget::openEditingForm(QWidget *widget, unsigned button_conf) { BaseForm editing_form(this); BaseObjectWidget *base_obj_wgt=qobject_cast(widget); QString class_name = widget->metaObject()->className(); int res = 0; if(base_obj_wgt) { BaseRelationship *rel = dynamic_cast(base_obj_wgt->getHandledObject()); editing_form.setMainWidget(base_obj_wgt); if(rel) class_name.prepend(rel->getRelationshipTypeName().replace(QRegExp("( )+|(\\-)+"), QString())); } else editing_form.setMainWidget(widget); editing_form.setButtonConfiguration(button_conf); GeneralConfigWidget::restoreWidgetGeometry(&editing_form, class_name); res = editing_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&editing_form, class_name); return(res); } template int ModelWidget::openEditingForm(BaseObject *object) { WidgetClass *object_wgt=new WidgetClass; object_wgt->setAttributes(db_model, op_list, dynamic_cast(object)); return(openEditingForm(object_wgt)); } template int ModelWidget::openEditingForm(BaseObject *object, BaseObject *parent_obj) { WidgetClass *object_wgt=new WidgetClass; object_wgt->setAttributes(db_model, op_list, dynamic_cast(parent_obj), dynamic_cast(object)); return(openEditingForm(object_wgt)); } template int ModelWidget::openEditingForm(BaseObject *object, BaseObject *parent_obj, const QPointF &pos) { WidgetClass *object_wgt=new WidgetClass; object_wgt->setAttributes(db_model, op_list, dynamic_cast(parent_obj), dynamic_cast(object), pos.x(), pos.y()); return(openEditingForm(object_wgt)); } int ModelWidget::openTableEditingForm(ObjectType tab_type, PhysicalTable *object, Schema *schema, const QPointF &pos) { TableWidget *tab_wgt=new TableWidget(nullptr, tab_type); if(tab_type == ObjectType::Table) tab_wgt->setAttributes(db_model, op_list, schema, dynamic_cast
(object), pos.x(), pos.y()); else tab_wgt->setAttributes(db_model, op_list, schema, dynamic_cast(object), pos.x(), pos.y()); return(openEditingForm(tab_wgt)); } void ModelWidget::showObjectForm(ObjectType obj_type, BaseObject *object, BaseObject *parent_obj, const QPointF &pos) { try { unsigned rel_type=0; int res = QDialog::Rejected; Schema *sel_schema=dynamic_cast(parent_obj); QPointF obj_pos=pos; /* Case the obj_type is greater than ObjectType::ObjBaseTable indicates that the object type is a relationship. To get the specific relationship id (1-1, 1-n, n-n, gen, dep) is necessary to subtract the ObjectType::ObjRelationship from the obj_type parameter, the result will point to the BaseRelationship::RELATIONSHIP_??? constant. */ if(obj_type > ObjectType::BaseTable) { rel_type=enum_cast(obj_type) - enum_cast(ObjectType::Relationship); obj_type=ObjectType::Relationship; } if(obj_type!=ObjectType::Permission) { if(object && obj_type!=object->getObjectType()) throw Exception(ErrorCode::OprObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__); //If the user try to call the table object form without specify a parent object else if(!parent_obj && TableObject::isTableObject(obj_type)) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } if(object && dynamic_cast(object)) obj_pos=dynamic_cast(object)->getPosition(); /* Raises an error if the user try to edit a reserverd object. The only exception is for "public" schema that can be edited only on its fill color an rectangle attributes */ if(object && object->isSystemObject() && (object->getObjectType()!=ObjectType::Schema || object->getName()!="public")) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(object->getName()).arg(object->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(obj_type==ObjectType::Schema) res=openEditingForm(object); else if(obj_type==ObjectType::Role) res=openEditingForm(object); else if(obj_type==ObjectType::Tablespace) res=openEditingForm(object); else if(obj_type==ObjectType::Language) res=openEditingForm(object); else if(obj_type==ObjectType::Cast) res=openEditingForm(object); else if(obj_type==ObjectType::Tag) res=openEditingForm(object); else if(obj_type== ObjectType::EventTrigger) res=openEditingForm(object); else if(obj_type==ObjectType::Function) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Conversion) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Domain) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Aggregate) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Sequence) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Operator) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::OpFamily) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::OpClass) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Type) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Collation) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Extension) res=openEditingForm(object, sel_schema); else if(obj_type==ObjectType::Table) res=openTableEditingForm(obj_type, dynamic_cast
(object), sel_schema, obj_pos); else if(obj_type==ObjectType::ForeignTable) res=openTableEditingForm(obj_type, dynamic_cast(object), sel_schema, obj_pos); else if(obj_type==ObjectType::View) res=openEditingForm(object, sel_schema, obj_pos); else if(obj_type==ObjectType::Rule) res=openEditingForm(object, parent_obj); else if(obj_type== ObjectType::Trigger) res=openEditingForm(object, parent_obj); else if(obj_type== ObjectType::Index) res=openEditingForm(object, parent_obj); else if(obj_type== ObjectType::Policy) res=openEditingForm(object, parent_obj); else if(obj_type==ObjectType::Column || obj_type==ObjectType::Constraint) { TableObject *tab_obj=dynamic_cast(object); if(obj_type==ObjectType::Column) res=openEditingForm(object, parent_obj); else res=openEditingForm(object, parent_obj); if(res==QDialog::Accepted) { if(tab_obj && parent_obj->getObjectType()==ObjectType::Table) db_model->validateRelationships(tab_obj, dynamic_cast
(parent_obj)); else db_model->validateRelationships(); } } else if(obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Relationship) { RelationshipWidget *relationship_wgt=new RelationshipWidget; if(!object && rel_type > 0 && selected_objects.size() > 0 && PhysicalTable::isPhysicalTable(selected_objects[0]->getObjectType())) { PhysicalTable *tab1 = dynamic_cast(selected_objects[0]), *tab2 = (selected_objects.size()==2 ? dynamic_cast(selected_objects[1]) : tab1); relationship_wgt->setAttributes(db_model, op_list, tab1, tab2, rel_type); } else relationship_wgt->setAttributes(db_model, op_list, dynamic_cast(object)); res=openEditingForm(relationship_wgt); scene->clearSelection(); } else if(obj_type==ObjectType::Textbox) { TextboxWidget *textbox_wgt=new TextboxWidget; textbox_wgt->setAttributes(db_model, op_list, dynamic_cast(object), obj_pos.x(), obj_pos.y()); res=openEditingForm(textbox_wgt); } else if(obj_type==ObjectType::Permission) { PermissionWidget *permission_wgt=new PermissionWidget; Permission *perm=dynamic_cast(object); permission_wgt->setAttributes(db_model, nullptr, (perm ? perm->getObject() : object)); res=openEditingForm(permission_wgt, Messagebox::OkButton); } else if(obj_type==ObjectType::GenericSql) { GenericSQLWidget *genericsql_wgt=new GenericSQLWidget; genericsql_wgt->setAttributes(db_model, op_list, dynamic_cast(object)); res=openEditingForm(genericsql_wgt); } else if(obj_type==ObjectType::ForeignDataWrapper) res = openEditingForm(object); else if(obj_type==ObjectType::ForeignServer) res = openEditingForm(object); else if(obj_type==ObjectType::UserMapping) res = openEditingForm(object); else { DatabaseWidget *database_wgt=new DatabaseWidget; database_wgt->setAttributes(db_model); res=openEditingForm(database_wgt); } if(res==QDialog::Accepted) { this->modified=true; this->db_model->setInvalidated(true); emit s_objectManipulated(); } else emit s_manipulationCanceled(); this->setFocus(); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); } } void ModelWidget::showDependenciesReferences(void) { QAction *obj_sender=dynamic_cast(sender()); if(obj_sender) { BaseObject *object=reinterpret_cast(obj_sender->data().value()); if(object) { ObjectDepsRefsWidget *deps_refs_wgt=new ObjectDepsRefsWidget; deps_refs_wgt->setAttributes(this, object); openEditingForm(deps_refs_wgt, Messagebox::OkButton); } } } void ModelWidget::showSourceCode(void) { QAction *obj_sender=dynamic_cast(sender()); if(obj_sender) { BaseObject *object=reinterpret_cast(obj_sender->data().value()); if(object) { SourceCodeWidget *sourcecode_wgt=new SourceCodeWidget; sourcecode_wgt->setAttributes(this->db_model, object); openEditingForm(sourcecode_wgt, Messagebox::OkButton); } } } void ModelWidget::cancelObjectAddition(void) { //Reset the new object type to a invalid one forcing the user to select a correct type again new_obj_type=ObjectType::BaseObject; //Restore the cursor icon viewport->setCursor(QCursor(Qt::ArrowCursor)); //Hide the line that simulates the relationship creation scene->showRelationshipLine(false); this->configurePopupMenu(this->selected_objects); } void ModelWidget::renameObject(void) { QAction *act=dynamic_cast(sender()); BaseObject *obj=reinterpret_cast(act->data().value()); if(obj->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(obj->getName()).arg(obj->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); ObjectRenameWidget objectrename_wgt(this); objectrename_wgt.setAttributes(obj, this->db_model, this->op_list); objectrename_wgt.exec(); if(objectrename_wgt.result()==QDialog::Accepted) { this->modified=true; emit s_objectModified(); } } void ModelWidget::moveToSchema(void) { QAction *act=dynamic_cast(sender()); Schema *schema=dynamic_cast(reinterpret_cast(act->data().value())); BaseGraphicObject *obj_graph=nullptr; vector ref_objs; int op_id=-1, op_curr_idx=op_list->getCurrentIndex(); try { QApplication::setOverrideCursor(Qt::WaitCursor); op_list->startOperationChain(); for(BaseObject *obj : selected_objects) { //Change the object's schema only if the new schema is different from the current if(obj->acceptsSchema() && obj->getSchema()!=schema) { op_id=op_list->registerObject(obj, Operation::ObjectModified, -1); obj->setSchema(schema); obj_graph=dynamic_cast(obj); //If the object is a graphical one, move it to a position near to the new schema box if(obj_graph) { SchemaView *dst_schema=dynamic_cast(schema->getOverlyingObject()); QPointF p; if(dst_schema && dst_schema->isVisible()) { p.setX(dst_schema->pos().x()); p.setY(dst_schema->pos().y() + dst_schema->boundingRect().height() + BaseObjectView::VertSpacing); dynamic_cast(obj_graph->getOverlyingObject())->setPos(p); } } //Invalidating the code of the object's references db_model->getObjectReferences(obj, ref_objs); for(BaseObject *ref_obj : ref_objs) ref_obj->setCodeInvalidated(true); } } op_list->finishOperationChain(); db_model->setObjectsModified(); this->setModified(true); emit s_objectModified(); QApplication::restoreOverrideCursor(); } catch(Exception &e) { QApplication::restoreOverrideCursor(); if(op_id >=0 && op_id > op_curr_idx) op_list->removeLastOperation(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::moveToLayer(void) { QAction *act = dynamic_cast(sender()); BaseGraphicObject *graph_obj = nullptr; unsigned layer_id = act->data().toUInt(); for(auto &obj : selected_objects) { graph_obj = dynamic_cast(obj); graph_obj->setLayer(layer_id); } QApplication::setOverrideCursor(Qt::WaitCursor); scene->updateActiveLayers(); QApplication::restoreOverrideCursor(); } void ModelWidget::changeOwner(void) { QAction *act=dynamic_cast(sender()); BaseObject *owner=reinterpret_cast(act->data().value()); vector sel_objs; int op_id=-1, op_curr_idx=op_list->getCurrentIndex(); try { if(selected_objects.empty()) sel_objs.push_back(this->db_model); else sel_objs=selected_objects; op_list->startOperationChain(); for(BaseObject *obj : sel_objs) { if(obj->acceptsOwner() && obj->getOwner()!=owner) { if(obj->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(obj->getName()) .arg(obj->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Register an operation only if the object is not the database itself if(obj->getObjectType()!=ObjectType::Database) op_id=op_list->registerObject(obj, Operation::ObjectModified, -1); obj->setOwner(owner); } } op_list->finishOperationChain(); emit s_objectModified(); } catch(Exception &e) { if(op_id >=0 && op_id >= op_curr_idx) op_list->removeLastOperation(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::setTag(void) { QAction *act=dynamic_cast(sender()); BaseObject *tag=reinterpret_cast(act->data().value()); BaseTable *tab=nullptr; int op_id=-1, op_curr_idx=op_list->getCurrentIndex(); try { op_list->startOperationChain(); for(BaseObject *obj : selected_objects) { tab=dynamic_cast(obj); if(tab) { op_id=op_list->registerObject(obj, Operation::ObjectModified, -1); tab->setTag(dynamic_cast(tag)); } } op_list->finishOperationChain(); db_model->setObjectsModified(selected_objects); scene->clearSelection(); emit s_objectModified(); } catch(Exception &e) { if(op_id >=0 && op_id > op_curr_idx) op_list->removeLastOperation(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::editPermissions(void) { PermissionWidget *permission_wgt=new PermissionWidget; QAction *act=dynamic_cast(sender()); BaseObject *obj=reinterpret_cast(act->data().value()); permission_wgt->setAttributes(this->db_model, nullptr, obj); openEditingForm(permission_wgt, Messagebox::OkButton); this->setModified(true); emit s_objectManipulated(); } void ModelWidget::editObject(void) { QObject *obj_sender=dynamic_cast(sender()); TableObject *tab_obj=nullptr; BaseObject *object=nullptr; /* Workaround: To permit the object edition via double click on the ModelObjectWidget the sender is configured as the edit action of the model widget */ if(!obj_sender) obj_sender=action_edit; object=reinterpret_cast(dynamic_cast(obj_sender)->data().value()); tab_obj=dynamic_cast(object); if(object) showObjectForm(object->getObjectType(), object, (tab_obj ? tab_obj->getParentTable() : nullptr)); } void ModelWidget::selectSchemaChildren(void) { QObject *obj_sender=dynamic_cast(sender()); Schema *schema=nullptr; schema=dynamic_cast( reinterpret_cast( dynamic_cast(obj_sender)->data().value())); scene->clearSelection(); dynamic_cast( dynamic_cast(schema->getOverlyingObject()))->selectChildren(); } void ModelWidget::selectTaggedTables(void) { QObject *obj_sender=dynamic_cast(sender()); Tag *tag=nullptr; vector objects; BaseObjectView *obj_view = nullptr; tag=dynamic_cast( reinterpret_cast( dynamic_cast(obj_sender)->data().value())); scene->clearSelection(); db_model->getObjectReferences(tag, objects); for(auto object : objects) { obj_view = dynamic_cast(dynamic_cast(object)->getOverlyingObject()); obj_view->setSelected(true); } } void ModelWidget::protectObject(void) { try { QObject *obj_sender=sender(); ObjectType obj_type; TableObject *tab_obj=nullptr; bool protect=false; QList upd_objects; Messagebox msgbox; scene->blockSignals(true); //Protects the whole model if there is no selected object if(this->selected_objects.empty()) { if(obj_sender==action_protect || obj_sender==action_unprotect) db_model->setProtected(!db_model->isProtected()); } //If there is more than one selected object, make a batch protection/unprotection else { protect=(!this->selected_objects[0]->isProtected()); for(auto &object : selected_objects) { obj_type=object->getObjectType(); if(obj_type==ObjectType::Column || obj_type==ObjectType::Constraint) { tab_obj=dynamic_cast(object); if(tab_obj->isAddedByRelationship()) { throw Exception(Exception::getErrorMessage(ErrorCode::OprRelationshipAddedObject) .arg(object->getName()).arg(object->getTypeName()), ErrorCode::OprRelationshipAddedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } // Applying protection status for the schema children objects if(obj_type==ObjectType::Schema) { if(!msgbox.isCustomOptionChecked()) { msgbox.setCustomOptionText("Apply to all other selected schemas"); msgbox.show(QString(QT_TR_NOOP("Do you want to %1 the children of the schema %2 too?")) .arg(protect ? QT_TR_NOOP("protect") : QT_TR_NOOP("unprotect")).arg(object->getName()), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); } if(msgbox.result()==QDialog::Accepted || msgbox.isCustomOptionChecked()) { vector objects(db_model->getObjects(object)); for(BaseObject *obj : objects) obj->setProtected(protect); } } object->setProtected(protect); tab_obj = dynamic_cast(object); if(tab_obj && !upd_objects.contains(tab_obj->getParentTable())) upd_objects.push_back(tab_obj->getParentTable()); } } for(auto &obj : upd_objects) obj->setModified(true); protected_model_frm->setVisible(db_model->isProtected()); scene->blockSignals(false); scene->clearSelection(); this->setModified(true); emit s_objectModified(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::cutObjects(void) { /* Store the source model as 'this'. This attribute is used on the paste method to remove the selected object and updated the source model */ ModelWidget::src_model=this; //Set the flag indicating that a cut operation started ModelWidget::cut_operation=true; this->copyObjects(); } void ModelWidget::copyObjects(bool duplicate_mode) { map objs_map; map::iterator obj_itr; vector::iterator itr, itr_end; vector deps; BaseObject *object=nullptr; TableObject *tab_obj=nullptr; BaseTable *table=nullptr; Constraint *constr=nullptr; ObjectType types[]={ ObjectType::Trigger, ObjectType::Rule, ObjectType::Index, ObjectType::Constraint, ObjectType::Policy }; unsigned i, type_id, count; Messagebox msg_box; if(selected_objects.size()==1) { //Raise an error if the user try to copy a reserved object if(selected_objects[0]->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(selected_objects[0]->getName()).arg(selected_objects[0]->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } if(!duplicate_mode) { //Ask for confirmation to copy the dependencies of the object(s) msg_box.show(trUtf8("Also copy all dependencies of selected objects? This minimizes the breakdown of references when copied objects are pasted into another model."), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); } /* When in cut operation is necessary to store the selected objects in a separeted list in order to correclty cut (remove) the object on the source model */ if(ModelWidget::cut_operation) cutted_objects=selected_objects; itr=selected_objects.begin(); itr_end=selected_objects.end(); while(itr!=itr_end) { object=(*itr); //Table-view relationships and FK relationship aren't copied since they are created automatically when pasting the tables/views if(object->getObjectType()!=ObjectType::BaseRelationship) { if(msg_box.result()==QDialog::Accepted) db_model->getObjectDependecies(object, deps, true); else deps.push_back(object); /* Copying the special objects (which references columns added by relationship) in order to be correclty created when pasted */ if(object->getObjectType()==ObjectType::Table || object->getObjectType() == ObjectType::View) { table=dynamic_cast(object); for(type_id=0; type_id <= 4; type_id++) { count=table->getObjectCount(types[type_id]); for(i=0; i < count; i++) { tab_obj=dynamic_cast(table->getObject(i, types[type_id])); constr=dynamic_cast(tab_obj); /* The object is only inserted at the list when it was not included by relationship but references columns added by relationship. Case the object is a constraint, it cannot be a primary key because this type of constraint is treated separetely by relationships */ if(duplicate_mode || (!duplicate_mode && !tab_obj->isAddedByRelationship() && (!constr || (((constr && (constr->getConstraintType()==ConstraintType::ForeignKey || (constr->getConstraintType()==ConstraintType::Unique && constr->isReferRelationshipAddedColumn())))))))) deps.push_back(tab_obj); } if(object->getObjectType() == ObjectType::View && type_id >= 2) break; } } } itr++; } itr=deps.begin(); itr_end=deps.end(); //Storing the objects ids in a auxiliary vector while(itr!=itr_end) { object=(*itr); objs_map[object->getObjectId()]=object; itr++; } copied_objects.clear(); obj_itr=objs_map.begin(); while(obj_itr!=objs_map.end()) { object=obj_itr->second; //Reserved object aren't copied if(!object->isSystemObject()) copied_objects.push_back(object); obj_itr++; } } void ModelWidget::pasteObjects(bool duplicate_mode) { map xml_objs; BaseTable *orig_parent_tab=nullptr; vector::iterator itr, itr_end; map orig_obj_names; BaseObject *object=nullptr, *aux_object=nullptr; TableObject *tab_obj=nullptr; Table *sel_table=nullptr, *aux_table = nullptr; View *sel_view=nullptr; BaseTable *parent=nullptr; Function *func=nullptr; Constraint *constr=nullptr; Operator *oper=nullptr; QString aux_name, copy_obj_name; ObjectType obj_type; vector errors; unsigned pos=0; TaskProgressWidget task_prog_wgt(this); task_prog_wgt.setWindowTitle(trUtf8("Pasting objects...")); task_prog_wgt.show(); itr=copied_objects.begin(); itr_end=copied_objects.end(); /* If there is only one object selected, check if its a table or view. Because if the user try to paste a table object the receiver object (selected) must be a table or view */ if(selected_objects.size()==1) { sel_table=dynamic_cast
(selected_objects[0]); sel_view=dynamic_cast(selected_objects[0]); } while(itr!=itr_end) { object=(*itr); obj_type=object->getObjectType(); tab_obj=dynamic_cast(object); itr++; pos++; task_prog_wgt.updateProgress((pos/static_cast(copied_objects.size()))*100, trUtf8("Validating object: `%1' (%2)").arg(object->getName()) .arg(object->getTypeName()), enum_cast(object->getObjectType())); if(!tab_obj || ((sel_table || sel_view) && tab_obj)) { /* The first validation is to check if the object to be pasted does not conflict with any other object of the same type on the model */ if(obj_type==ObjectType::Function) dynamic_cast(object)->createSignature(true); else if(tab_obj) aux_name=tab_obj->getName(true); else aux_name=object->getSignature(); if(!tab_obj) //Try to find the object on the model aux_object=db_model->getObject(aux_name, obj_type); else { if(sel_view && (obj_type==ObjectType::Trigger || obj_type==ObjectType::Rule || obj_type==ObjectType::Index)) aux_object=sel_view->getObject(aux_name, obj_type); else if(sel_table) aux_object=sel_table->getObject(aux_name, obj_type); } /* The second validation is to check, when the object is found on the model, if the XML code of the found object and the object to be pasted are different. When the XML defintion are the same the object isn't pasted because the found object can be used as substitute of the object to be pasted. This operation is not applied to graphical objects because they are ALWAYS pasted on the model. The only exception is that the below code is executed when the found object is the same as the copied object (this means that user is copying and pasting the object at the same database) */ if(tab_obj || (aux_object && (dynamic_cast(object) || (aux_object->getDatabase()==object->getDatabase()) || (aux_object->getCodeDefinition(SchemaParser::SchemaParser::XmlDefinition) != object->getCodeDefinition(SchemaParser::SchemaParser::XmlDefinition))))) { //Resolving name conflicts if(obj_type!=ObjectType::Cast) { func=nullptr; oper=nullptr; //Store the orignal object name on a map orig_obj_names[object]=object->getName(); /* For each object type as follow configures the name and the suffix and store them on the 'copy_obj_name' variable. This string is used to check if there are objects with the same name on model. While the 'copy_obj_name' conflicts with other objects (of same type) this validation is made */ if(obj_type==ObjectType::Function) { func=dynamic_cast(object); func->setName(PgModelerNs::generateUniqueName(func, (*db_model->getObjectList(ObjectType::Function)), false, QString("_cp"))); copy_obj_name=func->getName(); func->setName(orig_obj_names[object]); } else if(obj_type==ObjectType::Operator) { oper=dynamic_cast(object); oper->setName(PgModelerNs::generateUniqueName(oper, (*db_model->getObjectList(ObjectType::Operator)))); copy_obj_name=oper->getName(); oper->setName(orig_obj_names[object]); } else { if(tab_obj) { if(sel_table) tab_obj->setName(PgModelerNs::generateUniqueName(tab_obj, (*sel_table->getObjectList(tab_obj->getObjectType())), false, QString("_cp"), true)); else tab_obj->setName(PgModelerNs::generateUniqueName(tab_obj, (*sel_view->getObjectList(tab_obj->getObjectType())), false, QString("_cp"), true)); } else object->setName(PgModelerNs::generateUniqueName(object, (*db_model->getObjectList(object->getObjectType())), false, QString("_cp"), true)); copy_obj_name=object->getName(); object->setName(orig_obj_names[object]); } //Sets the new object name concatenating the suffix to the original name object->setName(copy_obj_name); } } } } /* The third step is get the XML code definition of the copied objects, is with the xml code that the copied object are created and inserted on the model */ itr=copied_objects.begin(); itr_end=copied_objects.end(); pos=0; while(itr!=itr_end) { object=(*itr); object->setCodeInvalidated(true); tab_obj=dynamic_cast(object); itr++; pos++; task_prog_wgt.updateProgress((pos/static_cast(copied_objects.size()))*100, trUtf8("Generating XML for: `%1' (%2)").arg(object->getName()) .arg(object->getTypeName()), enum_cast(object->getObjectType())); if(!tab_obj) { aux_table = dynamic_cast
(object);; //Stores the XML definition on a xml buffer map if(duplicate_mode && aux_table) { xml_objs[object] = aux_table->__getCodeDefinition(SchemaParser::XmlDefinition, true); object->setCodeInvalidated(true); } else xml_objs[object]=object->getCodeDefinition(SchemaParser::XmlDefinition); } //Store the original parent table of the object else if(tab_obj && (sel_table || sel_view)) { if(sel_table) parent=sel_table; else parent=sel_view; /* Only generates the XML for a table object when the selected receiver object * is a table or is a view and the current object is a trigger, index, or rule (because * view's only accepts this two types) */ if(sel_table || (sel_view && (tab_obj->getObjectType()==ObjectType::Trigger || tab_obj->getObjectType()==ObjectType::Rule || tab_obj->getObjectType()==ObjectType::Index))) { //Backups the original parent table orig_parent_tab=tab_obj->getParentTable(); constr = dynamic_cast(tab_obj); //Set the parent table as the selected table/view tab_obj->setParentTable(parent); //Generates the XML code with the new parent table if(constr) { xml_objs[object]=constr->getCodeDefinition(SchemaParser::XmlDefinition, duplicate_mode); tab_obj->setCodeInvalidated(true); } else xml_objs[object]=object->getCodeDefinition(SchemaParser::XmlDefinition); //Restore the original parent table tab_obj->setParentTable(orig_parent_tab); } } else if(tab_obj) { //Generates the XML code with the new parent table constr = dynamic_cast(tab_obj); if(constr) { xml_objs[object]=constr->getCodeDefinition(SchemaParser::XmlDefinition, duplicate_mode); tab_obj->setCodeInvalidated(true); } else xml_objs[object]=tab_obj->getCodeDefinition(SchemaParser::XmlDefinition); } } //The fourth step is the restoration of original names of the copied objects itr=copied_objects.begin(); itr_end=copied_objects.end(); while(itr!=itr_end) { object = (*itr); obj_type = object->getObjectType(); itr++; if(orig_obj_names[object].count() && obj_type!=ObjectType::Cast) object->setName(orig_obj_names[object]); } //The last step is create the object from the stored xmls itr=copied_objects.begin(); itr_end=copied_objects.end(); pos=0; op_list->startOperationChain(); while(itr!=itr_end) { object = *itr; itr++; if(xml_objs.count(object)) { xmlparser->restartParser(); xmlparser->loadXMLBuffer(xml_objs[object]); try { pos++; task_prog_wgt.updateProgress((pos/static_cast(copied_objects.size()))*100, trUtf8("Pasting object: `%1' (%2)").arg(object->getName()) .arg(object->getTypeName()), enum_cast(object->getObjectType())); //Creates the object from the XML object=db_model->createObject(BaseObject::getObjectType(xmlparser->getElementName())); tab_obj=dynamic_cast(object); constr=dynamic_cast(tab_obj); /* Once created, the object is added on the model, except for relationships and table objects * because they are inserted automatically */ if(object && !tab_obj && !dynamic_cast(object)) { if(db_model->getObjectIndex(object->getSignature(), object->getObjectType()) >= 0) object->setName(PgModelerNs::generateUniqueName(object, *db_model->getObjectList(object->getObjectType()), false, QString("_cp"))); db_model->addObject(object); } //Special case for table objects if(tab_obj) { if(sel_table && tab_obj->getObjectType()==ObjectType::Column) { sel_table->addObject(tab_obj); sel_table->setModified(true); } else if(constr && duplicate_mode && constr->getConstraintType() == ConstraintType::PrimaryKey && constr->getParentTable()->getObjectIndex(constr) < 0) { constr->getParentTable()->addObject(constr); constr->getParentTable()->setModified(true); } //Updates the fk relationships if the constraint is a foreign-key if(constr && constr->getConstraintType()==ConstraintType::ForeignKey) db_model->updateTableFKRelationships(dynamic_cast
(tab_obj->getParentTable())); op_list->registerObject(tab_obj, Operation::ObjectCreated, -1, tab_obj->getParentTable()); } else op_list->registerObject(object, Operation::ObjectCreated); } catch(Exception &e) { errors.push_back(e); } } } op_list->finishOperationChain(); //Validates the relationships to reflect any modification on the tables structures and not propagated columns db_model->validateRelationships(); this->adjustSceneSize(); task_prog_wgt.close(); //If some error occur during the process show it to the user if(!errors.empty()) { Messagebox msg_box; msg_box.show(Exception(trUtf8("Not all objects were pasted to the model due to errors returned during the process! Refer to error stack for more details!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__, errors), QString(), Messagebox::AlertIcon); } if(!ModelWidget::cut_operation) { //copied_objects.clear(); emit s_objectCreated(); } //If its a cut operatoin else { //Remove the objects from the source model ModelWidget::src_model->selected_objects=ModelWidget::cutted_objects; ModelWidget::src_model->removeObjects(false); //Uncheck the cut operation flag ModelWidget::cut_operation=false; copied_objects.clear(); cutted_objects.clear(); if(this!=ModelWidget::src_model) ModelWidget::src_model->configurePopupMenu(); ModelWidget::src_model=nullptr; } this->configurePopupMenu(); this->modified=true; //Restoring the viewport position after paste objects viewport->verticalScrollBar()->setValue(db_model->getLastPosition().y()); viewport->horizontalScrollBar()->setValue(db_model->getLastPosition().x()); } void ModelWidget::duplicateObject(void) { int op_id = -1; try { if(scene->hasOnlyTableChildrenSelection() || (selected_objects.size() == 1 && TableObject::isTableObject(selected_objects[0]->getObjectType()))) { Schema *schema = nullptr; BaseObject *dup_object=nullptr; BaseTable *table = nullptr; ObjectType obj_type; QList upd_schemas; QList upd_view_ref_tables; QList upd_tables; QList upd_fk_rels; op_list->startOperationChain(); for(auto &tab_obj : selected_objects) { dup_object=nullptr; obj_type = tab_obj->getObjectType(); table = dynamic_cast(tab_obj)->getParentTable(); schema = dynamic_cast(table->getSchema()); PgModelerNs::copyObject(&dup_object, tab_obj, obj_type); if(PhysicalTable::isPhysicalTable(table->getObjectType())) dup_object->setName(PgModelerNs::generateUniqueName(dup_object, *dynamic_cast(table)->getObjectList(obj_type), false, QString("_cp"))); else dup_object->setName(PgModelerNs::generateUniqueName(dup_object, *dynamic_cast(table)->getObjectList(obj_type), false, QString("_cp"))); op_id=op_list->registerObject(dup_object, Operation::ObjectCreated, -1, table); table->addObject(dup_object); // Flagging the table to be repainted if(!upd_tables.contains(table)) upd_tables.append(table); // Flagging the schema to be repainted if(!upd_schemas.contains(schema)) upd_schemas.append(schema); // Flagging the table to have the view references (relationships) updated if(!upd_view_ref_tables.contains(table) && obj_type == ObjectType::Column) upd_view_ref_tables.append(table); // Flagging the table to have its fk relationships updated else if(!upd_fk_rels.contains(table) && obj_type == ObjectType::Constraint && dynamic_cast(tab_obj)->getConstraintType() == ConstraintType::ForeignKey) upd_fk_rels.append(table); } op_list->finishOperationChain(); scene->clearSelection(); for(auto &tab : upd_tables) tab->setModified(true); for(auto &sch : upd_schemas) sch->setModified(true); for(auto &tab : upd_view_ref_tables) { db_model->validateRelationships(); db_model->updateViewsReferencingTable(dynamic_cast(tab)); } for(auto &tab : upd_fk_rels) db_model->updateTableFKRelationships(dynamic_cast
(tab)); this->setModified(true); emit s_objectCreated(); } else if(!selected_objects.empty()) { copyObjects(true); pasteObjects(true); } } catch(Exception &e) { //If operation was registered if(op_id >= 0) op_list->removeLastOperation(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::removeObjects(bool cascade) { int obj_idx=-1; unsigned count, op_count=0, obj_id=0; Table *aux_table=nullptr; BaseTable *table=nullptr, *src_table=nullptr, *dst_table=nullptr; BaseRelationship *rel=nullptr; TableObject *tab_obj=nullptr; ObjectType obj_type=ObjectType::BaseObject, parent_type=ObjectType::BaseObject; BaseObject *object=nullptr, *aux_obj=nullptr; vector sel_objs, aux_sel_objs; map> objs_map; map>::reverse_iterator ritr, ritr_end; QAction *obj_sender=dynamic_cast(sender()); QString obj_name, parent_name; vector errors; if(obj_sender) object=reinterpret_cast(obj_sender->data().value()); if(!object) sel_objs=selected_objects; else sel_objs.push_back(object); if(!sel_objs.empty()) { Messagebox msg_box; //Cancel the cut operation if the user try to delete an object in the middle of the process if(ModelWidget::cut_operation && (sender()==action_remove || sender()==action_cascade_del)) { ModelWidget::cut_operation=false; copied_objects.clear(); } //If the removal is not due to a cut operation, ask for permission to remove the objects if(!ModelWidget::cut_operation) { if(cascade) msg_box.show(trUtf8("CAUTION: You are about to delete objects in cascade mode which means more objects than the selected will be dropped too. Do you really want to proceed?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); else if(sel_objs.size() > 1) { msg_box.show(trUtf8("CAUTION: Remove multiple objects at once can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); } else { if(sel_objs[0]->getObjectType()==ObjectType::Relationship) msg_box.show(trUtf8("CAUTION: Remove a relationship can cause irreversible invalidations to other objects in the model causing such invalid objects to be deleted too. Do you really want to proceed?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); else msg_box.show(trUtf8("Do you really want to delete the selected object?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); } } //If the user confirmed the removal or its a cut operation if(msg_box.result()==QDialog::Accepted || ModelWidget::cut_operation) { try { //If in cascade mode, retrieve all references to the object (direct and indirect) if(cascade) { vector refs; for(BaseObject *sel_obj : sel_objs) { refs.clear(); db_model->__getObjectReferences(sel_obj, refs); for(BaseObject *ref_obj : refs) { obj_id=ref_obj->getObjectId(); tab_obj=dynamic_cast(ref_obj); //Store the base relationships in a auxiliary list to be processed ahead if(ref_obj->getObjectType()==ObjectType::BaseRelationship) { aux_sel_objs.push_back(ref_obj); } //Insert the reference object to the list of objects to be removed else if(objs_map.count(obj_id)==0 && (!tab_obj || (tab_obj && !tab_obj->isAddedByRelationship()))) { parent_type=(tab_obj ? tab_obj->getParentTable()->getObjectType() : ObjectType::Database); parent_name=(tab_obj ? tab_obj->getParentTable()->getName(true) : QString()); obj_name=(tab_obj ? tab_obj->getName() : ref_obj->getSignature()); objs_map[ref_obj->getObjectId()]=std::make_tuple(ref_obj, obj_name, ref_obj->getObjectType(), parent_name, parent_type); } } } } sel_objs.insert(sel_objs.end(), aux_sel_objs.begin(), aux_sel_objs.end()); for(BaseObject *object : sel_objs) { obj_type=object->getObjectType(); obj_id=object->getObjectId(); //If the object is as FK relationship remove the foreign keys that generates it if(obj_type==ObjectType::BaseRelationship) { rel = dynamic_cast(object); if(rel->getRelationshipType()==BaseRelationship::RelationshipFk) { tab_obj=rel->getReferenceForeignKey(); obj_id=tab_obj->getObjectId(); if(objs_map.count(obj_id)==0) { objs_map[tab_obj->getObjectId()]=std::make_tuple(tab_obj, tab_obj->getName(true), tab_obj->getObjectType(), tab_obj->getParentTable()->getName(true), ObjectType::Table); } } } else if(objs_map.count(obj_id)==0) { tab_obj=dynamic_cast(object); obj_name=(tab_obj ? object->getName(true) : object->getSignature()); parent_name=(tab_obj ? tab_obj->getParentTable()->getName(true) : QString()); parent_type=(tab_obj ? tab_obj->getParentTable()->getObjectType() : ObjectType::Database); objs_map[object->getObjectId()]=std::make_tuple(object, obj_name, obj_type, parent_name, parent_type); } } rel=nullptr; ritr=objs_map.rbegin(); ritr_end=objs_map.rend(); op_count=op_list->getCurrentSize(); op_list->startOperationChain(); do { object=std::get<0>(ritr->second); obj_name=std::get<1>(ritr->second); obj_type=std::get<2>(ritr->second); parent_name=std::get<3>(ritr->second); parent_type=std::get<4>(ritr->second); ritr++; if(obj_type==ObjectType::BaseRelationship) continue; else if(parent_type!=ObjectType::Database) { /* If the parent table does not exist on the model of the object to be removed * does not exists in parent table, it'll not be processed */ table=dynamic_cast(db_model->getObject(parent_name, parent_type)); if(!table || (table && table->getObjectIndex(obj_name, obj_type) < 0)) continue; } else { //If the object does not exists on the model it'll not be processed. aux_obj=db_model->getObject(obj_name, obj_type); if(aux_obj!=object) continue; } //Raises an error if the user try to remove a reserved object if(object->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(object->getName()).arg(object->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the user try to remove a protected object else if(object->isProtected()) { throw Exception(Exception::getErrorMessage(ErrorCode::RemProtectedObject) .arg(object->getName(true)) .arg(object->getTypeName()), ErrorCode::RemProtectedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { tab_obj=dynamic_cast(object); if(tab_obj) { if(tab_obj->isAddedByRelationship()) { throw Exception(Exception::getErrorMessage(ErrorCode::RemProtectedObject) .arg(tab_obj->getName(true)) .arg(tab_obj->getTypeName()), ErrorCode::RemProtectedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } table=dynamic_cast(tab_obj->getParentTable()); obj_idx=table->getObjectIndex(tab_obj->getName(true), obj_type); try { //If the object is a column validates the column removal before remove it if(!cascade && obj_type==ObjectType::Column) db_model->validateColumnRemoval(dynamic_cast(tab_obj)); //Register the removed object on the operation list table->removeObject(obj_idx, obj_type); op_list->registerObject(tab_obj, Operation::ObjectRemoved, obj_idx, table); db_model->removePermissions(tab_obj); aux_table=dynamic_cast
(table); if(aux_table && obj_type==ObjectType::Constraint && dynamic_cast(tab_obj)->getConstraintType()==ConstraintType::ForeignKey) db_model->updateTableFKRelationships(aux_table); table->setModified(true); dynamic_cast(table->getSchema())->setModified(true); if(aux_table) db_model->validateRelationships(tab_obj, aux_table); if(obj_type == ObjectType::Column) db_model->updateViewsReferencingTable(aux_table); } catch(Exception &e) { if(cascade && (e.getErrorCode()==ErrorCode::RemInvalidatedObjects || e.getErrorCode()==ErrorCode::RemDirectReference || e.getErrorCode()==ErrorCode::RemInderectReference || e.getErrorCode()==ErrorCode::RemProtectedObject || e.getErrorCode()==ErrorCode::OprReservedObject)) errors.push_back(e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } else { obj_idx=db_model->getObjectIndex(object); if(obj_idx >=0 ) { if(obj_type==ObjectType::Relationship) { rel=dynamic_cast(object); src_table=rel->getTable(BaseRelationship::SrcTable); dst_table=rel->getTable(BaseRelationship::DstTable); } try { db_model->removeObject(object, obj_idx); op_list->registerObject(object, Operation::ObjectRemoved, obj_idx); } catch(Exception &e) { if(cascade && (e.getErrorCode()==ErrorCode::RemInvalidatedObjects || e.getErrorCode()==ErrorCode::RemDirectReference || e.getErrorCode()==ErrorCode::RemInderectReference || e.getErrorCode()==ErrorCode::RemProtectedObject || e.getErrorCode()==ErrorCode::OprReservedObject)) errors.push_back(e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } if(rel) { src_table->setModified(true); dst_table->setModified(true); rel=nullptr; dst_table=src_table=nullptr; } } } } } while(ritr!=ritr_end); op_list->finishOperationChain(); scene->clearSelection(); this->configurePopupMenu(); this->modified=true; emit s_objectRemoved(); if(!errors.empty()) { msg_box.show(Exception(ErrorCode::RemInvalidatedObjects, __PRETTY_FUNCTION__,__FILE__,__LINE__, errors), trUtf8("The cascade deletion found some problems when running! Some objects could not be deleted or registered in the operation's history! Please, refer to error stack for more details."), Messagebox::AlertIcon); } } catch(Exception &e) { if(op_list->isOperationChainStarted()) op_list->finishOperationChain(); if(op_count < op_list->getCurrentSize()) { count=op_list->getCurrentSize()-op_count; op_list->ignoreOperationChain(true); for(unsigned i=0; i < count; i++) op_list->removeLastOperation(); op_list->ignoreOperationChain(false); } scene->clearSelection(); this->modified=true; emit s_objectRemoved(); msg_box.show(e); } /* In case of any object removal we clear the copied objects list in order to avoid * segfaults when trying to paste an object that was removed previously */ copied_objects.clear(); } } } void ModelWidget::removeObjectsCascade(void) { removeObjects(true); } void ModelWidget::editCustomSQL(void) { QAction *act=dynamic_cast(sender()); BaseObject *obj=reinterpret_cast(act->data().value()); CustomSQLWidget *customsql_wgt=new CustomSQLWidget; customsql_wgt->setAttributes(db_model, obj); this->modified=(openEditingForm(customsql_wgt)==QDialog::Accepted); } void ModelWidget::showObjectMenu(void) { BaseTableView *tab=nullptr; /* When the popup is hidden check if there is a table object (colum, constraint, etc) selected, if so, is necessary to reenable the table view deactivated before the menu activation */ if(this->selected_objects.size()==1) { //Get the selected table object TableObject *tab_obj=dynamic_cast(this->selected_objects[0]); if(tab_obj && tab_obj->getParentTable()) //Get the graphical representation for table tab=dynamic_cast(tab_obj->getParentTable()->getOverlyingObject()); } magnifier_area_lbl->hide(); popup_menu.exec(QCursor::pos()); //If the table object has a parent table if(tab) { //Reacitvates the table tab->setEnabled(true); //Calls the hoverLeaveEvent in order to hide the child selection tab->hoverLeaveEvent(nullptr); } } void ModelWidget::configureObjectMenu(BaseObject *object) { vector vet; vet.push_back(object); this->configurePopupMenu(vet); } void ModelWidget::enableModelActions(bool value) { action_source_code->setEnabled(value); action_edit->setEnabled(value); action_protect->setEnabled(value); action_unprotect->setEnabled(value); action_select_all->setEnabled(value); action_convert_relnn->setEnabled(value); action_deps_refs->setEnabled(value); action_new_object->setEnabled(value); action_copy->setEnabled(value); action_duplicate->setEnabled(value); action_paste->setEnabled(value); action_cut->setEnabled(value); action_remove->setEnabled(value); action_cascade_del->setEnabled(value); action_quick_actions->setEnabled(value); } void ModelWidget::configureSubmenu(BaseObject *object) { QAction *act=nullptr; vector sel_objs; ObjectType obj_type=ObjectType::BaseObject; bool tab_or_view=false, is_graph_obj = false, accepts_owner=false, accepts_schema=false; if(object) sel_objs.push_back(object); else sel_objs=selected_objects; /* Determining if one or more selected objects accepts schema, owner or are table/views, this is done to correctly show the actions to the user */ for(BaseObject *obj : sel_objs) { obj_type=obj->getObjectType(); if(!tab_or_view) tab_or_view=BaseTable::isBaseTable(obj_type); if(!is_graph_obj) is_graph_obj = BaseGraphicObject::isGraphicObject(obj_type); if(!accepts_owner) accepts_owner=obj->acceptsOwner(); if(!accepts_schema) accepts_schema=obj->acceptsSchema(); if(tab_or_view && accepts_owner && accepts_schema) break; } if(!sel_objs.empty()) { if(accepts_owner || accepts_schema) { vector obj_list; map act_map; QStringList name_list; QMenu *menus[]={ &schemas_menu, &owners_menu, &tags_menu }; ObjectType types[]={ ObjectType::Schema, ObjectType::Role, ObjectType::Tag }; for(unsigned i=0; i < 3; i++) { menus[i]->clear(); //Configuring actions "Move to schema", "Change Owner" and "Set tag" if((types[i] == ObjectType::Schema && accepts_schema) || (types[i] == ObjectType::Role && accepts_owner) || (types[i]==ObjectType::Tag && tab_or_view)) { obj_list=db_model->getObjects(types[i]); if(obj_list.empty()) { menus[i]->addAction(trUtf8("(no objects)")); menus[i]->actions().at(0)->setEnabled(false); } else { if(types[i] == ObjectType::Tag) { menus[i]->addAction(trUtf8("None"), this, SLOT(setTag())); menus[i]->addSeparator(); } while(!obj_list.empty()) { act=new QAction(obj_list.back()->getName(), menus[i]); act->setIcon(QPixmap(PgModelerUiNs::getIconPath(types[i]))); /* Check the current action only if there is only one selected object and the object representing the action is assigned to the selected object */ act->setCheckable(sel_objs.size()==1); act->setChecked(sel_objs.size()==1 && (object->getSchema()==obj_list.back() || object->getOwner()==obj_list.back() || (tab_or_view && dynamic_cast(sel_objs[0])->getTag()==obj_list.back()))); act->setEnabled(!act->isChecked()); act->setData(QVariant::fromValue(obj_list.back())); if(i==0) connect(act, SIGNAL(triggered(bool)), this, SLOT(moveToSchema(void))); else if(i==1) connect(act, SIGNAL(triggered(bool)), this, SLOT(changeOwner(void))); else connect(act, SIGNAL(triggered(bool)), this, SLOT(setTag(void))); act_map[obj_list.back()->getName()]=act; name_list.push_back(obj_list.back()->getName()); obj_list.pop_back(); } name_list.sort(); while(!name_list.isEmpty()) { menus[i]->addAction(act_map[name_list.front()]); name_list.pop_front(); } act_map.clear(); } } } } // Configuring the layers menu if(is_graph_obj) { unsigned layer_id = ObjectsScene::DefaultLayer; layers_menu.clear(); for(auto &layer : scene->getLayers()) { act = layers_menu.addAction(layer); act->setData(layer_id++); connect(act, SIGNAL(triggered(bool)), this, SLOT(moveToLayer())); } } //Display the quick rename action is a single object is selected if(object && obj_type!=ObjectType::Cast) { quick_actions_menu.addAction(action_rename); action_rename->setData(QVariant::fromValue(object)); } if(accepts_schema) quick_actions_menu.addAction(action_moveto_schema); if(is_graph_obj) quick_actions_menu.addAction(action_moveto_layer); if(accepts_owner) quick_actions_menu.addAction(action_change_owner); if(tab_or_view) quick_actions_menu.addAction(action_set_tag); if(object && Permission::acceptsPermission(obj_type)) { quick_actions_menu.addAction(action_edit_perms); action_edit_perms->setData(QVariant::fromValue(object)); } if(object && PhysicalTable::isPhysicalTable(obj_type)) quick_actions_menu.addAction(action_edit_data); if(object && BaseObject::acceptsCustomSQL(obj_type)) { action_append_sql->setData(QVariant::fromValue(object)); quick_actions_menu.addAction(action_append_sql); } if(object && ((!TableObject::isTableObject(obj_type) && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::BaseRelationship) || (TableObject::isTableObject(obj_type) && !dynamic_cast(object)->isAddedByRelationship()))) { action_enable_sql->setData(QVariant::fromValue(object)); action_disable_sql->setData(QVariant::fromValue(object)); if(object->isSQLDisabled()) quick_actions_menu.addAction(action_enable_sql); else quick_actions_menu.addAction(action_disable_sql); } //Include the quick actions if it is not empty and the model is not protected if(!db_model->isProtected() && !quick_actions_menu.isEmpty()) popup_menu.addAction(action_quick_actions); } } void ModelWidget::configureFadeMenu(void) { bool is_db_selected = (selected_objects.empty() || (selected_objects.size() == 1 && selected_objects[0]->getObjectType() == ObjectType::Database)); fade_menu.clear(); fade_in_menu.clear(); fade_out_menu.clear(); if(is_db_selected || (selected_objects.size() > 1 && !scene->hasOnlyTableChildrenSelection())) { fade_menu.addAction(action_fade_in); fade_menu.addAction(action_fade_out); action_fade_in->setMenu(&fade_in_menu); action_fade_out->setMenu(&fade_out_menu); if(is_db_selected) { QAction *action = nullptr; vector types = { ObjectType::Schema, ObjectType::Table, ObjectType::View, ObjectType::Relationship, ObjectType::Textbox }; QStringList labels = { trUtf8("Schemas"), trUtf8("Tables"), trUtf8("Views"), trUtf8("Relationships"), trUtf8("Textboxes") }; unsigned id = 0; for(ObjectType type : types) { action = new QAction(QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(type) + QString("_grp"))), labels[id], &fade_in_menu); action->setData(enum_cast(type)); fade_in_menu.addAction(action); connect(action, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsIn())); action = new QAction(QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(type) + QString("_grp"))), labels[id], &fade_out_menu); action->setData(enum_cast(type)); fade_out_menu.addAction(action); id++; connect(action, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsOut())); } action = new QAction(trUtf8("All objects"), &fade_in_menu); action->setData(enum_cast(ObjectType::BaseObject)); connect(action, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsIn())); fade_in_menu.addSeparator(); fade_in_menu.addAction(action); action = new QAction(trUtf8("All objects"), &fade_out_menu); action->setData(enum_cast(ObjectType::BaseObject)); connect(action, SIGNAL(triggered(bool)), this, SLOT(fadeObjectsOut())); fade_out_menu.addSeparator(); fade_out_menu.addAction(action); } else { action_fade_in->setMenu(nullptr); action_fade_out->setMenu(nullptr); } } else if(selected_objects.size() == 1) { ObjectType obj_type = selected_objects[0]->getObjectType(); if(obj_type == ObjectType::Tag) { fade_menu.addAction(action_fade_in); fade_menu.addAction(action_fade_out); action_fade_in->setMenu(nullptr); action_fade_out->setMenu(nullptr); } else { BaseObjectView *obj_view = dynamic_cast(dynamic_cast(selected_objects[0])->getOverlyingObject()); if(obj_view) { if(obj_view->opacity() == 1) { fade_menu.addAction(action_fade_out); action_fade_out->setMenu(nullptr); } else { fade_menu.addAction(action_fade_in); action_fade_in->setMenu(nullptr); } } if(obj_type == ObjectType::Table || obj_type == ObjectType::View) { fade_menu.addAction(action_fade_rels); action_fade_rels->setText(trUtf8("Table && Relationships")); } } } } void ModelWidget::fadeObjects(const vector &objects, bool fade_in) { BaseObjectView *obj_view = nullptr; Schema *schema = nullptr; for(auto obj : objects) { schema = dynamic_cast(obj); if(!BaseGraphicObject::isGraphicObject(obj->getObjectType()) || (schema && !schema->isRectVisible())) continue; obj_view = dynamic_cast(dynamic_cast(obj)->getOverlyingObject()); if(obj_view) { dynamic_cast(obj)->setFadedOut(!fade_in); obj_view->setOpacity(fade_in ? 1 : min_object_opacity); //If the minimum opacity is zero the object hidden obj_view->setVisible(scene->isLayerActive(obj_view->getLayer()) && (fade_in || (!fade_in && min_object_opacity > 0))); this->modified = true; } } scene->clearSelection(); } void ModelWidget::fadeObjects(QAction *action, bool fade_in) { if(!action) return; vector list; //If the database object is selected or there is no object select if(selected_objects.empty() || (selected_objects.size() == 1 && selected_objects[0]->getObjectType() == ObjectType::Database)) { ObjectType obj_type = static_cast(action->data().toUInt()); //If the action contains a data of type ObjectType::ObjBaseObject means that the user wants to fade all objects if(obj_type == ObjectType::BaseObject) { vector types = { ObjectType::Schema, ObjectType::Table, ObjectType::View, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Textbox}; for(ObjectType type : types) { list.insert(list.end(), db_model->getObjectList(type)->begin(), db_model->getObjectList(type)->end()); } } else { //Fading objects of a certain type list = *db_model->getObjectList(obj_type); if(obj_type == ObjectType::Relationship) { list.insert(list.end(), db_model->getObjectList(ObjectType::BaseRelationship)->begin(), db_model->getObjectList(ObjectType::BaseRelationship)->end()); } } } else { //For tag object the fade is applied in the tables/views related to it if(selected_objects.size() == 1 && selected_objects[0]->getObjectType() == ObjectType::Tag) db_model->getObjectReferences(selected_objects[0], list); else { if(action == action_fade_rels_in || action == action_fade_rels_out) { //Applying fade to the relationships linked to the selected table/view vector rel_list = db_model->getRelationships(dynamic_cast(selected_objects[0])); for(auto rel : rel_list) { list.push_back(rel); list.push_back(rel->getTable(BaseRelationship::SrcTable)); list.push_back(rel->getTable(BaseRelationship::DstTable)); } vector::iterator end; std::sort(list.begin(), list.end()); end=std::unique(list.begin(), list.end()); list.erase(end, list.end()); } else //Applying fade to the selected objects list = selected_objects; } } fadeObjects(list, fade_in); scene->clearSelection(); } void ModelWidget::fadeObjectsIn(void) { fadeObjects(qobject_cast(sender()), true); } void ModelWidget::fadeObjectsOut(void) { fadeObjects(qobject_cast(sender()), false); } void ModelWidget::setAllCollapseMode(CollapseMode mode) { BaseTable *base_tab = nullptr; vector objects; this->scene->clearSelection(); objects.assign(db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::View)->begin(), db_model->getObjectList(ObjectType::View)->end()); for(auto obj : objects) { base_tab = dynamic_cast(obj); if(base_tab) base_tab->setCollapseMode(mode); } this->setModified(true); } void ModelWidget::setCollapseMode(void) { CollapseMode mode = static_cast(dynamic_cast(sender())->data().toUInt()); BaseTable *base_tab = nullptr; vector objects; if(selected_objects.empty() || (selected_objects.size() == 1 && selected_objects[0] == db_model)) { objects.assign(db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::ForeignTable)->begin(), db_model->getObjectList(ObjectType::ForeignTable)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::View)->begin(), db_model->getObjectList(ObjectType::View)->end()); } else objects = selected_objects; for(auto obj : objects) { base_tab = dynamic_cast(obj); if(base_tab && base_tab->getCollapseMode() != mode) { base_tab->setCollapseMode(mode); base_tab->setModified(true); } } db_model->setObjectsModified({ ObjectType::Schema }); this->setModified(true); } void ModelWidget::togglePagination(void) { bool enable = dynamic_cast(sender())->data().toBool(); BaseTable *base_tab = nullptr; vector objects; if(selected_objects.empty() || (selected_objects.size() == 1 && selected_objects[0] == db_model)) { objects.assign(db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::ForeignTable)->begin(), db_model->getObjectList(ObjectType::ForeignTable)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::View)->begin(), db_model->getObjectList(ObjectType::View)->end()); } else objects = selected_objects; for(auto obj : objects) { base_tab = dynamic_cast(obj); if(base_tab && base_tab->isPaginationEnabled() != enable) { base_tab->setPaginationEnabled(enable); base_tab->setModified(true); } } db_model->setObjectsModified({ ObjectType::Schema }); this->setModified(true); } void ModelWidget::toggleSchemasRectangles(void) { bool visible = sender() == action_show_schemas_rects; Schema *schema = nullptr; for(auto obj : *db_model->getObjectList(ObjectType::Schema)) { schema = dynamic_cast(obj); if(schema && schema->isRectVisible() != visible) { schema->setRectVisible(visible); schema->setModified(true); } } this->setModified(true); } void ModelWidget::updateObjectsOpacity(void) { vector types = { ObjectType::Schema, ObjectType::Table, ObjectType::View, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Textbox}; BaseObjectView *obj_view = nullptr; BaseGraphicObject *base_obj = nullptr; for(auto type : types) { for(auto object : *db_model->getObjectList(type)) { base_obj = dynamic_cast(object); obj_view = dynamic_cast(base_obj->getOverlyingObject()); if(obj_view && ((base_obj->isFadedOut() && obj_view->opacity() == 1) || (obj_view->opacity() < 1.0 && obj_view->opacity() != min_object_opacity))) { obj_view->setOpacity(min_object_opacity); obj_view->setVisible(min_object_opacity > 0); } } } } void ModelWidget::configurePopupMenu(const vector &objects) { QMenu *submenu=nullptr; PhysicalTable *table=nullptr; unsigned count, i; vector submenus; Constraint *constr=nullptr; QAction *action=nullptr; TableObject *tab_obj=nullptr; QString str_aux; bool protected_obj=false, model_protected=db_model->isProtected(); new_object_menu.clear(); quick_actions_menu.clear(); popup_menu.clear(); this->enableModelActions(false); this->selected_objects=objects; new_object_menu.setEnabled(!this->db_model->isProtected()); if(objects.size() <= 1) { //Case there is no selected object or the selected object is the database model if(objects.empty() || (objects.size()==1 && objects[0]==db_model)) { new_object_menu.addAction(action_database_category); new_object_menu.addAction(action_schema_category); new_object_menu.addAction(actions_new_objects[ObjectType::Relationship]); new_object_menu.addAction(actions_new_objects[ObjectType::GenericSql]); new_object_menu.addAction(actions_new_objects[ObjectType::Tag]); new_object_menu.addAction(actions_new_objects[ObjectType::Textbox]); action_new_object->setMenu(&new_object_menu); popup_menu.addAction(action_new_object); configureSubmenu(db_model); action_edit->setData(QVariant::fromValue(dynamic_cast(db_model))); action_source_code->setData(QVariant::fromValue(dynamic_cast(db_model))); popup_menu.addAction(action_edit); popup_menu.addSeparator(); popup_menu.addAction(action_source_code); if(db_model->isProtected()) popup_menu.addAction(action_unprotect); else popup_menu.addAction(action_protect); if(scene->items().count() > 1) popup_menu.addAction(action_select_all); } else if(objects.size()==1) { BaseObject *obj=objects[0]; BaseRelationship *rel=dynamic_cast(obj); ObjectType obj_type=obj->getObjectType(); configureSubmenu(obj); popup_menu.addAction(action_edit); if((obj_type==ObjectType::Schema && obj->isSystemObject()) || (!obj->isProtected() && (BaseTable::isBaseTable(obj_type) || obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Relationship || obj_type==ObjectType::Schema || obj_type == ObjectType::Tag))) { if(BaseTable::isBaseTable(obj_type)) { for(auto type : BaseObject::getChildObjectTypes(obj_type)) new_object_menu.addAction(actions_new_objects[type]); if(obj_type==ObjectType::Table) new_object_menu.addAction(actions_new_objects[ObjectType::Relationship]); action_new_object->setMenu(&new_object_menu); popup_menu.insertAction(action_quick_actions, action_new_object); } else if(obj_type==ObjectType::Relationship || obj_type==ObjectType::BaseRelationship) { if(obj_type==ObjectType::Relationship) { new_object_menu.addAction(actions_new_objects[ObjectType::Column]); new_object_menu.addAction(actions_new_objects[ObjectType::Constraint]); action_new_object->setMenu(&new_object_menu); popup_menu.insertAction(action_quick_actions, action_new_object); } if(rel->getRelationshipType()==Relationship::RelationshipNn) { action_convert_relnn->setData(QVariant::fromValue(rel)); popup_menu.addAction(action_convert_relnn); } if(!rel->isSelfRelationship()) { if(rel->getPoints().empty()) { action_break_rel_line->setData(QVariant::fromValue(rel)); popup_menu.addAction(action_break_rel_line); } else { action_remove_rel_points->setData(QVariant::fromValue(rel)); popup_menu.addAction(action_remove_rel_points); } popup_menu.addAction(action_jump_to_table); jump_to_tab_menu.clear(); action = jump_to_tab_menu.addAction(QIcon(PgModelerUiNs::getIconPath(rel->getTable(BaseRelationship::SrcTable)->getObjectType())), rel->getTable(BaseRelationship::SrcTable)->getSignature(), this, SLOT(jumpToTable())); action->setData(QVariant::fromValue(reinterpret_cast(rel->getTable(BaseRelationship::SrcTable)))); action = jump_to_tab_menu.addAction(QIcon(PgModelerUiNs::getIconPath(rel->getTable(BaseRelationship::DstTable)->getObjectType())), rel->getTable(BaseRelationship::DstTable)->getSignature(), this, SLOT(jumpToTable())); action->setData(QVariant::fromValue(reinterpret_cast(rel->getTable(BaseRelationship::DstTable)))); } } else if(obj_type == ObjectType::Schema) { for(auto type : BaseObject::getChildObjectTypes(ObjectType::Schema)) new_object_menu.addAction(actions_new_objects[type]); action_new_object->setMenu(&new_object_menu); popup_menu.insertAction(action_quick_actions, action_new_object); popup_menu.addAction(action_sel_sch_children); action_sel_sch_children->setData(QVariant::fromValue(obj)); } else if(obj_type == ObjectType::Tag) { popup_menu.addAction(action_sel_tagged_tabs); action_sel_tagged_tabs->setData(QVariant::fromValue(obj)); } } /* Adding the action to highlight the object only when the sender is not one of the the objects that calls this method from inside the ModelWidget instance. This action is mainly used when the user wants to find a graphical object from the ModelObjects dockwidget*/ if((sender()!=this && sender()!=scene) && dynamic_cast(obj)) { popup_menu.addAction(action_select_object); action_select_object->setData(QVariant::fromValue(obj)); } action_edit->setData(QVariant::fromValue(obj)); action_source_code->setData(QVariant::fromValue(obj)); action_deps_refs->setData(QVariant::fromValue(obj)); tab_obj=dynamic_cast(obj); if(tab_obj && tab_obj->getObjectType()==ObjectType::Column) { Column *col=dynamic_cast(tab_obj); if(tab_obj->isAddedByRelationship()) { action_parent_rel->setData(QVariant::fromValue(dynamic_cast(tab_obj)->getParentRelationship())); popup_menu.addAction(action_parent_rel); } else if(col->getType().isSerialType()) { action_create_seq_col->setData(QVariant::fromValue(col)); popup_menu.addAction(action_create_seq_col); } else if(col->getType().isIntegerType()) { action_conv_int_serial->setData(QVariant::fromValue(col)); popup_menu.addAction(action_conv_int_serial); } } popup_menu.addSeparator(); popup_menu.addAction(action_source_code); if(!tab_obj || (tab_obj && !tab_obj->isAddedByRelationship())) popup_menu.addAction(action_deps_refs); } } else { configureSubmenu(nullptr); } if(objects.size() > 1) { bool rem_points = true; for(auto &obj : objects) { rem_points = obj->getObjectType() == ObjectType::Relationship || obj->getObjectType() == ObjectType::BaseRelationship; if(!rem_points) break; } if(rem_points) { action_remove_rel_points->setData(QVariant()); popup_menu.addAction(action_remove_rel_points); } } /* Adds the protect/unprotect action when the selected object was not included by relationship and if its a table object and the parent table is not protected. */ if(!objects.empty() && !this->db_model->isProtected() && (!tab_obj || (tab_obj && !tab_obj->getParentTable()->isProtected() && !tab_obj->isAddedByRelationship()))) { /* Special case for systema objects: The actions protect/unprotect will be displayed only for system schemas. The rest of system objects those actions aren't available */ if(!objects[0]->isSystemObject() || (objects[0]->isSystemObject() && objects[0]->getObjectType()==ObjectType::Schema)) { if(!objects[0]->isProtected()) popup_menu.addAction(action_protect); else popup_menu.addAction(action_unprotect); } } //Adding the extended attributes action (only for table/view/database) if(objects.size() > 1 || (objects.empty() && (db_model->getObjectCount(ObjectType::Table) > 0 || db_model->getObjectCount(ObjectType::ForeignTable) > 0 || db_model->getObjectCount(ObjectType::View) > 0)) || (objects.size() == 1 && (BaseTable::isBaseTable(objects[0]->getObjectType()) || objects[0]->getObjectType() == ObjectType::Database))) { bool tab_or_view = false; for(BaseObject *obj : objects) { if(!tab_or_view) { tab_or_view=(PhysicalTable::isPhysicalTable(obj->getObjectType()) || obj->getObjectType()==ObjectType::View); break; } } if(tab_or_view || objects.empty() || objects.size() == 1) { popup_menu.addAction(action_collapse_mode); popup_menu.addAction(action_pagination); } if(objects.empty() || (objects.size() == 1 && objects[0]->getObjectType() == ObjectType::Database)) popup_menu.addAction(action_schemas_rects); } if(!tab_obj && (objects.empty() || (objects.size() > 1 && !scene->hasOnlyTableChildrenSelection()) || (objects.size() == 1 && (objects[0]->getObjectType() == ObjectType::Database || objects[0]->getObjectType() == ObjectType::Tag || BaseGraphicObject::isGraphicObject(objects[0]->getObjectType()))))) { //Adding fade inout action only for graphical objects or when there is no objects selected or many objects seleted popup_menu.addAction(action_fade); popup_menu.addSeparator(); configureFadeMenu(); } //Adding the copy and paste if there is selected objects if(!model_protected && !(objects.size()==1 && (objects[0]==db_model || objects[0]->getObjectType()==ObjectType::BaseRelationship)) && !objects.empty()) { popup_menu.addAction(action_copy); count=objects.size(); i=0; while(i < count && !protected_obj) protected_obj=objects[i++]->isProtected(); if(!tab_obj || (tab_obj && !tab_obj->isAddedByRelationship())) popup_menu.addAction(action_cut); popup_menu.addAction(action_duplicate); } //If there is copied object adds the paste action if(!model_protected && !copied_objects.empty()) popup_menu.addAction(action_paste); /* Adding the delete object action. This action will be unavailable on following conditions: 1) The selected object is the database itself 2) The object is protected 3) The object is table child object and it was added by relationship 4) The object is a base relationship (table-view) */ if((tab_obj && !tab_obj->isAddedByRelationship() && !tab_obj->isProtected()) || (objects.size()==1 && objects[0]->isProtected()) || (!tab_obj && objects.size()==1 && objects[0]!=db_model && objects[0]->getObjectType()!=ObjectType::BaseRelationship) || (objects.size()==1 && objects[0]->getObjectType()==ObjectType::BaseRelationship && dynamic_cast(objects[0])->getRelationshipType()==BaseRelationship::RelationshipFk) || objects.size() > 1) { popup_menu.addAction(action_remove); popup_menu.addAction(action_cascade_del); } //If the table object is a column creates a special menu to acess the constraints that is applied to the column if(tab_obj) { table=dynamic_cast(tab_obj->getParentTable()); if(tab_obj->getObjectType()==ObjectType::Column) { count=table->getConstraintCount(); for(i=0; i < count; i++) { constr=table->getConstraint(i); if(constr->isColumnReferenced(dynamic_cast(tab_obj), false)) { switch(!constr->getConstraintType()) { case ConstraintType::PrimaryKey: str_aux=QString("_%1").arg(TableObjectView::TextPrimaryKey); break; case ConstraintType::ForeignKey: str_aux=QString("_%1").arg(TableObjectView::TextForeignKey); break; case ConstraintType::Check: str_aux=QString("_%1").arg(TableObjectView::TextCheck); break; case ConstraintType::Unique: str_aux=QString("_%1").arg(TableObjectView::TextUnique); break; case ConstraintType::Exclude: str_aux=QString("_%1").arg(TableObjectView::TextExclude); break; } //For each constaint is created a menu with the edit, source code, protect/unprotect and delete actions submenu=new QMenu(&popup_menu); submenu->setIcon(QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(ObjectType::Constraint) + str_aux))); submenu->setTitle(constr->getName()); action=new QAction(dynamic_cast(submenu)); action->setIcon(QPixmap(PgModelerUiNs::getIconPath("editar"))); action->setText(trUtf8("Properties")); action->setData(QVariant::fromValue(dynamic_cast(constr))); connect(action, SIGNAL(triggered(bool)), this, SLOT(editObject(void))); submenu->addAction(action); action=new QAction(dynamic_cast(submenu)); action->setIcon(QPixmap(PgModelerUiNs::getIconPath("codigosql"))); action->setText(trUtf8("Source code")); action->setData(QVariant::fromValue(dynamic_cast(constr))); connect(action, SIGNAL(triggered(bool)), this, SLOT(showSourceCode(void))); submenu->addAction(action); if(!constr->isAddedByRelationship()) { if(!constr->getParentTable()->isProtected()) { action=new QAction(dynamic_cast(&popup_menu)); action->setData(QVariant::fromValue(dynamic_cast(constr))); connect(action, SIGNAL(triggered(bool)), this, SLOT(protectObject(void))); submenu->addAction(action); if(constr->isProtected()) { action->setIcon(QPixmap(PgModelerUiNs::getIconPath("desbloqobjeto"))); action->setText(trUtf8("Unprotect")); } else { action->setIcon(QPixmap(PgModelerUiNs::getIconPath("bloqobjeto"))); action->setText(trUtf8("Protect")); } } action=new QAction(dynamic_cast(submenu)); action->setIcon(QPixmap(PgModelerUiNs::getIconPath("excluir"))); action->setData(QVariant::fromValue(dynamic_cast(constr))); action->setText(trUtf8("Delete")); submenu->addAction(action); connect(action, SIGNAL(triggered()), this, SLOT(removeObjects())); action=new QAction(dynamic_cast(submenu)); action->setIcon(QPixmap(PgModelerUiNs::getIconPath("delcascade"))); action->setData(QVariant::fromValue(dynamic_cast(constr))); action->setText(trUtf8("Del. cascade")); submenu->addAction(action); connect(action, SIGNAL(triggered()), this, SLOT(removeObjectsCascade())); } submenus.push_back(submenu); } } //Adding the constraint submenus to the main popup menu if(!submenus.empty()) { submenu=new QMenu(&popup_menu); submenu->setTitle(trUtf8("Constraints")); submenu->setIcon(QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(ObjectType::Constraint) + QString("_grp")))); count=submenus.size(); for(i=0; i < count; i++) submenu->addMenu(submenus[i]); popup_menu.insertMenu(action_edit, submenu); } } } //Enable the popup actions that are visible QList actions=popup_menu.actions(); actions.append(quick_actions_menu.actions()); while(!actions.isEmpty()) { actions.back()->setEnabled(true); actions.pop_back(); } if(objects.size() <= 2 && !scene->hasOnlyTableChildrenSelection()) { popup_menu.addSeparator(); popup_menu.addAction(action_edit_creation_order); } } bool ModelWidget::isModified(void) { return(modified); } DatabaseModel *ModelWidget::getDatabaseModel(void) { return(db_model); } ObjectsScene *ModelWidget::getObjectsScene(void) { return(scene); } QGraphicsView *ModelWidget::getViewport(void) { return(viewport); } OperationList *ModelWidget::getOperationList(void) { return(op_list); } void ModelWidget::setSaveLastCanvasPosition(bool value) { ModelWidget::save_restore_pos=value; } void ModelWidget::setRenderSmoothnessDisabled(bool value) { ModelWidget::disable_render_smooth=value; } void ModelWidget::setSimplifiedObjectCreation(bool value) { ModelWidget::simple_obj_creation=value; } void ModelWidget::setMinimumObjectOpacity(unsigned min_opacity) { if(min_opacity > 70) min_opacity = 70; ModelWidget::min_object_opacity = static_cast(min_opacity)/100.0; } void ModelWidget::highlightObject(void) { QAction *action=dynamic_cast(sender()); if(action ) { BaseObject *obj=reinterpret_cast(action->data().value()); BaseGraphicObject *graph_obj=dynamic_cast(obj); if(graph_obj) { BaseObjectView *obj_view=dynamic_cast(graph_obj->getOverlyingObject()); scene->clearSelection(); obj_view->setSelected(true); viewport->centerOn(obj_view); } } } void ModelWidget::toggleNewObjectOverlay(void) { if(new_obj_overlay_wgt->isHidden() && (selected_objects.empty() || selected_objects[0]->getObjectType()!=ObjectType::BaseRelationship)) { new_obj_overlay_wgt->raise(); new_obj_overlay_wgt->show(); new_obj_overlay_wgt->setSelectedObjects(selected_objects); this->adjustOverlayPosition(); } else new_obj_overlay_wgt->hide(); } void ModelWidget::adjustOverlayPosition(void) { int px=0, py=0; px=(this->width()/2) - (new_obj_overlay_wgt->width()/2); py=(this->height()/2) - (new_obj_overlay_wgt->height()/2); new_obj_overlay_wgt->move(px, py); } void ModelWidget::toggleObjectSQL(void) { QAction *action=dynamic_cast(sender()); if(action) { BaseObject *object=reinterpret_cast(action->data().value()); PgModelerUiNs::disableObjectSQL(object, !object->isSQLDisabled()); this->modified=true; emit s_objectModified(); } } void ModelWidget::createSequenceFromColumn(void) { try { QAction *action=dynamic_cast(sender()); Column *col=reinterpret_cast(action->data().value()); Sequence *seq=nullptr; Table *tab=dynamic_cast
(col->getParentTable()); op_list->startOperationChain(); //Creates a sequence which name is like the ones auto generated by PostgreSQL seq=new Sequence; seq->setName(BaseObject::formatName(tab->getName() + QString("_") + col->getName() + QString("_seq"))); seq->setName(PgModelerNs::generateUniqueName(seq, *db_model->getObjectList(ObjectType::Sequence), false)); seq->setSchema(tab->getSchema()); seq->setDefaultValues(col->getType()); op_list->registerObject(seq, Operation::ObjectCreated); db_model->addSequence(seq); BaseObject::swapObjectsIds(tab, seq, false); op_list->registerObject(col, Operation::ObjectModified, -1, tab); //Changes the column type to the alias for serial type col->setType(col->getType().getAliasType()); col->setSequence(seq); op_list->finishOperationChain(); //Revalidate the relationships since the modified column can be a primary key if(tab->getPrimaryKey() && tab->getPrimaryKey()->isColumnReferenced(col)) db_model->validateRelationships(); tab->setModified(true); this->setModified(true); emit s_objectCreated(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::convertIntegerToSerial(void) { try { QAction *action=dynamic_cast(sender()); Column *col=reinterpret_cast(action->data().value()); Table *tab=dynamic_cast
(col->getParentTable()); PgSqlType col_type=col->getType(); QRegExp regexp(QString("^nextval\\(.+\\:\\:regclass\\)")); QString serial_tp; if(!col_type.isIntegerType() || (!col->getDefaultValue().contains(regexp) && !col->getSequence())) throw Exception(Exception::getErrorMessage(ErrorCode::InvConversionIntegerToSerial).arg(col->getName()), ErrorCode::InvConversionIntegerToSerial ,__PRETTY_FUNCTION__,__FILE__,__LINE__); op_list->registerObject(col, Operation::ObjectModified, -1, tab); if(col_type==QString("integer") || col_type==QString("int4")) serial_tp=QString("serial"); else if(col_type==QString("smallint") || col_type==QString("int2")) serial_tp=QString("smallserial"); else serial_tp=QString("bigserial"); col->setType(PgSqlType(serial_tp)); col->setDefaultValue(QString()); //Revalidate the relationships since the modified column can be a primary key if(tab->getPrimaryKey()->isColumnReferenced(col)) db_model->validateRelationships(); tab->setModified(true); emit s_objectModified(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::breakRelationshipLine(void) { try { QAction *action=dynamic_cast(sender()); BaseRelationship *rel=dynamic_cast(selected_objects[0]); op_list->registerObject(rel, Operation::ObjectModified); breakRelationshipLine(rel, action->data().toUInt()); rel->setModified(true); this->setModified(true); emit s_objectModified(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::breakRelationshipLine(BaseRelationship *rel, unsigned break_type) { if(!rel) return; try { RelationshipView *rel_view=dynamic_cast(rel->getOverlyingObject()); double dx, dy; QPointF src_pnt, dst_pnt; src_pnt=rel_view->getConnectionPoint(BaseRelationship::SrcTable); dst_pnt=rel_view->getConnectionPoint(BaseRelationship::DstTable); if(break_type==BreakVertNinetyDegrees) rel->setPoints({ QPointF(src_pnt.x(), dst_pnt.y()) }); else if(break_type==BreakHorizNinetyDegrees) rel->setPoints({ QPointF(dst_pnt.x(), src_pnt.y()) }); else if(break_type==BreakHoriz2NinetyDegrees) { //Calculates the midle vertical point between the tables centers dy=(src_pnt.y() + dst_pnt.y())/2; //Adds two points on the middle space between tables creating two 90° angles rel->setPoints({ QPointF(src_pnt.x(), dy), QPointF(dst_pnt.x(), dy) }); } else { //Calculates the middle horizontal point between the tables centers dx=(src_pnt.x() + dst_pnt.x())/2; //Adds two points on the middle space between tables creating two 90° angles rel->setPoints({ QPointF(dx, src_pnt.y()), QPointF(dx, dst_pnt.y()) }); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::removeRelationshipPoints(void) { try { QAction *action=dynamic_cast(sender()); BaseRelationship *rel=reinterpret_cast(action->data().value()); //Remove points from all selected relationships if(!rel && !selected_objects.empty()) { vector rels; rels = *db_model->getObjectList(ObjectType::BaseRelationship); rels.insert(rels.end(), db_model->getObjectList(ObjectType::Relationship)->begin(), db_model->getObjectList(ObjectType::Relationship)->end()); op_list->startOperationChain(); for(auto &obj : rels) { rel = dynamic_cast(obj); if(!rel->isProtected()) { op_list->registerObject(rel, Operation::ObjectModified); rel->setPoints({}); rel->setModified(true); } } op_list->finishOperationChain(); } else { op_list->registerObject(rel, Operation::ObjectModified); rel->setPoints({}); rel->setModified(true); } scene->clearSelection(); this->setModified(true); emit s_objectModified(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ModelWidget::rearrangeSchemasInGrid(unsigned tabs_per_row, unsigned sch_per_row, QPointF origin, double obj_spacing) { vector *objects=nullptr; Schema *schema=nullptr; SchemaView *sch_view=nullptr; unsigned sch_id=0, min_cnt = 0; double x=origin.x(), y=origin.y(), max_y=-1, cy=0; objects=db_model->getObjectList(ObjectType::Schema); /* If schemas per row or tables per row isn't specified * we calculate an minimal number of objects to be arranged per row */ if(sch_per_row == 0) { min_cnt = objects->size() * 0.10; sch_per_row = min_cnt < 3 ? 3 : min_cnt; } if(tabs_per_row == 0) { min_cnt = (db_model->getObjectCount(ObjectType::Table) + db_model->getObjectCount(ObjectType::View) + db_model->getObjectCount(ObjectType::ForeignTable)) * 0.05; tabs_per_row = min_cnt < 5 ? 5 : min_cnt; } for(BaseObject *obj : *objects) { schema=dynamic_cast(obj); /* Forcing the schema rectangle to be visible in order to correctly positioin schemas over the screen */ schema->setRectVisible(true); sch_view=dynamic_cast(schema->getOverlyingObject()); schema->setModified(true); //The schema is processed only there are tables inside of it if(sch_view && sch_view->getChildrenCount() > 0) { //Organizing the tables inside the schema rearrangeTablesInGrid(schema, tabs_per_row, QPointF(x,y), obj_spacing); schema->setModified(true); cy=sch_view->pos().y() + sch_view->boundingRect().height(); //Defining the maximum y position to avoid schema boxes colliding vertically if(max_y < cy) max_y=cy; sch_id++; //It the current schema is the last of it`s row if(sch_id >= sch_per_row) { //Incrementing the row position sch_id=0; y=max_y + obj_spacing; x=origin.x(); max_y=-1; } else //Configuring the x position for the next schema on the current row x=sch_view->pos().x() + sch_view->boundingRect().width() + obj_spacing; } } objects=db_model->getObjectList(ObjectType::Relationship); for(BaseObject *obj : *objects) { dynamic_cast(obj)->setModified(true); } objects=db_model->getObjectList(ObjectType::BaseRelationship); for(BaseObject *obj : *objects) { dynamic_cast(obj)->setModified(true); } //Adjust the whole scene size due to table/schema repositioning this->adjustSceneSize(); } void ModelWidget::rearrangeTablesInGrid(Schema *schema, unsigned tabs_per_row, QPointF origin, double obj_spacing) { if(schema) { vector tables, views, ftables; vector::iterator itr; BaseTableView *tab_view=nullptr; BaseTable *base_tab=nullptr; unsigned tab_id=0; double max_y=-1, x=origin.x(), y=origin.y(), cy=0; //Get the tables and views for the specified schema tables=db_model->getObjects(ObjectType::Table, schema); ftables=db_model->getObjects(ObjectType::ForeignTable, schema); views=db_model->getObjects(ObjectType::View, schema); tables.insert(tables.end(), ftables.begin(), ftables.end()); tables.insert(tables.end(), views.begin(), views.end()); itr=tables.begin(); while(itr!=tables.end()) { base_tab=dynamic_cast(*itr); tab_view=dynamic_cast(base_tab->getOverlyingObject()); tab_view->setPos(QPointF(x,y)); //Defining the maximum y position to avoid table boxes colliding vertically cy=tab_view->pos().y() + tab_view->boundingRect().bottomRight().y(); if(max_y < cy) max_y=cy; //It the current table is the last of it's row tab_id++; if(tab_id >= tabs_per_row) { //Incrementing the row position tab_id=0; y=max_y + obj_spacing; x=origin.x(); max_y=-1; } else //Configuring the x position for the next table on the current row x=tab_view->pos().x() + tab_view->boundingRect().width() + obj_spacing; itr++; } } } void ModelWidget::swapObjectsIds(void) { BaseForm parent_form(this); SwapObjectsIdsWidget *swap_ids_wgt=new SwapObjectsIdsWidget; swap_ids_wgt->setModel(this->getDatabaseModel()); if(!selected_objects.empty()) swap_ids_wgt->setSelectedObjects(selected_objects[0], selected_objects.size() == 2 ? selected_objects[1] : nullptr); connect(swap_ids_wgt, &SwapObjectsIdsWidget::s_objectsIdsSwapped, [&](){ this->op_list->removeOperations(); emit s_objectManipulated(); }); parent_form.apply_ok_btn->setVisible(true); parent_form.setMainWidget(swap_ids_wgt); GeneralConfigWidget::restoreWidgetGeometry(&parent_form, swap_ids_wgt->metaObject()->className()); parent_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&parent_form, swap_ids_wgt->metaObject()->className()); } void ModelWidget::jumpToTable(void) { QAction *act = qobject_cast(sender()); BaseTable *tab = nullptr; BaseTableView *tab_view = nullptr; if(!act) return; tab = reinterpret_cast(act->data().value()); scene->clearSelection(); tab_view = dynamic_cast(tab->getOverlyingObject()); tab_view->setSelected(true); viewport->centerOn(tab_view); } void ModelWidget::editTableData(void) { TableDataWidget *tab_data_wgt=new TableDataWidget; tab_data_wgt->setAttributes(db_model, dynamic_cast(selected_objects.at(0))); openEditingForm(tab_data_wgt); this->setModified(true); emit s_objectManipulated(); } void ModelWidget::updateModelLayers(void) { QStringList layers = scene->getLayers(); layers.removeAt(0); db_model->setLayers(layers); db_model->setActiveLayers(scene->getActiveLayersIds()); modified = true; } void ModelWidget::rearrangeTablesHierarchically(void) { vector objects; BaseGraphicObject *graph_obj = nullptr; BaseTableView *tab_view = nullptr, *root = nullptr; int num_rels = 0; scene->clearSelection(); objects.assign(db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::View)->begin(), db_model->getObjectList(ObjectType::View)->end()); //We determine the root by searching the table/view which contains the more amount of relationships connected for(auto obj : objects) { graph_obj = dynamic_cast(obj); dynamic_cast(graph_obj->getSchema())->setRectVisible(false); tab_view = dynamic_cast(graph_obj->getOverlyingObject()); if(tab_view->getConnectRelsCount() > num_rels) { root = tab_view; num_rels = tab_view->getConnectRelsCount(); } } if(root) { BaseObjectView *obj_view = nullptr; BaseRelationship *rel = nullptr; QRectF items_rect; vector evaluated_tabs, not_evaluated, not_linked_tabs; double px = 0, py = 0, max_h = 0, max_w = 0; //Positioning the root object at the top-left portion of canvas root->setPos(QPointF(50, 50)); evaluated_tabs.push_back(root->getUnderlyingObject()); items_rect = rearrangeTablesHierarchically(root, evaluated_tabs); max_w = items_rect.width(); objects.clear(); objects.assign(db_model->getObjectList(ObjectType::Table)->begin(), db_model->getObjectList(ObjectType::Table)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::View)->begin(), db_model->getObjectList(ObjectType::View)->end()); //Retrieving the rest of tables/views that were not evaluated in the previous iteration std::sort(objects.begin(), objects.end()); std::sort(evaluated_tabs.begin(), evaluated_tabs.end()); std::set_difference(objects.begin(), objects.end(), evaluated_tabs.begin(), evaluated_tabs.end(), std::inserter(not_evaluated, not_evaluated.begin())); /* While there is not evaluated objects (tables/views that are linked to each other but none of them are linked to the root (in)directly) we need to perform the same operation done for the root previously */ while(!not_evaluated.empty()) { num_rels = 0; root = nullptr; //Determining which table has the greater number of relationships attached for(auto &tab : not_evaluated) { tab_view = dynamic_cast(dynamic_cast(tab)->getOverlyingObject()); if(tab_view->getConnectRelsCount() > num_rels) { root = tab_view; num_rels = tab_view->getConnectRelsCount(); } } //Once determined the new root we perform the positioning of its "children" if(root && std::find(evaluated_tabs.begin(), evaluated_tabs.end(), root->getUnderlyingObject()) == evaluated_tabs.end()) { root->setPos(QPointF(50, items_rect.bottom() + 50)); evaluated_tabs.push_back(root->getUnderlyingObject()); items_rect = rearrangeTablesHierarchically(root, evaluated_tabs); not_evaluated.erase(std::find(not_evaluated.begin(), not_evaluated.end(), root->getUnderlyingObject())); if(items_rect.width() > max_w) max_w = items_rect.width(); } else { tab_view = dynamic_cast(dynamic_cast(not_evaluated.front())->getOverlyingObject()); //If the table/view has not relationships connected we separate it in a new list for further rearrangement if(tab_view->getConnectRelsCount() == 0) not_linked_tabs.push_back(not_evaluated.front()); not_evaluated.erase(not_evaluated.begin()); } } //Repositioning remaining tables (without relationships) and textboxes objects.clear(); objects.assign(not_linked_tabs.begin(), not_linked_tabs.end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::Textbox)->begin(), db_model->getObjectList(ObjectType::Textbox)->end()); px = 50; py = items_rect.bottom() + 100; max_h = 0; for(auto &obj : objects) { obj_view = dynamic_cast(dynamic_cast(obj)->getOverlyingObject()); obj_view->setPos(px, py); px += obj_view->boundingRect().width() + 100; if(obj_view->boundingRect().height() > max_h) max_h = obj_view->boundingRect().height(); if(px > max_w) { px = 50; py += max_h + 100; } } objects.clear(); objects.assign(db_model->getObjectList(ObjectType::Relationship)->begin(), db_model->getObjectList(ObjectType::Relationship)->end()); objects.insert(objects.end(), db_model->getObjectList(ObjectType::BaseRelationship)->begin(), db_model->getObjectList(ObjectType::BaseRelationship)->end()); for(auto obj : objects) { rel = dynamic_cast(obj); rel->setPoints({}); rel->resetLabelsDistance(); if(!RelationshipView::isCurvedLines() && round(rel->getTable(BaseRelationship::SrcTable)->getPosition().y()) != round(rel->getTable(BaseRelationship::DstTable)->getPosition().y())) breakRelationshipLine(dynamic_cast(obj), ModelWidget::BreakVert2NinetyDegrees); } db_model->setObjectsModified({ ObjectType::Table, ObjectType::View, ObjectType::Schema, ObjectType::Relationship, ObjectType::BaseRelationship }); } else { //This is a fallback arrangement when the model does not have relationships rearrangeSchemasInGrid(); } adjustSceneSize(); viewport->updateScene({ scene->sceneRect() }); } QRectF ModelWidget::rearrangeTablesHierarchically(BaseTableView *root, vector &evaluated_tabs) { BaseTable *base_tab = dynamic_cast(root->getUnderlyingObject()), *src_tab = nullptr, *dst_tab = nullptr, *curr_tab = nullptr; vector rels ; double px = 0, py = 0, px1 = 0, py1 = 0; BaseTableView *tab_view = nullptr; vector tabs = { base_tab }, next_tabs; bool is_protected = false; while(!tabs.empty()) { base_tab = tabs.front(); tabs.erase(tabs.begin()); tab_view = dynamic_cast(base_tab->getOverlyingObject()); rels = db_model->getRelationships(base_tab); for(auto &rel : rels) { if(rel->isSelfRelationship()) continue; src_tab = rel->getTable(BaseRelationship::SrcTable); dst_tab = rel->getTable(BaseRelationship::DstTable); if(src_tab != base_tab) curr_tab = src_tab; else if(dst_tab != base_tab) curr_tab = dst_tab; else curr_tab = nullptr; if(curr_tab && std::find(evaluated_tabs.begin(), evaluated_tabs.end(), dynamic_cast(curr_tab)) == evaluated_tabs.end()) { next_tabs.push_back(curr_tab); evaluated_tabs.push_back(dynamic_cast(curr_tab)); } } if(tabs.empty()) { px = tab_view->pos().x() + (tab_view->boundingRect().width() * 1.50); py = root->pos().y() + 75; for(auto &next_tab : next_tabs) { tab_view = dynamic_cast(next_tab->getOverlyingObject()); //Temporarily unprotecting the table so it can be moved if(next_tab->isProtected()) { next_tab->setProtected(false); is_protected = true; } else is_protected = false; tab_view->setPos(QPointF(px, py)); next_tab->setProtected(is_protected); py += tab_view->boundingRect().height() + 75; px += 50; } if(px > px1) px1 = px; if(py > py1) py1 = py; tabs.assign(next_tabs.begin(), next_tabs.end()); next_tabs.clear(); } } return(QRectF(root->pos(), QPointF(px1, py1))); } void ModelWidget::rearrangeTablesInSchema(Schema *schema, QPointF start) { vector tables, views; if(!schema) return; tables = db_model->getObjects(ObjectType::Table, schema); views = db_model->getObjects(ObjectType::View, schema); tables.insert(tables.end(), views.begin(), views.end()); if(!tables.empty()) { BaseTable *base_tab = nullptr; BaseTableView *tab_view = nullptr, *comp_tab = nullptr, *curr_tab = nullptr; //If there two or less tables we put them side-by-side if(tables.size() <= 2) { base_tab = dynamic_cast(tables[0]); curr_tab = dynamic_cast(base_tab->getOverlyingObject()); curr_tab->setPos(start); if(tables.size() > 1) { tab_view = curr_tab; base_tab = dynamic_cast(tables[1]); curr_tab = dynamic_cast(base_tab->getOverlyingObject()); curr_tab->setPos(start + QPointF(tab_view->boundingRect().width() * 1.25, 0)); } } else { double max_w = 0, max_h = 0; bool has_collision = false; QRectF curr_brect, comp_brect, irect; QPointF pos; random_device rand_seed; default_random_engine rand_num_engine; unsigned tries = 0; rand_num_engine.seed(rand_seed()); /* Calculating the maximum width and height * The new tables' positions are calculated using these dimensions */ for(auto &tab : tables) { base_tab = dynamic_cast(tab); curr_tab = dynamic_cast(base_tab->getOverlyingObject()); max_w += curr_tab->boundingRect().width(); max_h += curr_tab->boundingRect().height(); } if(tables.size() >= 4) { max_w *= 0.50; max_h *= 0.50; } else { max_w *= 1.15; max_h *= 1.15; } uniform_int_distribution dist_x(start.x(), start.x() + max_w), dist_y(start.y(), start.y() + max_h); //Doing the first random positioning on all tables for(auto &tab : tables) { base_tab = dynamic_cast(tab); curr_tab = dynamic_cast(base_tab->getOverlyingObject()); pos.setX(dist_x(rand_num_engine)); pos.setY(dist_y(rand_num_engine)); curr_tab->setPos(pos); } /* Collision detection: If a table collides with other tables it'll then repositioned * until no interception is detected */ for(auto &tab : tables) { base_tab = dynamic_cast(tab); curr_tab = dynamic_cast(base_tab->getOverlyingObject()); curr_brect = QRectF(curr_tab->pos(), curr_tab->boundingRect().size()); tries = 0; do { has_collision = false; for(auto &tab1 : tables) { if(tab == tab1) continue; base_tab = dynamic_cast(tab1); comp_tab = dynamic_cast(base_tab->getOverlyingObject()); comp_brect = QRectF(comp_tab->pos(), comp_tab->boundingRect().size()); irect = comp_brect.intersected(curr_brect); if(irect.isValid()) { has_collision = true; pos.setX(dist_x(rand_num_engine)); pos.setY(dist_y(rand_num_engine)); curr_tab->setPos(pos); curr_brect = QRectF(curr_tab->pos(), curr_tab->boundingRect().size()); break; } } tries++; } while(has_collision && tries < (tables.size() * 100)); } } schema->setRectVisible(true); schema->setModified(true); } } void ModelWidget::rearrangeTablesInSchemas(void) { BaseRelationship *base_rel = nullptr; Schema *schema = nullptr; SchemaView *sch_view = nullptr, *sch_view_aux = nullptr; QRectF curr_brect, comp_brect, irect; random_device rand_seed; default_random_engine rand_num_engine; double max_w = 1000, max_h = 1000; vector schemas = *db_model->getObjectList(ObjectType::Schema), rels; bool has_collision = false; uniform_int_distribution dist_x(0, max_w), dist_y(0, max_h); unsigned tries = 0, max_tries = (db_model->getObjectCount(ObjectType::Table) + db_model->getObjectCount(ObjectType::View) + db_model->getObjectCount(ObjectType::Schema)) * 100; rand_num_engine.seed(rand_seed()); /* Rearraging tables inside schemas and determining the maximum width and height by summing * all schemas widths and heights. These values will be serve as the maximum * position limit for the schemas */ for(auto &sch : schemas) { schema = dynamic_cast(sch); sch_view = dynamic_cast(schema->getOverlyingObject()); if(!sch_view) continue; rearrangeTablesInSchema(schema, QPointF(dist_x(rand_num_engine), dist_y(rand_num_engine))); max_w += sch_view->boundingRect().width(); max_h += sch_view->boundingRect().height(); } uniform_int_distribution::param_type new_dx(0, max_w * 0.40); dist_x.param(new_dx); uniform_int_distribution::param_type new_dy(0, max_h * 0.40); dist_y.param(new_dy); /* Collision detection: If a schema collides with other schemas it'll then repositioned * until no interception is detected or the tries reached the max_tries value */ for(auto &sch : schemas) { schema = dynamic_cast(sch); sch_view = dynamic_cast(schema->getOverlyingObject()); tries = 0; if(!sch_view) continue; curr_brect = QRectF(sch_view->pos(), sch_view->boundingRect().size()); do { has_collision = false; for(auto &sch1 : schemas) { schema = dynamic_cast(sch1); sch_view_aux = dynamic_cast(schema->getOverlyingObject()); if(sch == sch1 || !sch_view_aux) continue; comp_brect = QRectF(sch_view_aux->pos(), sch_view_aux->boundingRect().size()); irect = comp_brect.intersected(curr_brect); if(irect.isValid()) { has_collision = true; sch_view->moveTo(QPointF(dist_x(rand_num_engine), dist_y(rand_num_engine))); curr_brect = QRectF(sch_view->pos(), sch_view->boundingRect().size()); break; } } tries++; } while(has_collision && tries < max_tries); } //Removing all custom points from relationships rels.assign(db_model->getObjectList(ObjectType::Relationship)->begin(), db_model->getObjectList(ObjectType::Relationship)->end()); rels.insert(rels.end(), db_model->getObjectList(ObjectType::BaseRelationship)->begin(), db_model->getObjectList(ObjectType::BaseRelationship)->end()); for(auto &rel : rels) { base_rel = dynamic_cast(rel); base_rel->setPoints({}); base_rel->resetLabelsDistance(); } db_model->setObjectsModified({ ObjectType::Table, ObjectType::View, ObjectType::Schema, ObjectType::Relationship, ObjectType::BaseRelationship }); adjustSceneSize(); viewport->updateScene({ scene->sceneRect() }); } void ModelWidget::updateMagnifierArea(void) { QPoint pos = viewport->mapFromGlobal(QCursor::pos()); QPointF scene_pos = viewport->mapToScene(pos); QSize size = magnifier_area_lbl->size(); QPixmap pix = QPixmap(size); double cx = magnifier_area_lbl->width() / 2, cy = magnifier_area_lbl->height() / 2; magnifier_frm->setGeometry(0, 0, magnifier_area_lbl->width() * current_zoom, magnifier_area_lbl->height() * current_zoom); magnifier_frm->move(pos - QPoint(magnifier_frm->width()/2, magnifier_frm->height()/2)); if(magnifier_frm->geometry().left() <= magnifier_area_lbl->geometry().right()) magnifier_area_lbl->move(viewport->width() - magnifier_area_lbl->width(), magnifier_area_lbl->geometry().top()); if(magnifier_frm->geometry().right() >= magnifier_area_lbl->geometry().left()) magnifier_area_lbl->move(5, magnifier_area_lbl->geometry().top()); QPainter p(&pix); p.setRenderHints(viewport->renderHints()); scene->blockSignals(true); scene->render(&p, QRectF(QPointF(0,0), size), QRectF(scene_pos - QPointF(cx, cy), size)); p.setPen(QColor(80,0,0)); p.drawLine(QPointF(cx, cy - 10), QPointF(cx, cy + 10)); p.drawLine(QPointF(cx - 10, cy), QPointF(cx + 10, cy)); magnifier_area_lbl->setPixmap(pix); scene->blockSignals(false); } void ModelWidget::showMagnifierArea(bool show) { if(show) { updateMagnifierArea(); viewport->setCursor(Qt::CrossCursor); } else viewport->setCursor(Qt::ArrowCursor); magnifier_area_lbl->setVisible(show); magnifier_frm->setVisible(show); } pgmodeler-0.9.2/libpgmodeler_ui/src/modelwidget.h000066400000000000000000000447201360462764600221330ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ModelWidget \brief Implements the widget that permits the direct user interation over the database model. */ #ifndef MODEL_WIDGET_H #define MODEL_WIDGET_H #include #include "databasemodel.h" #include "operationlist.h" #include "messagebox.h" #include "objectsscene.h" #include "taskprogresswidget.h" #include "newobjectoverlaywidget.h" class ModelWidget: public QWidget { private: Q_OBJECT XmlParser *xmlparser; NewObjectOverlayWidget *new_obj_overlay_wgt; //! \brief Current zoom aplied to the scene double current_zoom; //! \brief Indicates if the model was modified by some operation bool modified, //! brief Indicates if the panning mode was activated via event filter (see eventFilter()) panning_mode; /*! \brief Indicates if the cut operation is currently activated. This flag modifies the way the methods copyObjects() and removeObject() works. */ static bool cut_operation; //! \brief Indicates if the last position and zoom must be saved/restored static bool save_restore_pos, //! \brief Indicates that graphical objects like table, view and textboxes can be created without click canvas (direclty from their editing form) simple_obj_creation, disable_render_smooth; //! \brief Indicates if the minimum object opacity used when appliyng fade out to objects static double min_object_opacity; /*! \brief Stores the model that generates the copy/cut operation. This model is updated from the destination model whenever a past/cut operation is done. */ static ModelWidget *src_model; //! \brief Copied object on the source model static vector copied_objects; //! \brief Stores the cutted object on source model (only when executing cut command) static vector cutted_objects; //! \brief Frame that indicates if the model is protected QFrame *protected_model_frm; //! \brief Graphical objects scene ObjectsScene *scene; //! \brief Manages the objects scene QGraphicsView *viewport; //! \brief Model's general context menu QMenu popup_menu, //! \brief Stores the actions related to new objects creation new_object_menu, //! \brief Stores the quick actions quick_actions_menu, //! \brief Stores the schemas used by the "move to schema" operation schemas_menu, //! \brief Stores the role names used by the "change owner" operation owners_menu, //! \brief Stores the tags used by the "set tag" operation tags_menu, //! \brief Stores the layers used by the "move to layer" operation layers_menu, break_rel_menu, fade_menu, fade_in_menu, fade_out_menu, fade_rels_menu, toggle_attrs_menu, pagination_menu, select_all_menu, jump_to_tab_menu, toggle_sch_rects_menu, database_category_menu, schema_category_menu; //! \brief Stores the selected object on the scene vector selected_objects; //! \brief Type of the object to be inserted on the model ObjectType new_obj_type; //! \brief Operation list that stores the modifications executed over the model OperationList *op_list; //! \brief Database model handle by the ModelWidget class. All operations are made over this attribute DatabaseModel *db_model; //! \brief Stores the loaded database model filename QString filename, //! \brief Stores the temporary database model filename tmp_filename; //! \brief This label shows the user the current applied zoom QLabel *zoom_info_lbl, //! \brief This label shows a small portion of the canvas in normal zoom at the current cursor position *magnifier_area_lbl; QFrame *magnifier_frm; //! \brief This timer controls the interval the zoom label is visible QTimer zoom_info_timer; //! \brief Opens a editing form for objects at database level template int openEditingForm(BaseObject *object); /*! \brief Opens a editing form for objects that can have a parent other than database, e.g., schema level objects, table child object or relationship attributes & constraints */ template int openEditingForm(BaseObject *object, BaseObject *parent_obj); //! \brief Opens a editing form for objects that can have a position in the canvas area template int openEditingForm(BaseObject *object, BaseObject *parent_obj, const QPointF &pos); //! \brief Opens a editing form specific for tables and foreign tables int openTableEditingForm(ObjectType tab_type, PhysicalTable *object, Schema *parent_obj, const QPointF &pos); //! \brief Configures the popup menu according the the selected objects list void configurePopupMenu(const vector &objects=vector()); //! \brief Configures the submenu related to the object void configureSubmenu(BaseObject *object); //! \brief Configures the submenu related to fade in/out operations void configureFadeMenu(void); //! \brief Fades in our out the object types held by the specified action void fadeObjects(QAction *action, bool fade_in); void breakRelationshipLine(BaseRelationship *rel, unsigned break_type); /*! \brief Arrange tables starting from a specified root in a hierarchical way where for a certain table its child (or related) tables are places aside from left to right and top to bottom. This method returns the bounding rect of the items after the rearrangement */ QRectF rearrangeTablesHierarchically(BaseTableView *root, vector &evaluated_tabs); /*! \brief Arrange tables inside the provided schema randomly (scattered). An start point should * be provided. The method will avoid to put two or more tables in the same position causing * overlaping. This method causes the schema rectangle to be enabled. */ void rearrangeTablesInSchema(Schema *schema, QPointF start); void updateMagnifierArea(void); void showMagnifierArea(bool show); protected: static constexpr unsigned BreakVertNinetyDegrees=0, //Break vertically the line in one 90° angle BreakHorizNinetyDegrees=1, //Break horizontally the line in one 90° angle BreakVert2NinetyDegrees=2, //Break vertically the line in two 90° angles BreakHoriz2NinetyDegrees=3;//Break horizontally the line in two 90° angles QAction *action_source_code, *action_edit, *action_protect, *action_unprotect, *action_remove, *action_cascade_del, *action_select_all, *action_convert_relnn, *action_copy, *action_paste, *action_cut, *action_deps_refs, *action_new_object, *action_rename, *action_moveto_schema, *action_edit_perms, *action_change_owner, *action_quick_actions, *action_sel_sch_children, *action_sel_tagged_tabs, *action_select_object, *action_parent_rel, *action_append_sql, *action_create_seq_col, *action_conv_int_serial, *action_break_rel_line, *action_remove_rel_points, *action_set_tag, *action_moveto_layer, *action_disable_sql, *action_enable_sql, *action_duplicate, *action_fade, *action_fade_in, *action_fade_out, *action_fade_rels, *action_fade_rels_in, *action_fade_rels_out, *action_pagination, *action_collapse_mode, *action_collapse_ext_attribs, *action_collpase_all_attribs, *action_no_collapse_attribs, *action_edit_creation_order, *action_jump_to_table, *action_schemas_rects, *action_show_schemas_rects, *action_hide_schemas_rects, *action_edit_data, *action_database_category, *action_schema_category; //! \brief Actions used to create new objects on the model map actions_new_objects; //! \brief Stores the relationship types menu QMenu *rels_menu; void resizeEvent(QResizeEvent *); void mousePressEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void hideEvent(QHideEvent *); //! \brief Captures and handles the QWeelEvent raised on the viewport scrollbars bool eventFilter(QObject *object, QEvent *event); //! \brief Cancel the creation of a new object (only for graphical objects) void cancelObjectAddition(void); //! \brief Disables the model actions when some new object action is active void enableModelActions(bool value); /*! \brief Reorganizes the tables of a specific schema over the scene. The parameter are: the schema in which the tables will be rearranged, an origin point, number of tables per row a object spacing */ void rearrangeTablesInGrid(Schema *schema, unsigned tabs_per_row, QPointF origin, double obj_spacing); void fadeObjects(const vector &objects, bool fade_in); void setAllCollapseMode(CollapseMode mode); public: static constexpr double MinimumZoom=0.050000, MaximumZoom=5.000001, ZoomIncrement=0.050000; ModelWidget(QWidget *parent = nullptr); ~ModelWidget(void); //! \brief Creates a BaseForm instance and insert the widget into it. A custom configuration for dialog buttons can be passed int openEditingForm(QWidget *widget, unsigned button_conf = Messagebox::OkCancelButtons); /*! \brief Configures the scene aligning the object to the grid and resizing the scene rect when some object is out of bound */ void adjustSceneSize(void); //! \brief Set the model as modified forcing it to be redrawn void setModified(bool value); //! \brief Returns the loaded database model filename QString getFilename(void); //! \brief Returns the temporary (security copy) of the currently loaded model QString getTempFilename(void); //! \brief Shows the editing form according to the passed object type void showObjectForm(ObjectType obj_type, BaseObject *object=nullptr, BaseObject *parent_obj=nullptr, const QPointF &pos=QPointF(DNaN, DNaN)); //! \brief Applies a zoom factor to the model void applyZoom(double zoom); //! \brief Returns the current zoom factor applied to the model double getCurrentZoom(void); //! \brief Returns if the model is modified or not bool isModified(void); //! \brief Returns the reference database model DatabaseModel *getDatabaseModel(void); //! \brief Returns the object scene used by the model ObjectsScene *getObjectsScene(void); //! \brief Returns the scene view used by the model QGraphicsView *getViewport(void); //! \brief Returns the operation list used by database model OperationList *getOperationList(void); //! \brief Defines if any instance of ModelWidget must restore the last saved editing position on canvas static void setSaveLastCanvasPosition(bool value); //! \brief Defines if any instance of the class must disable rendering smoothness improving performance static void setRenderSmoothnessDisabled(bool value); //! \brief Defines if any instance of the class must simiplify the graphical object's creation static void setSimplifiedObjectCreation(bool value); //! \brief Defines the minimum object opacity when using fade out feature static void setMinimumObjectOpacity(unsigned min_opacity); //! \brief Restore the last editing position on canvas as well the zoom factor void restoreLastCanvasPosition(void); /*! \brief Save the last editing position on canvas as well the zoom factor. This method return true when the current values was saved on the database model */ bool saveLastCanvasPosition(void); void setUpdatesEnabled(bool value); void updateRenderHints(void); /*! \brief Updates the opacity factor of the objects faded in the model. This method should be called whenever the min_object_opacity changes */ void updateObjectsOpacity(void); /*! \brief Rearrange table/view/textboxes in the canvas in such way to provide better visualization * of the whole model. Currently only hierachical arrangement is possible. See rearrangeTablesHierarchically() */ void rearrangeTablesHierarchically(void); /*! \brief Reorganizes the schemas over the scene in a grid form. The parameters are: an origin point, number of tables per row, schemas per row and a object spacing */ void rearrangeSchemasInGrid(unsigned tabs_per_row = 0, unsigned sch_per_row = 0, QPointF origin = QPointF(50, 50), double obj_spacing = 50); //! \brief Arrange all tables it their schemas randomly (scattered) void rearrangeTablesInSchemas(void); void emitSceneInteracted(void); private slots: //! \brief Handles the signals that indicates the object creation on the reference database model void handleObjectAddition(BaseObject *object); //! \brief Handles the signals that indicates the object removal on the reference database model void handleObjectRemoval(BaseObject *object); //! \brief Handles the signals that indicates the object moviment on the scene void handleObjectsMovement(bool end_moviment); //! \brief Handles the signals that indicates the object edition on the scene void handleObjectModification(BaseGraphicObject *object); //! \brief Handles the signals that indicates the object was double clicked on the scene void handleObjectDoubleClick(BaseGraphicObject *object); //! \brief Configures the popup menu specific for the passed object void configureObjectMenu(BaseObject *object); //! \brief Shows the configured popup menu void showObjectMenu(void); //! \brief Shows the widget containing the dependencies and references to the object void showDependenciesReferences(void); //! \brief Triggers the object editing void editObject(void); //! \brief Toggles the protection of the selected objects void protectObject(void); //! \brief Triggers the quick rename action void renameObject(void); //! \brief Move the selected object to a schema (selectable via menu) void moveToSchema(void); //! \brief Move the selected object to a layer (selectable via menu) void moveToLayer(void); //! \brief Quickly changes the object's owner via popup menu void changeOwner(void); //! \brief Quickly sets the table's tag via popup menu void setTag(void); //! \brief Triggers the permission editing form void editPermissions(void); //! \brief Selects all the graphical objects under the selected schema void selectSchemaChildren(void); //! \brief Selects all the tables and views that references the selected tag void selectTaggedTables(void); //! \brief Removes the selected objects void removeObjects(bool cascade = false); //! \brief Removes the selected objects in cascade model. This is the same as call removeObjects(true). void removeObjectsCascade(void); //! \brief Selects all the graphical objects on the scene void selectAllObjects(void); //! \brief Copies all the selected objects void copyObjects(bool duplicate_mode = false); //! \brief Paste all the objects copied previously void pasteObjects(bool duplicate_mode = false); //! \brief Duplicate the selected table object in its parent table void duplicateObject(void); //! \brief Cuts the selected objects. The effective removal is made when the cutted objects are pasted. void cutObjects(void); //! \brief Converts the Many to Many relationship generating a table and two additional relationships. void convertRelationshipNN(void); //! \brief Loads the selected object source code on the source code widget. void showSourceCode(void); //! \brief Adds a new object onto the selected model/table/schema void addNewObject(void); //! \brief Triggers the sql insertion widget for the current database model void editCustomSQL(void); //! \brief Configures the selected object vector whenever the selection changes on the scene void configureObjectSelection(void); /*! \brief Creates a sequence based upon the selected column. This method changes the default value for the column as well the type. */ void createSequenceFromColumn(void); /*! \brief Creates a serial data type based upon the selected column data type. The prerequisite to create a serial data type is that the column's type is an integer one (smallint, int, bigint) and the default value is a function call to nextval('myseq'::regclass) */ void convertIntegerToSerial(void); //! \brief Break the relationship line in one or two straight angles (see BREAK_??? constants) void breakRelationshipLine(void); //! \brief Removes any user added point from relationship void removeRelationshipPoints(void); //! \brief Highlights the object stored on the action that triggers the slot void highlightObject(void); void toggleNewObjectOverlay(void); void adjustOverlayPosition(void); void toggleObjectSQL(void); void fadeObjectsIn(void); void fadeObjectsOut(void); void setCollapseMode(void); void togglePagination(void); void toggleSchemasRectangles(void); void swapObjectsIds(void); void jumpToTable(void); void editTableData(void); void updateModelLayers(void); public slots: void loadModel(const QString &filename); void saveModel(const QString &filename); void saveModel(void); void printModel(QPrinter *printer, bool print_grid, bool print_page_nums); void update(void); signals: void s_objectModified(void); void s_objectsMoved(void); void s_objectCreated(void); void s_objectRemoved(void); void s_zoomModified(double); void s_modelResized(void); //! \brief Signal emitted whenever a object is created / edited using the form void s_objectManipulated(void); /*! \brief Signal emitted whenever the user open an object in its editing form but cancel the operation by closing the form */ void s_manipulationCanceled(void); void s_sceneInteracted(BaseObjectView *sel_obj); void s_sceneInteracted(const QSizeF &scene_size); void s_sceneInteracted(const QPointF &mouse_pos); void s_sceneInteracted(int obj_count, const QRectF &objs_rect); friend class MainWindow; friend class ModelExportForm; friend class OperationListWidget; friend class ModelObjectsWidget; friend class ModelOverviewWidget; friend class ModelValidationWidget; friend class DatabaseImportForm; friend class ObjectFinderWidget; friend class NewObjectOverlayWidget; friend class LayersWidget; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/newobjectoverlaywidget.cpp000066400000000000000000000152461360462764600247510ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "newobjectoverlaywidget.h" #include "modelwidget.h" NewObjectOverlayWidget::NewObjectOverlayWidget(ModelWidget *parent): QWidget(parent) { Ui_NewObjectOverlayWidget::setupUi(this); QToolButton *button=nullptr; ObjectType obj_type; QString shortcut; int action_idx=0; QList rel_actions=parent->rels_menu->actions(); map> obj_shortcuts={ { aggregate_tb, std::make_tuple(trUtf8("A"), ObjectType::Aggregate) }, { cast_tb, std::make_tuple(trUtf8("G"), ObjectType::Cast) }, { eventtrigger_tb, std::make_tuple(trUtf8("K"), ObjectType::EventTrigger)}, { collation_tb, std::make_tuple(trUtf8("H"), ObjectType::Collation) }, { conversion_tb, std::make_tuple(trUtf8("J"), ObjectType::Conversion) }, { domain_tb, std::make_tuple(trUtf8("D"), ObjectType::Domain) }, { extension_tb, std::make_tuple(trUtf8("E"), ObjectType::Extension) }, { function_tb, std::make_tuple(trUtf8("F"), ObjectType::Function) }, { language_tb, std::make_tuple(trUtf8("L"), ObjectType::Language) }, { opclass_tb, std::make_tuple(trUtf8("O"), ObjectType::OpClass) }, { operator_tb, std::make_tuple(trUtf8("U"), ObjectType::Operator) }, { opfamily_tb, std::make_tuple(trUtf8("I"), ObjectType::OpFamily) }, { role_tb, std::make_tuple(trUtf8("R"), ObjectType::Role) }, { schema_tb, std::make_tuple(trUtf8("S"), ObjectType::Schema) }, { sequence_tb, std::make_tuple(trUtf8("Q"), ObjectType::Sequence) }, { table_tb, std::make_tuple(trUtf8("T"), ObjectType::Table) }, { tablespace_tb, std::make_tuple(trUtf8("P"), ObjectType::Tablespace) }, { textbox_tb, std::make_tuple(trUtf8("M"), ObjectType::Textbox) }, { type_tb, std::make_tuple(trUtf8("Y"), ObjectType::Type) }, { view_tb, std::make_tuple(trUtf8("W"), ObjectType::View) }, { tag_tb, std::make_tuple(trUtf8("9"), ObjectType::Tag) }, { constraint_tb, std::make_tuple(trUtf8("Z"), ObjectType::Constraint) }, { index_tb, std::make_tuple(trUtf8("X"), ObjectType::Index) }, { column_tb, std::make_tuple(trUtf8("C"), ObjectType::Column) }, { rule_tb, std::make_tuple(trUtf8("V"), ObjectType::Rule) }, { trigger_tb, std::make_tuple(trUtf8("B"), ObjectType::Trigger) }, { policy_tb, std::make_tuple(trUtf8("9"), ObjectType::Policy) }, { genericsql_tb, std::make_tuple(trUtf8("8"), ObjectType::GenericSql) }, { fdw_tb, std::make_tuple(trUtf8("7"), ObjectType::ForeignDataWrapper) }, { server_tb, std::make_tuple(trUtf8("6"), ObjectType::ForeignServer) }, { user_mapping_tb, std::make_tuple(trUtf8("5"), ObjectType::UserMapping) }, { foreigntable_tb, std::make_tuple(trUtf8("4"), ObjectType::ForeignTable) }}; map> rel_shortcuts={ { rel11_tb, std::make_tuple(trUtf8("1"), 0) }, { rel1n_tb, std::make_tuple(trUtf8("2"), 1) }, { relnn_tb, std::make_tuple(trUtf8("3"), 2) }, { reldep_tb, std::make_tuple(trUtf8("5"), 3) }, { relgen_tb, std::make_tuple(trUtf8("4"), 4) }, { relpart_tb, std::make_tuple(trUtf8("5"), 5) }}; vector permission_btns={db_sch_perms_tb, tab_perms_tb }; for(auto &itr : obj_shortcuts) { button=itr.first; shortcut=std::get<0>(itr.second); obj_type=std::get<1>(itr.second); button->setText(shortcut + QString(": ") + button->text()); button->setShortcut(QKeySequence(shortcut)); connect(button, SIGNAL(clicked()), this, SLOT(hide())); connect(button, SIGNAL(clicked()), parent->actions_new_objects[obj_type], SLOT(trigger())); } for(auto &itr : rel_shortcuts) { button=itr.first; shortcut=std::get<0>(itr.second); action_idx=std::get<1>(itr.second); button->setText(shortcut + QString(": ") + button->text()); button->setShortcut(QKeySequence(shortcut)); connect(button, SIGNAL(clicked()), this, SLOT(hide())); if(action_idx < rel_actions.size()) connect(button, SIGNAL(clicked()), rel_actions[action_idx], SLOT(trigger())); } shortcut=trUtf8("0"); for(auto &itr : permission_btns) { button=itr; button->setText(shortcut + QString(": ") + button->text()); button->setShortcut(QKeySequence(shortcut)); connect(button, SIGNAL(clicked()), this, SLOT(hide())); connect(button, SIGNAL(clicked()), parent->action_edit_perms, SLOT(trigger())); } } void NewObjectOverlayWidget::setSelectedObjects(vector &sel_objs) { ObjectType obj_type=ObjectType::BaseObject; if(sel_objs.size()==1) obj_type=sel_objs.at(0)->getObjectType(); else if(sel_objs.empty()) obj_type=ObjectType::Database; db_objs_grp->setVisible(obj_type==ObjectType::Database); sch_objs_grp->setVisible(obj_type==ObjectType::Database || obj_type==ObjectType::Schema); tab_objs_grp->setVisible(BaseTable::isBaseTable(obj_type) || obj_type==ObjectType::Relationship); column_tb->setVisible(obj_type!=ObjectType::View); constraint_tb->setVisible(obj_type!=ObjectType::View); index_tb->setVisible(obj_type==ObjectType::Table || obj_type==ObjectType::View); rule_tb->setVisible(obj_type==ObjectType::Table || obj_type==ObjectType::View); trigger_tb->setVisible(BaseTable::isBaseTable(obj_type)); policy_tb->setVisible(obj_type==ObjectType::Table); tab_perms_tb->setVisible(obj_type==ObjectType::Table || obj_type==ObjectType::View); rels_grp->setVisible((sel_objs.size()==1 && sel_objs.at(0)->getObjectType()==ObjectType::Table) || (sel_objs.size()==2 && sel_objs.at(0)->getObjectType()==ObjectType::Table && sel_objs.at(1)->getObjectType()==ObjectType::Table)); overlay_frm->adjustSize(); this->adjustSize(); } pgmodeler-0.9.2/libpgmodeler_ui/src/newobjectoverlaywidget.h000066400000000000000000000026431360462764600244130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class NewObjectOverlayWidget \brief Implements the a basic overlay to quicly trigger action to create new objects. */ #ifndef NEW_OBJECT_OVERLAY_WIDGET_H #define NEW_OBJECT_OVERLAY_WIDGET_H #include #include #include "baseobject.h" #include "ui_newobjectoverlaywidget.h" //Adding the declaration of ModelWidget class in order to be visible to NewObjectOverlayWidget class ModelWidget; class NewObjectOverlayWidget: public QWidget, public Ui::NewObjectOverlayWidget { private: Q_OBJECT public: explicit NewObjectOverlayWidget(ModelWidget * parent); void setSelectedObjects(vector &sel_objs); void configureOverlayButtons(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/numberedtexteditor.cpp000066400000000000000000000415011360462764600240710ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "numberedtexteditor.h" #include "generalconfigwidget.h" #include #include #include #include #include #include "pgmodeleruins.h" bool NumberedTextEditor::line_nums_visible=true; bool NumberedTextEditor::highlight_lines=true; QColor NumberedTextEditor::line_hl_color=Qt::yellow; QFont NumberedTextEditor::default_font=QFont(QString("Source Code Pro"), 10); int NumberedTextEditor::tab_width=0; QString NumberedTextEditor::src_editor_app=QString(); QString NumberedTextEditor::src_editor_app_args=QString(); NumberedTextEditor::NumberedTextEditor(QWidget * parent, bool handle_ext_files) : QPlainTextEdit(parent) { this->handle_ext_files = handle_ext_files; line_number_wgt=new LineNumbersWidget(this); top_widget = nullptr; load_file_btn = clear_btn = nullptr; if(handle_ext_files) { QPalette pal; QHBoxLayout *hbox = new QHBoxLayout, *hbox1 = new QHBoxLayout; QFont font = this->font(); font.setPointSizeF(font.pointSizeF() * 0.95); top_widget = new QWidget(this); top_widget->setAutoFillBackground(true); pal.setColor(QPalette::Window, LineNumbersWidget::getBackgroundColor()); top_widget->setPalette(pal); top_widget->setVisible(handle_ext_files); top_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hbox->setContentsMargins(2,2,2,2); hbox1->setContentsMargins(0,0,0,0); QLabel *ico = new QLabel(this); msg_lbl = new QLabel(this); msg_lbl->setTextInteractionFlags(Qt::TextSelectableByMouse); ico->setMaximumSize(22,22); ico->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta"))); ico->setScaledContents(true); editor_alert_wgt = new QWidget(this); editor_alert_wgt->setFont(font); hbox1->addWidget(ico); hbox1->addWidget(msg_lbl); editor_alert_wgt->setLayout(hbox1); editor_alert_wgt->setVisible(false); hbox->addWidget(editor_alert_wgt); hbox->addSpacerItem(new QSpacerItem(10,10, QSizePolicy::Expanding)); load_file_btn = new QToolButton(top_widget); load_file_btn->setIcon(QPixmap(PgModelerUiNs::getIconPath("abrir"))); load_file_btn->setIconSize(QSize(16,16)); load_file_btn->setAutoRaise(true); load_file_btn->setText(trUtf8("Load")); load_file_btn->setToolTip(trUtf8("Load the object's source code from an external file")); load_file_btn->setFont(font); load_file_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); hbox->addWidget(load_file_btn); connect(load_file_btn, SIGNAL(clicked(bool)), this, SLOT(loadFile())); edit_src_btn = new QToolButton(top_widget); edit_src_btn->setIcon(QPixmap(PgModelerUiNs::getIconPath("editar"))); edit_src_btn->setIconSize(QSize(16,16)); edit_src_btn->setAutoRaise(true); edit_src_btn->setText(trUtf8("Edit")); edit_src_btn->setToolTip(trUtf8("Edit the source code in the preferred external editor")); edit_src_btn->setFont(font); edit_src_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); hbox->addWidget(edit_src_btn); connect(edit_src_btn, SIGNAL(clicked(bool)), this, SLOT(editSource())); clear_btn = new QToolButton(top_widget); clear_btn->setIcon(QPixmap(PgModelerUiNs::getIconPath("limpartexto"))); clear_btn->setIconSize(QSize(16,16)); clear_btn->setAutoRaise(true); clear_btn->setText(trUtf8("Clear")); clear_btn->setFont(font); clear_btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); clear_btn->setDisabled(true); connect(clear_btn, &QToolButton::clicked, [&](){ this->clear(); clear_btn->setEnabled(false); }); connect(this, &NumberedTextEditor::textChanged, [&](){ clear_btn->setEnabled(!this->toPlainText().isEmpty() && !this->isReadOnly()); }); hbox->addWidget(clear_btn); top_widget->setLayout(hbox); connect(&src_editor_proc, SIGNAL(finished(int)), this, SLOT(updateSource(int))); connect(&src_editor_proc, SIGNAL(started()), this, SLOT(handleProcessStart())); connect(&src_editor_proc, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(handleProcessError())); } setWordWrapMode(QTextOption::NoWrap); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumbers(void))); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumbersSize())); setCustomContextMenuEnabled(true); } NumberedTextEditor::~NumberedTextEditor(void) { if(src_editor_proc.state() != QProcess::NotRunning) { disconnect(&src_editor_proc, nullptr, this, nullptr); src_editor_proc.terminate(); src_editor_proc.waitForFinished(); QFile(tmp_src_file).remove(); } } void NumberedTextEditor::setCustomContextMenuEnabled(bool enabled) { if(!enabled) { setContextMenuPolicy(Qt::NoContextMenu); disconnect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu())); } else { setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu()), Qt::UniqueConnection); } } void NumberedTextEditor::setDefaultFont(const QFont &font) { default_font=font; } void NumberedTextEditor::setLineNumbersVisible(bool value) { line_nums_visible=value; } void NumberedTextEditor::setHighlightLines(bool value) { highlight_lines=value; } void NumberedTextEditor::setLineHighlightColor(const QColor &color) { line_hl_color=color; } void NumberedTextEditor::setTabWidth(int value) { if(value < 0) tab_width=0; else tab_width=value; } int NumberedTextEditor::getTabWidth(void) { if(tab_width == 0) return(80); else { QFontMetrics fm(default_font); return(tab_width * fm.width(' ')); } } void NumberedTextEditor::setSourceEditorApp(const QString &app) { NumberedTextEditor::src_editor_app = app; } void NumberedTextEditor::setSourceEditorAppArgs(const QString &args) { NumberedTextEditor::src_editor_app_args = args; } void NumberedTextEditor::showContextMenu(void) { QMenu *ctx_menu; QAction *act=nullptr; ctx_menu=createStandardContextMenu(); if(!isReadOnly()) { ctx_menu->addSeparator(); act=ctx_menu->addAction(trUtf8("Upper case"), this, SLOT(changeSelectionToUpper()), QKeySequence(QString("Ctrl+U"))); act->setEnabled(textCursor().hasSelection()); act=ctx_menu->addAction(trUtf8("Lower case"), this, SLOT(changeSelectionToLower()), QKeySequence(QString("Ctrl+Shift+U"))); act->setEnabled(textCursor().hasSelection()); ctx_menu->addSeparator(); act=ctx_menu->addAction(trUtf8("Ident right"), this, SLOT(identSelectionRight()), QKeySequence(QString("Tab"))); act->setEnabled(textCursor().hasSelection()); act=ctx_menu->addAction(trUtf8("Ident left"), this, SLOT(identSelectionLeft()), QKeySequence(QString("Shift+Tab"))); act->setEnabled(textCursor().hasSelection()); } ctx_menu->exec(QCursor::pos()); delete(ctx_menu); } void NumberedTextEditor::changeSelectionToLower(void) { changeSelectionCase(true); } void NumberedTextEditor::changeSelectionToUpper(void) { changeSelectionCase(false); } void NumberedTextEditor::changeSelectionCase(bool lower) { QTextCursor cursor=textCursor(); if(cursor.hasSelection()) { int start=cursor.selectionStart(), end=cursor.selectionEnd(); if(!lower) cursor.insertText(cursor.selectedText().toUpper()); else cursor.insertText(cursor.selectedText().toLower()); cursor.setPosition(start); cursor.setPosition(end, QTextCursor::KeepAnchor); setTextCursor(cursor); } } void NumberedTextEditor::identSelectionRight(void) { identSelection(true); } void NumberedTextEditor::identSelectionLeft(void) { identSelection(false); } void NumberedTextEditor::identSelection(bool ident_right) { QTextCursor cursor=textCursor(); if(cursor.hasSelection()) { QStringList lines; int start=-1, end=-1, factor=(ident_right ? 1 : -1), count=0; /* Forcing the selection of the very beggining of the first line and as well the end of the last line to avoid moving chars and break words wrongly */ start=toPlainText().lastIndexOf(QChar('\n'), cursor.selectionStart()); end=toPlainText().indexOf(QChar('\n'), cursor.selectionEnd()); cursor.setPosition(start, QTextCursor::MoveAnchor); cursor.setPosition(end, QTextCursor::KeepAnchor); lines=cursor.selectedText().split(QChar(QChar::ParagraphSeparator)); for(int i=0; i < lines.size(); i++) { if(!lines[i].isEmpty()) { if(ident_right) { lines[i].prepend(QChar('\t')); count++; } else if(lines[i].at(0)==QChar('\t')) { lines[i].remove(0,1); count++; } } } if(count > 0) { cursor.insertText(lines.join(QChar('\n'))); //Preserving the selection in the text to permit user perform several identations cursor.setPosition(start); cursor.setPosition(end + (count * factor), QTextCursor::KeepAnchor); setTextCursor(cursor); } } } void NumberedTextEditor::loadFile(void) { QFileDialog sql_file_dlg; sql_file_dlg.setDefaultSuffix(QString("sql")); sql_file_dlg.setFileMode(QFileDialog::AnyFile); sql_file_dlg.setNameFilter(trUtf8("SQL file (*.sql);;All files (*.*)")); sql_file_dlg.setModal(true); sql_file_dlg.setWindowTitle(trUtf8("Load file")); sql_file_dlg.setAcceptMode(QFileDialog::AcceptOpen); sql_file_dlg.exec(); if(sql_file_dlg.result()==QDialog::Accepted) { QFile file; file.setFileName(sql_file_dlg.selectedFiles().at(0)); if(!file.open(QFile::ReadOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed) .arg(sql_file_dlg.selectedFiles().at(0)), ErrorCode::FileDirectoryNotAccessed ,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->clear(); this->setPlainText(file.readAll()); file.close(); clear_btn->setEnabled(!this->toPlainText().isEmpty()); } } void NumberedTextEditor::editSource(void) { QByteArray buffer; QFile input; QStringList args; if(tmp_src_file.isEmpty()) { QTemporaryFile tmp_file; tmp_file.setFileTemplate(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + QString("source_XXXXXX") + QString(".sql")); tmp_file.open(); tmp_src_file = tmp_file.fileName(); tmp_file.close(); } input.setFileName(tmp_src_file); if(!input.open(QFile::WriteOnly | QFile::Truncate)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed) .arg(tmp_src_file), ErrorCode::FileDirectoryNotAccessed ,__PRETTY_FUNCTION__,__FILE__,__LINE__); buffer.append(this->toPlainText()); input.write(buffer); input.close(); //Starting the source editor application using the temp source file as input if(!src_editor_app_args.isEmpty()) args.push_back(src_editor_app_args); args.push_back(tmp_src_file); src_editor_proc.setProgram(src_editor_app); src_editor_proc.setArguments(args); src_editor_proc.setWorkingDirectory(QDir::currentPath()); src_editor_proc.start(); src_editor_proc.waitForStarted(); } void NumberedTextEditor::enableEditor(void) { editor_alert_wgt->setVisible(false); load_file_btn->setEnabled(true); edit_src_btn->setEnabled(true); clear_btn->setEnabled(!this->toPlainText().isEmpty()); this->setReadOnly(false); } void NumberedTextEditor::updateSource(int exit_code) { if(exit_code != 0) handleProcessError(); else { QFile input(tmp_src_file); enableEditor(); if(!input.open(QFile::ReadOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed) .arg(tmp_src_file), ErrorCode::FileDirectoryNotAccessed ,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->setPlainText(input.readAll()); input.close(); input.remove(); } } void NumberedTextEditor::handleProcessStart(void) { if(src_editor_proc.state() == QProcess::Running) { msg_lbl->setText(PgModelerUiNs::formatMessage(trUtf8("The source editor `%1' is running on `pid: %2'.") .arg(src_editor_proc.program()).arg(src_editor_proc.processId()))); editor_alert_wgt->setVisible(true); load_file_btn->setEnabled(false); edit_src_btn->setEnabled(false); clear_btn->setEnabled(false); this->setReadOnly(true); } } void NumberedTextEditor::handleProcessError(void) { Messagebox msg_box; QStringList errors = { src_editor_proc.errorString(), src_editor_proc.readAllStandardError() }; msg_box.show(PgModelerUiNs::formatMessage(trUtf8("Failed to the source code editor %1! Make to sure that the source editor path points to a valid executable and the current user has permission to run the application. Error message returned: %2") .arg(src_editor_proc.program()) .arg(errors.join(QString("\n\n")))), Messagebox::ErrorIcon); enableEditor(); } void NumberedTextEditor::setReadOnly(bool ro) { if(handle_ext_files) { load_file_btn->setEnabled(!ro); edit_src_btn->setEnabled(!ro); clear_btn->setEnabled(!ro && !this->toPlainText().isEmpty()); } QPlainTextEdit::setReadOnly(ro); } void NumberedTextEditor::setFocus(void) { QPlainTextEdit::setFocus(); this->highlightCurrentLine(); } void NumberedTextEditor::updateLineNumbers(void) { line_number_wgt->setVisible(line_nums_visible); if(!line_nums_visible) return; setFont(default_font); line_number_wgt->setFont(default_font); QTextBlock block = firstVisibleBlock(); int block_number = block.blockNumber(), //Calculates the first block postion (in widget coordinates) top = static_cast(blockBoundingGeometry(block).translated(contentOffset()).top()), bottom = top + static_cast(blockBoundingRect(block).height()), dy = top; unsigned first_line=0, line_count=0; // Calculates the visible lines by iterating over the visible/valid text blocks. while(block.isValid()) { if(block.isVisible()) { line_count++; if(first_line==0) first_line=static_cast(block_number + 1); } block = block.next(); top = bottom; bottom = top + static_cast(blockBoundingRect(block).height()); ++block_number; /* Check if the line count converted to widget coordinates is higher than the widget height. This is done to avoid draw line numbers that are beyond the widget's height */ if((static_cast(line_count) * fontMetrics().height()) > this->height()) break; } line_number_wgt->drawLineNumbers(first_line, line_count, dy); if(this->tabStopWidth()!=NumberedTextEditor::getTabWidth()) this->setTabStopWidth(NumberedTextEditor::getTabWidth()); } void NumberedTextEditor::updateLineNumbersSize(void) { int py = (handle_ext_files && top_widget ? top_widget->height() : 0); if(line_nums_visible) { QRect rect=contentsRect(); setViewportMargins(getLineNumbersWidth(), py, 0, 0); line_number_wgt->setGeometry(QRect(rect.left(), rect.top() + py, getLineNumbersWidth(), rect.height() - py)); if(top_widget) top_widget->setGeometry(rect.left(), rect.top(), rect.width() - (this->verticalScrollBar()->isVisible() ? this->verticalScrollBar()->width() : 0), top_widget->height()); } else setViewportMargins(0, py, 0, 0); } int NumberedTextEditor::getLineNumbersWidth(void) { int digits=1, max=qMax(1, blockCount()); while(max >= 10) { max /= 10; ++digits; } return(15 + fontMetrics().width(QChar('9')) * digits); } void NumberedTextEditor::resizeEvent(QResizeEvent *event) { QPlainTextEdit::resizeEvent(event); updateLineNumbersSize(); } void NumberedTextEditor::keyPressEvent(QKeyEvent *event) { if(!isReadOnly() && textCursor().hasSelection()) { if(event->key()==Qt::Key_U && event->modifiers()!=Qt::NoModifier) { if(event->modifiers()==Qt::ControlModifier) changeSelectionToUpper(); else if(event->modifiers()==(Qt::ControlModifier | Qt::ShiftModifier)) changeSelectionToLower(); } else if(event->key()==Qt::Key_Tab || event->key()==Qt::Key_Backtab) { if(event->key()==Qt::Key_Tab) identSelectionRight(); else if(event->key()==Qt::Key_Backtab) identSelectionLeft(); } else QPlainTextEdit::keyPressEvent(event); } else QPlainTextEdit::keyPressEvent(event); } void NumberedTextEditor::highlightCurrentLine(void) { QList extraSelections; if(highlight_lines && !isReadOnly()) { QTextEdit::ExtraSelection selection; selection.format.setBackground(line_hl_color); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); extraSelections.append(selection); } setExtraSelections(extraSelections); } pgmodeler-0.9.2/libpgmodeler_ui/src/numberedtexteditor.h000066400000000000000000000100151360462764600235320ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class NumberedTextEditor \brief Implements a simple text editor with a line number block attached to it. This class is based upon the code editor example provided by Qt */ #ifndef NUMBERED_TEXT_EDITOR_H #define NUMBERED_TEXT_EDITOR_H #include #include #include #include #include #include "linenumberswidget.h" class NumberedTextEditor : public QPlainTextEdit { private: Q_OBJECT //! \brief Controls if line numbers must be visible or not static bool line_nums_visible, //! \brief Controls if current line must be highlighted highlight_lines; //! \brief Line highlight color static QColor line_hl_color; //! \brief Default font for texts static QFont default_font; //! \brief Default tab size for texts static int tab_width; static QString src_editor_app; static QString src_editor_app_args; //! \brief Widget used to expose document line numbers LineNumbersWidget *line_number_wgt; //! \brief Indicates if the text editor can handle external files bool handle_ext_files; QWidget *top_widget, *editor_alert_wgt; QLabel *msg_lbl; QToolButton *load_file_btn, *edit_src_btn, *clear_btn; //! \brief The name of the temp file currently being used to edit the souce QString tmp_src_file; //! \brief The process object that holds the source code editor app QProcess src_editor_proc; //! \brief Determines and returns the line numbers widget width int getLineNumbersWidth(void); protected: void resizeEvent(QResizeEvent *event); void keyPressEvent(QKeyEvent *event); public: NumberedTextEditor(QWidget * parent = nullptr, bool handle_ext_files = false); ~NumberedTextEditor(void); static void setDefaultFont(const QFont &font); static void setLineNumbersVisible(bool value); static void setHighlightLines(bool value); static void setLineHighlightColor(const QColor &color); static void setTabWidth(int value); static int getTabWidth(void); static void setSourceEditorApp(const QString &app); static void setSourceEditorAppArgs(const QString &args); /*! brief Disable the custom context menu designed specifically for this class. This method is useful when the user needs to create another context menu that executes actions differents from the original ones */ void setCustomContextMenuEnabled(bool enabled); private slots: void showContextMenu(void); void changeSelectionToLower(void); void changeSelectionToUpper(void); void changeSelectionCase(bool lower); void identSelectionRight(void); void identSelectionLeft(void); void identSelection(bool ident_right); void loadFile(void); void editSource(void); void updateSource(int exit_code); void handleProcessStart(void); void handleProcessError(void); void enableEditor(void); public slots: void setReadOnly(bool ro); //! \brief Grabs the keyboard input and also highlight the current line void setFocus(void); //! \brief Draw the line numbers according to the current visible lines void updateLineNumbers(void); /*! \brief Configures the line numbers widget sizes (w,h) depending on the current visible lines and the text editor height */ void updateLineNumbersSize(void); //! \brief Colors the background of the line where the cursor is void highlightCurrentLine(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/objectdepsrefswidget.cpp000066400000000000000000000110531360462764600243610ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectdepsrefswidget.h" #include "pgmodeleruins.h" ObjectDepsRefsWidget::ObjectDepsRefsWidget(QWidget *parent): BaseObjectWidget(parent) { Ui_ObjectDepsRefsWidget::setupUi(this); configureFormLayout(objectdepsrefs_grid, ObjectType::BaseObject); PgModelerUiNs::configureWidgetFont(message_lbl, PgModelerUiNs::MediumFontFactor); model_wgt=nullptr; alert_frm->setVisible(false); connect(exc_ind_deps_chk, SIGNAL(toggled(bool)), this, SLOT(updateObjectTables(void))); connect(inc_ind_refs_chk, SIGNAL(toggled(bool)), this, SLOT(updateObjectTables(void))); connect(dependences_tbw, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(handleItemSelection(QTableWidgetItem*))); connect(references_tbw, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(handleItemSelection(QTableWidgetItem*))); setMinimumSize(580, 350); } void ObjectDepsRefsWidget::setAttributes(DatabaseModel *model, BaseObject *object, BaseObject *parent_obj) { BaseObjectWidget::setAttributes(model, object, parent_obj); if(object->getObjectType() == ObjectType::Constraint || object->getObjectType() == ObjectType::UserMapping) name_edt->setText(object->getName()); this->name_edt->setReadOnly(true); this->protected_obj_frm->setVisible(false); this->comment_edt->setVisible(false); this->comment_lbl->setVisible(false); obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(object->getObjectType()))); updateObjectTables(); } void ObjectDepsRefsWidget::setAttributes(ModelWidget *model_wgt, BaseObject *object, BaseObject *parent_obj) { if(!model_wgt) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->model_wgt=model_wgt; setAttributes(model_wgt->getDatabaseModel(), object, parent_obj); } void ObjectDepsRefsWidget::applyConfiguration(void) { emit s_closeRequested(); } void ObjectDepsRefsWidget::clearTables(void) { dependences_tbw->clearContents(); dependences_tbw->setRowCount(0); references_tbw->clearContents(); references_tbw->setRowCount(0); } void ObjectDepsRefsWidget::updateObjectTables(void) { vector objs; model->getObjectDependecies(object, objs, !exc_ind_deps_chk->isChecked()); /* As the list of dependencies include the this->object itself is necessary to remove only for semantics reasons */ objs.erase(std::find(objs.begin(), objs.end(), this->object)); ObjectFinderWidget::updateObjectTable(dependences_tbw, objs); objs.clear(); if(!inc_ind_refs_chk->isChecked()) model->getObjectReferences(object, objs); else model->__getObjectReferences(object, objs); ObjectFinderWidget::updateObjectTable(references_tbw, objs); references_tbw->resizeColumnsToContents(); dependences_tbw->resizeColumnsToContents(); } void ObjectDepsRefsWidget::handleItemSelection(QTableWidgetItem *item) { BaseObject *sel_obj=nullptr, *parent=nullptr; Table *parent_tab=nullptr; View *parent_view=nullptr; sel_obj=reinterpret_cast(item->data(Qt::UserRole).value()); if(sel_obj) { if(TableObject::isTableObject(sel_obj->getObjectType())) parent=dynamic_cast(sel_obj)->getParentTable(); model_wgt->showObjectForm(sel_obj->getObjectType(), sel_obj, parent); clearTables(); if(TableObject::isTableObject(this->object->getObjectType())) { parent=dynamic_cast(this->object)->getParentTable(); if(parent->getObjectType()==ObjectType::Table) parent_tab=dynamic_cast
(parent); else parent_view=dynamic_cast(parent); } if((parent_tab && parent_tab->getObjectIndex(this->object) >= 0) || (parent_view && parent_view->getObjectIndex(this->object) >= 0) || (model->getObjectIndex(this->object) >= 0)) { updateObjectTables(); } else { references_tbw->setEnabled(false); dependences_tbw->setEnabled(false); exc_ind_deps_chk->setEnabled(false); alert_frm->setVisible(true); } } } pgmodeler-0.9.2/libpgmodeler_ui/src/objectdepsrefswidget.h000066400000000000000000000030771360462764600240350ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectDepsRefsWidget \brief Implements the form to show the object's dependeces and references */ #ifndef OBJECT_DEPS_REFS_WIDGET_H #define OBJECT_DEPS_REFS_WIDGET_H #include "ui_objectdepsrefswidget.h" #include "baseobjectwidget.h" #include "baseobjectview.h" class ObjectDepsRefsWidget: public BaseObjectWidget, public Ui::ObjectDepsRefsWidget { private: Q_OBJECT ModelWidget *model_wgt; void setAttributes(DatabaseModel *model, BaseObject *object, BaseObject *parent_obj); public: ObjectDepsRefsWidget(QWidget * parent = nullptr); void setAttributes(ModelWidget *model_wgt, BaseObject *object, BaseObject *parent_obj=nullptr); public slots: void applyConfiguration(void); private slots: void clearTables(void); void updateObjectTables(void); void handleItemSelection(QTableWidgetItem *item); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/objectfinderwidget.cpp000066400000000000000000000377501360462764600240310ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectfinderwidget.h" #include "pgmodeleruins.h" const QStringList ObjectFinderWidget::search_attribs = { Attributes::Name, Attributes::Comment, Attributes::Signature, Attributes::Schema, Attributes::Owner, Attributes::Tablespace, Attributes::Type, Attributes::ReturnType }; const QStringList ObjectFinderWidget::search_attribs_i18n = { QT_TR_NOOP("Name"), QT_TR_NOOP("Comment"), QT_TR_NOOP("Signature"), QT_TR_NOOP("Schema"), QT_TR_NOOP("Owner"), QT_TR_NOOP("Tablespace"), QT_TR_NOOP("Data type"), QT_TR_NOOP("Return type")}; ObjectFinderWidget::ObjectFinderWidget(QWidget *parent) : QWidget(parent) { setupUi(this); filter_frm->setVisible(false); splitter->handle(1)->setEnabled(false); updateObjectTypeList(obj_types_lst); select_menu.addAction(trUtf8("Listed"), this, SLOT(selectObjects())); select_menu.addAction(trUtf8("Not listed"), this, SLOT(selectObjects())); select_btn->setMenu(&select_menu); fade_menu.addAction(trUtf8("Listed"), this, SLOT(fadeObjects())); fade_menu.addAction(trUtf8("Not listed"), this, SLOT(fadeObjects())); fade_btn->setMenu(&fade_menu); connect(filter_btn, SIGNAL(toggled(bool)), filter_frm, SLOT(setVisible(bool))); connect(filter_btn, &QToolButton::toggled, [&](){ splitter->setSizes({0, 1000}); splitter->handle(1)->setEnabled(filter_btn->isChecked()); }); connect(find_btn, SIGNAL(clicked(bool)), this, SLOT(findObjects(void))); connect(hide_tb, SIGNAL(clicked(void)), this, SLOT(hide(void))); connect(result_tbw, SIGNAL(itemPressed(QTableWidgetItem*)), this, SLOT(selectObject(void))); connect(result_tbw, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(editObject(void))); connect(clear_res_btn, SIGNAL(clicked(void)), this, SLOT(clearResult(void))); connect(select_all_btn, SIGNAL(clicked(void)), this, SLOT(setAllObjectsChecked(void))); connect(clear_all_btn, SIGNAL(clicked(void)), this, SLOT(setAllObjectsChecked(void))); for(auto &attr : search_attribs_i18n) search_attrs_cmb->addItem(attr); this->setModel(nullptr); pattern_edt->installEventFilter(this); } bool ObjectFinderWidget::eventFilter(QObject *object, QEvent *event) { QKeyEvent *k_event=dynamic_cast(event); //Executes the search when user press enter/return on the pattern field if(event->type() == QEvent::KeyPress && (k_event->key()==Qt::Key_Return || k_event->key()==Qt::Key_Enter)) { find_btn->click(); return(true); } else return(QWidget::eventFilter(object, event)); } void ObjectFinderWidget::hide(void) { QWidget::hide(); emit s_visibilityChanged(false); } void ObjectFinderWidget::showEvent(QShowEvent *) { pattern_edt->setFocus(); } void ObjectFinderWidget::resizeEvent(QResizeEvent *event) { Qt::ToolButtonStyle style=Qt::ToolButtonTextBesideIcon; if(event->size().width() < this->baseSize().width()) style=Qt::ToolButtonIconOnly; if(find_btn->toolButtonStyle()!=style) { filter_btn->setToolButtonStyle(style); find_btn->setToolButtonStyle(style); clear_res_btn->setToolButtonStyle(style); select_btn->setToolButtonStyle(style); fade_btn->setToolButtonStyle(style); } } void ObjectFinderWidget::fadeObjects(void) { if(!model_wgt) return; vector objects, other_objs; bool fade_listed = false; for(auto obj_type : {ObjectType::Table, ObjectType::ForeignTable, ObjectType::View, ObjectType::Textbox, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Schema}) { objects.insert(objects.end(), model_wgt->getDatabaseModel()->getObjectList(obj_type)->begin(), model_wgt->getDatabaseModel()->getObjectList(obj_type)->end()); } model_wgt->fadeObjects(objects, true); if(!fade_menu.actions().contains(qobject_cast(sender()))) return; fade_listed = qobject_cast(sender()) == fade_menu.actions().at(0); std::sort(objects.begin(), objects.end()); std::sort(found_objs.begin(), found_objs.end()); std::set_difference(objects.begin(), objects.end(), found_objs.begin(), found_objs.end(), std::inserter(other_objs, other_objs.begin())); model_wgt->fadeObjects(found_objs, !fade_listed); model_wgt->fadeObjects(other_objs, fade_listed); } void ObjectFinderWidget::selectObjects(void) { if(!model_wgt) return; vector objects, other_objs; BaseObjectView *obj_view = nullptr; BaseGraphicObject *graph_obj = nullptr; bool sel_listed = false; for(auto obj_type : {ObjectType::Table, ObjectType::View, ObjectType::Textbox, ObjectType::Relationship, ObjectType::BaseRelationship, ObjectType::Schema}) { objects.insert(objects.end(), model_wgt->getDatabaseModel()->getObjectList(obj_type)->begin(), model_wgt->getDatabaseModel()->getObjectList(obj_type)->end()); } model_wgt->scene->blockSignals(true); fadeObjects(); model_wgt->scene->blockSignals(false); sel_listed = qobject_cast(sender()) == select_menu.actions().at(0); std::sort(objects.begin(), objects.end()); std::sort(found_objs.begin(), found_objs.end()); std::set_difference(objects.begin(), objects.end(), found_objs.begin(), found_objs.end(), std::inserter(other_objs, other_objs.begin())); objects.clear(); if(sel_listed) objects.assign(found_objs.begin(), found_objs.end()); else objects.assign(other_objs.begin(), other_objs.end()); for(auto &obj : objects) { graph_obj = dynamic_cast(obj); if(graph_obj) { obj_view = dynamic_cast(graph_obj->getOverlyingObject()); if(obj_view) { obj_view->blockSignals(true); obj_view->setSelected(true); obj_view->blockSignals(false); } } } model_wgt->configureObjectSelection(); } void ObjectFinderWidget::setModel(ModelWidget *model_wgt) { bool enable=model_wgt!=nullptr; clearResult(); this->model_wgt=model_wgt; filter_btn->setEnabled(enable); pattern_edt->setEnabled(enable); filter_frm->setEnabled(enable); pattern_lbl->setEnabled(enable); find_btn->setEnabled(enable); result_tbw->setEnabled(enable); } void ObjectFinderWidget::clearResult(void) { selected_obj=nullptr; found_objs.clear(); result_tbw->clearContents(); result_tbw->setRowCount(0); found_lbl->setVisible(false); clear_res_btn->setEnabled(false); select_btn->setEnabled(false); fade_btn->setEnabled(false); } void ObjectFinderWidget::findObjects(void) { if(model_wgt) { vector types; QString search_attr = search_attribs.at(search_attrs_cmb->currentIndex()); QTableWidgetItem *item = result_tbw->horizontalHeaderItem(result_tbw->columnCount() - 1); clearResult(); //Getting the selected object types for(int i=0; i < obj_types_lst->count(); i++) { if(obj_types_lst->item(i)->checkState()==Qt::Checked) types.push_back(static_cast(obj_types_lst->item(i)->data(Qt::UserRole).toUInt())); } //Search the objects on model found_objs=model_wgt->getDatabaseModel()->findObjects(pattern_edt->text(), types, case_sensitive_chk->isChecked(), regexp_chk->isChecked(), exact_match_chk->isChecked(), search_attr); //Show the found objects on the result table updateObjectTable(result_tbw, found_objs, search_attr); //Rename the last column of the results grid wth the name of the field used to search objects if(search_attr != Attributes::Name && search_attr != Attributes::Schema && search_attr != Attributes::Comment) item->setText(search_attrs_cmb->currentText()); else item->setText(trUtf8("Comment")); found_lbl->setVisible(true); //Show a message indicating the number of found objects if(!found_objs.empty()) { found_lbl->setText(trUtf8("Found %1 object(s).").arg(found_objs.size())); result_tbw->horizontalHeader()->setStretchLastSection(true); result_tbw->resizeColumnsToContents(); } else found_lbl->setText(trUtf8("No objects found.")); clear_res_btn->setEnabled(!found_objs.empty()); select_btn->setEnabled(!found_objs.empty()); fade_btn->setEnabled(!found_objs.empty()); fadeObjects(); } } void ObjectFinderWidget::selectObject(void) { QTableWidgetItem *tab_item=result_tbw->item(result_tbw->currentRow(), 0); if(tab_item) { selected_obj=reinterpret_cast(tab_item->data(Qt::UserRole).value()); if(QApplication::mouseButtons()!=Qt::RightButton) { BaseGraphicObject *graph_obj=dynamic_cast(selected_obj); TableObject *tab_obj=dynamic_cast(selected_obj); if(tab_obj && !graph_obj) graph_obj=dynamic_cast(tab_obj->getParentTable()); if(graph_obj) { BaseObjectView *obj=dynamic_cast(graph_obj->getOverlyingObject()); if(obj) { model_wgt->scene->clearSelection(); model_wgt->viewport->centerOn(obj); obj->setSelected(true); } } } //Showing the popup menu for the selected object in the result set else { model_wgt->configureObjectMenu(selected_obj); model_wgt->showObjectMenu(); } } } void ObjectFinderWidget::editObject(void) { if(selected_obj) { if(selected_obj->getObjectType()==ObjectType::Permission) model_wgt->showObjectForm(ObjectType::Permission, dynamic_cast(selected_obj)->getObject()); else { vector vect; vect.push_back(selected_obj); model_wgt->scene->clearSelection(); model_wgt->configurePopupMenu(vect); model_wgt->editObject(); } selected_obj=nullptr; } } void ObjectFinderWidget::setAllObjectsChecked(void) { bool checked=(sender()==select_all_btn); for(int i=0; i < obj_types_lst->count(); i++) obj_types_lst->item(i)->setCheckState((checked ? Qt::Checked : Qt::Unchecked)); } void ObjectFinderWidget::updateObjectTable(QTableWidget *tab_wgt, vector &objs, const QString &search_attr) { if(tab_wgt && tab_wgt->columnCount()!=0) { unsigned lin_idx, i; QTableWidgetItem *tab_item=nullptr; BaseObject *parent_obj=nullptr; QFont fnt; QString str_aux; bool new_row = false; tab_wgt->setUpdatesEnabled(false); tab_wgt->setSortingEnabled(false); for(lin_idx=0, i=0; i < objs.size(); i++) { if(objs[i]->getObjectType()==ObjectType::BaseRelationship) str_aux=QString("tv"); else str_aux.clear(); new_row = false; if(static_cast(lin_idx) >= tab_wgt->rowCount()) { tab_wgt->insertRow(lin_idx); new_row = true; } //First column: Object id tab_item=(new_row ? new QTableWidgetItem : tab_wgt->item(lin_idx, 0)); tab_item->setText(QString::number(objs[i]->getObjectId())); tab_item->setData(Qt::UserRole, QVariant::fromValue(reinterpret_cast(objs[i]))); if(new_row) tab_wgt->setItem(lin_idx, 0, tab_item); //Second column: Object name if(tab_wgt->columnCount() > 1) { tab_item=(new_row ? new QTableWidgetItem : tab_wgt->item(lin_idx, 1)); tab_item->setData(Qt::UserRole, QVariant::fromValue(reinterpret_cast(objs[i]))); fnt=tab_item->font(); tab_item->setText(objs[i]->getName()); tab_item->setIcon(QPixmap(PgModelerUiNs::getIconPath(BaseObject::getSchemaName(objs[i]->getObjectType()) + str_aux))); if(new_row) tab_wgt->setItem(lin_idx, 1, tab_item); if(objs[i]->isProtected() || objs[i]->isSystemObject()) { fnt.setItalic(true); tab_item->setForeground(BaseObjectView::getFontStyle(Attributes::ProtColumn).foreground()); } else if(dynamic_cast(objs[i]) && dynamic_cast(objs[i])->isAddedByRelationship()) { fnt.setItalic(true); tab_item->setForeground(BaseObjectView::getFontStyle(Attributes::InhColumn).foreground()); } else { fnt.setItalic(false); tab_item->setForeground(BaseObjectView::getFontStyle(Attributes::Column).foreground()); } fnt.setStrikeOut(objs[i]->isSQLDisabled() && !objs[i]->isSystemObject()); tab_item->setFont(fnt); fnt.setStrikeOut(false); } //Third column: Object type if(tab_wgt->columnCount() > 2) { fnt.setItalic(true); tab_item=(new_row ? new QTableWidgetItem : tab_wgt->item(lin_idx, 2)); tab_item->setFont(fnt); tab_item->setText(objs[i]->getTypeName()); if(new_row) tab_wgt->setItem(lin_idx, 2, tab_item); } //Fourth column: Parent object name if(tab_wgt->columnCount() > 3) { tab_item=(new_row ? new QTableWidgetItem : tab_wgt->item(lin_idx, 3)); if(dynamic_cast(objs[i])) parent_obj=dynamic_cast(objs[i])->getParentTable(); else if(objs[i]->getSchema()) parent_obj=objs[i]->getSchema(); else if(dynamic_cast(objs[i])) parent_obj=dynamic_cast(objs[i])->getObject(); else parent_obj=objs[i]->getDatabase(); tab_item->setText(parent_obj ? parent_obj->getName() : QString("-")); tab_item->setData(Qt::UserRole, QVariant::fromValue(reinterpret_cast(parent_obj))); if(new_row) tab_wgt->setItem(lin_idx, 3, tab_item); if(parent_obj) { if(parent_obj->isProtected() || parent_obj->isSystemObject()) { fnt.setItalic(true); tab_item->setForeground(BaseObjectView::getFontStyle(Attributes::ProtColumn).foreground()); } else { fnt.setItalic(false); tab_item->setForeground(BaseObjectView::getFontStyle(Attributes::Column).foreground()); } tab_item->setFont(fnt); tab_item->setIcon(QPixmap(PgModelerUiNs::getIconPath(parent_obj->getObjectType()))); } } //Fifth column: Parent object type if(tab_wgt->columnCount() > 4) { tab_item=(new_row ? new QTableWidgetItem : tab_wgt->item(lin_idx, 4)); fnt.setItalic(true); tab_item->setFont(fnt); tab_item->setText(parent_obj ? parent_obj->getTypeName() : QString("-")); if(new_row) tab_wgt->setItem(lin_idx, 4, tab_item); } //Sixth column: object comment if(tab_wgt->columnCount() > 5) { tab_item=(new_row ? new QTableWidgetItem : tab_wgt->item(lin_idx, 5)); fnt.setItalic(false); tab_item->setFont(fnt); if(search_attr != Attributes::Name && search_attr != Attributes::Schema && search_attr != Attributes::Comment) tab_item->setText(objs[i]->getSearchAttributes().at(search_attr)); else tab_item->setText(objs[i]->getComment()); if(new_row) tab_wgt->setItem(lin_idx, 5, tab_item); } lin_idx++; } if(static_cast(objs.size()) != tab_wgt->rowCount()) tab_wgt->setRowCount(objs.size()); tab_wgt->setUpdatesEnabled(true); tab_wgt->setSortingEnabled(true); tab_wgt->resizeColumnsToContents(); tab_wgt->resizeRowsToContents(); } } void ObjectFinderWidget::updateObjectTypeList(QListWidget *list_wgt) { vector types=BaseObject::getObjectTypes(); QListWidgetItem *item=nullptr; QPixmap icon; QString str_aux; if(list_wgt) { list_wgt->clear(); //Creating the visible object list for(unsigned type_id=0; type_id < types.size(); type_id++) { item=new QListWidgetItem; if(types[type_id]==ObjectType::BaseRelationship) str_aux=QString(BaseObject::getSchemaName(types[type_id])) + QString("tv"); else str_aux=QString(BaseObject::getSchemaName(types[type_id])); icon=QPixmap(PgModelerUiNs::getIconPath(str_aux)); item->setText(BaseObject::getTypeName(types[type_id])); item->setIcon(icon); //By default all object types are checked item->setCheckState(Qt::Checked); item->setData(Qt::UserRole, QVariant(enum_cast(types[type_id]))); list_wgt->insertItem(type_id, item); } } } pgmodeler-0.9.2/libpgmodeler_ui/src/objectfinderwidget.h000066400000000000000000000054521360462764600234700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectFinderWidget \brief Implements the operations to find objects over the model */ #ifndef OBJECT_FINDER_WIDGET_H #define OBJECT_FINDER_WIDGET_H #include "ui_objectfinderwidget.h" #include "pgmodelerns.h" #include "modelwidget.h" #include class ObjectFinderWidget : public QWidget, public Ui::ObjectFinderWidget { private: Q_OBJECT /*! \brief Store in a unordered list the attributes in order to allow the user * select which attribute will be used to search objects */ static const QStringList search_attribs, /*! \brief Store in a unordered list the attributes in a translated way in order to * populate the combo box used to select which attribute will be used to search objects */ search_attribs_i18n; vector found_objs; QMenu select_menu, fade_menu; //! \brief Reference model widget ModelWidget *model_wgt; //! \brief Stores the selected object on the result list BaseObject *selected_obj; //! \brief Captures the ENTER press to execute search bool eventFilter(QObject *object, QEvent *event); void showEvent(QShowEvent *); void resizeEvent(QResizeEvent *event); public: ObjectFinderWidget(QWidget *parent = nullptr); //! \brief Lists all valid types in a QListWidget static void updateObjectTypeList(QListWidget *list_wgt); /*! \brief Lists the objects of a vector in a QTableWidget. Any row of table contains the reference to the object on the first column */ static void updateObjectTable(QTableWidget *tab_wgt, vector &objects, const QString &search_attr = Attributes::Name); //! \brief Sets the database model to work on void setModel(ModelWidget *model_wgt); signals: void s_visibilityChanged(bool); public slots: void hide(void); void clearResult(void); void findObjects(void); private slots: //! \brief Opens the editing form of the selected object void editObject(void); //! \brief Selects a object on result list void selectObject(void); void setAllObjectsChecked(void); void fadeObjects(void); void selectObjects(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/objectrenamewidget.cpp000066400000000000000000000135421360462764600240220ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectrenamewidget.h" #include "pgmodeleruins.h" ObjectRenameWidget::ObjectRenameWidget(QWidget * parent) : QDialog(parent) { object=nullptr; op_list=nullptr; model=nullptr; setupUi(this); setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); connect(new_name_edt, SIGNAL(returnPressed(void)), this, SLOT(applyRenaming(void))); connect(apply_tb, SIGNAL(clicked(void)), this, SLOT(applyRenaming(void))); connect(cancel_tb, SIGNAL(clicked(void)), this, SLOT(reject(void))); } void ObjectRenameWidget::setAttributes(BaseObject *object, DatabaseModel *model, OperationList *op_list) { TableObject *tab_obj=dynamic_cast(object); if(!object || !op_list) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(tab_obj && tab_obj->isAddedByRelationship()) throw Exception(Exception::getErrorMessage(ErrorCode::OprRelationshipAddedObject) .arg(tab_obj->getName()) .arg(tab_obj->getTypeName()), ErrorCode::OprRelationshipAddedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->adjustSize(); this->object=object; this->op_list=op_list; this->model=model; obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(object->getSchemaName()))); obj_icon_lbl->setToolTip(object->getTypeName()); obj_name_lbl->setText(object->getName()); new_name_edt->setText(object->getName()); } int ObjectRenameWidget::exec(void) { if(object && op_list) return(QDialog::exec()); else return(QDialog::Rejected); } void ObjectRenameWidget::hideEvent(QHideEvent *) { object=nullptr; op_list=nullptr; model=nullptr; new_name_edt->clear(); obj_name_lbl->clear(); } void ObjectRenameWidget::applyRenaming(void) { ObjectType obj_type=ObjectType::BaseObject; try { //Apply the new name only when its not empty and its differs from the original one if(!new_name_edt->text().isEmpty() && this->object->getName()!=new_name_edt->text()) { BaseGraphicObject *obj_graph=dynamic_cast(object); TableObject *tab_obj=dynamic_cast(object); BaseObject *aux_obj=nullptr, *parent_obj=nullptr; QString fmt_name; vector ref_objs; obj_type=object->getObjectType(); if(obj_type!=ObjectType::Database) { //Register the object on operations list before the modification op_list->registerObject(object, Operation::ObjectModified, -1, (tab_obj ? tab_obj->getParentTable() : nullptr)); //Format the object name to check if it will have a conflicting name fmt_name=BaseObject::formatName(new_name_edt->text().toUtf8(), obj_type==ObjectType::Operator); if(object->getSchema()) fmt_name=object->getSchema()->getName(true) + QString(".") + fmt_name; //For table child object, check if there is another object with the same new name if(tab_obj) { parent_obj=tab_obj->getParentTable(); aux_obj=dynamic_cast(tab_obj->getParentTable())->getObject(fmt_name, obj_type); } //For database child object, check if there is another object with the same new name else { parent_obj=model; aux_obj=model->getObject(fmt_name, obj_type); } //Raises a error if another object is found if(aux_obj && aux_obj!=object) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject) .arg(fmt_name) .arg(object->getTypeName()) .arg(parent_obj->getName(true)) .arg(parent_obj->getTypeName()), ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } object->setName(new_name_edt->text().toUtf8()); //If the renamed object is a graphical one, set as modified to force its redraw if(object->getObjectType()==ObjectType::Schema) { model->validateSchemaRenaming(dynamic_cast(object), obj_name_lbl->text().toUtf8()); dynamic_cast(object)->setModified(true); } else if(obj_graph) { obj_graph->setModified(true); if(BaseTable::isBaseTable(obj_graph->getObjectType())) dynamic_cast(obj_graph->getSchema())->setModified(true); } else if(tab_obj) { BaseTable *base_tab = tab_obj->getParentTable(); PhysicalTable *tab = dynamic_cast(base_tab); Column *col=dynamic_cast(tab_obj); /* If the object is a column and some primary key on table is referencing it * the model relationship will be revalidated */ if(col && tab) { model->validateRelationships(); model->updateViewsReferencingTable(tab); } base_tab->setModified(true); base_tab->setCodeInvalidated(true); dynamic_cast(base_tab->getSchema())->setModified(true); } Column *col=nullptr; model->getObjectReferences(object, ref_objs); for(auto &obj : ref_objs) { if(obj->getObjectType()==ObjectType::Column) { col=dynamic_cast(obj); col->getParentTable()->setModified(true); col->setCodeInvalidated(true); } else obj->setCodeInvalidated(true); } accept(); } } catch(Exception &e) { Messagebox msg_box; if(obj_type!=ObjectType::Database) op_list->removeLastOperation(); msg_box.show(e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/objectrenamewidget.h000066400000000000000000000031711360462764600234640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectRenameWidget \brief Widget used to quickly rename objects without open the editing form */ #ifndef OBJECT_RENAME_WIDGET_H #define OBJECT_RENAME_WIDGET_H #include #include "ui_objectrenamewidget.h" #include "databasemodel.h" #include "operationlist.h" #include "messagebox.h" class ObjectRenameWidget: public QDialog, public Ui::ObjectRenameWidget { private: Q_OBJECT //! \brief Object to be renamed BaseObject *object; //! \brief Operation list used to register the modification over object OperationList *op_list; //! \brief Model used to made duplicity name validations DatabaseModel *model; void hideEvent(QHideEvent *); public: ObjectRenameWidget(QWidget *parent); void setAttributes(BaseObject *object, DatabaseModel *model, OperationList *op_list); public slots: int exec(void); private slots: void applyRenaming(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/objectsdiffinfo.cpp000066400000000000000000000067631360462764600233250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectsdiffinfo.h" constexpr unsigned ObjectsDiffInfo::CreateObject; constexpr unsigned ObjectsDiffInfo::DropObject; constexpr unsigned ObjectsDiffInfo::AlterObject; constexpr unsigned ObjectsDiffInfo::IgnoreObject; constexpr unsigned ObjectsDiffInfo::NoDifference; ObjectsDiffInfo::ObjectsDiffInfo(void) { object=old_object=nullptr; diff_type=NoDifference; } ObjectsDiffInfo::ObjectsDiffInfo(unsigned diff_type, BaseObject *object, BaseObject *new_object) { this->diff_type=diff_type; this->object=object; this->old_object=new_object; } unsigned ObjectsDiffInfo::getDiffType(void) { return(diff_type); } QString ObjectsDiffInfo::getInfoMessage(void) { QString msg=QString("%1 `%2' (%3)"), obj_name; BaseObject *ref_obj=nullptr; ObjectType obj_type=ObjectType::BaseObject; if(diff_type==AlterObject && old_object) ref_obj=old_object; else ref_obj=object; obj_type=ref_obj->getObjectType(); /* Forcing the usage of BaseObject::getSignature for the following object, since the custom getSignature for those types return some undesired SQL keywords for this context */ if(obj_type==ObjectType::Constraint || obj_type==ObjectType::Trigger || obj_type==ObjectType::Rule) obj_name=dynamic_cast(ref_obj)->TableObject::getSignature(); else if(obj_type==ObjectType::OpClass || obj_type==ObjectType::OpFamily) obj_name=ref_obj->BaseObject::getSignature(); else obj_name=ref_obj->getSignature(); if(diff_type==NoDifference) return(QString()); else if(diff_type==DropObject) { msg=msg.arg(QString("DROP")) .arg(obj_name) .arg(ref_obj->getTypeName()); } else if(diff_type==CreateObject) { msg=msg.arg(QString("CREATE")) .arg(obj_name) .arg(ref_obj->getTypeName()); } else if(diff_type==AlterObject) { msg=msg.arg(QString("ALTER")) .arg(obj_name) .arg(ref_obj->getTypeName()); } else if(diff_type==IgnoreObject) { msg=msg.arg(QString("IGNORE")) .arg(obj_name) .arg(ref_obj->getTypeName()); } return(msg); } QString ObjectsDiffInfo::getDiffTypeString(void) { if(diff_type==NoDifference) return(QString()); else if(diff_type==DropObject) return(QString("DROP")); else if(diff_type==CreateObject) return(QString("CREATE")); else if(diff_type==AlterObject) return(QString("ALTER")); else return(QString("IGNORE")); } BaseObject *ObjectsDiffInfo::getObject(void) { return(object); } BaseObject *ObjectsDiffInfo::getOldObject(void) { return(old_object); } bool ObjectsDiffInfo::operator == (ObjectsDiffInfo &info) { return(this->diff_type==info.diff_type && this->object==info.object && this->old_object==info.old_object); } pgmodeler-0.9.2/libpgmodeler_ui/src/objectsdiffinfo.h000066400000000000000000000032551360462764600227630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectsDiffInfo \brief Stores information about difference between two objects when the models are being compared. Instances of this class are emitted during the diff process on ModelsDiffHelper class. */ #ifndef OBJECTS_DIFF_INFO_H #define OBJECTS_DIFF_INFO_H #include "tableobject.h" class ObjectsDiffInfo { private: //! \brief Difference type (see constants below) unsigned diff_type; BaseObject *object, *old_object; public: static constexpr unsigned CreateObject=0, DropObject=1, AlterObject=2, IgnoreObject=3, NoDifference=4; ObjectsDiffInfo(void); ObjectsDiffInfo(unsigned diff_type, BaseObject *ref_object, BaseObject *old_object); unsigned getDiffType(void); QString getInfoMessage(void); QString getDiffTypeString(void); BaseObject *getObject(void); BaseObject *getOldObject(void); bool operator == (ObjectsDiffInfo &info); friend class ModelsDiffHelper; friend class QVariant; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/objectselectorwidget.cpp000066400000000000000000000125041360462764600243700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectselectorwidget.h" ObjectSelectorWidget::ObjectSelectorWidget(ObjectType sel_obj_type, bool install_highlighter, QWidget *parent) : QWidget(parent) { try { this->sel_obj_types.push_back(sel_obj_type); configureSelector(install_highlighter); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } ObjectSelectorWidget::ObjectSelectorWidget(vector sel_obj_types, bool install_highlighter, QWidget * parent) : QWidget(parent) { try { this->sel_obj_types=sel_obj_types; configureSelector(install_highlighter); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ObjectSelectorWidget::configureSelector(bool install_highlighter) { try { Ui_ObjectSelectorWidget::setupUi(this); obj_view_wgt=new ModelObjectsWidget(true); model=nullptr; selected_obj=nullptr; obj_name_hl=nullptr; if(install_highlighter) { obj_name_hl=new SyntaxHighlighter(obj_name_txt, true); obj_name_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); } else { //Adding a custom height to the input if the highlighter isn't installed QFontMetrics fm=obj_name_txt->fontMetrics(); obj_name_txt->setMaximumHeight(fm.height() + (fm.lineSpacing()/1.8)); this->adjustSize(); } connect(sel_object_tb, SIGNAL(clicked(bool)), this, SLOT(showObjectView(void))); connect(rem_object_tb, SIGNAL(clicked(bool)), this, SLOT(clearSelector(void))); connect(obj_view_wgt, SIGNAL(s_visibilityChanged(BaseObject*,bool)), this, SLOT(showSelectedObject(BaseObject*, bool))); obj_name_txt->installEventFilter(this); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } bool ObjectSelectorWidget::eventFilter(QObject *obj, QEvent *evnt) { if(this->isEnabled() && evnt->type()==QEvent::FocusIn && QApplication::mouseButtons()==Qt::LeftButton && obj==obj_name_txt) { QFocusEvent *focus_evnt = dynamic_cast(evnt); if(focus_evnt->reason() == Qt::MouseFocusReason) { showObjectView(); return(true); } } return(QWidget::eventFilter(obj, evnt)); } ObjectSelectorWidget::~ObjectSelectorWidget(void) { delete(obj_view_wgt); } void ObjectSelectorWidget::enableObjectCreation(bool value) { obj_view_wgt->enableObjectCreation(value); } BaseObject *ObjectSelectorWidget::getSelectedObject(void) { return(selected_obj); } QString ObjectSelectorWidget::getSelectedObjectName(void) { return(selected_obj->getSignature()); } void ObjectSelectorWidget::setSelectedObject(BaseObject *object) { ObjectType obj_type = ObjectType::BaseObject; if(object) obj_type=object->getObjectType(); if(object && std::find(sel_obj_types.begin(), sel_obj_types.end(),obj_type)!=sel_obj_types.end()) { rem_object_tb->setEnabled(object); this->selected_obj=object; if(obj_type != ObjectType::Constraint) { if(obj_type != ObjectType::UserMapping) obj_name_txt->setPlainText(selected_obj->getSignature()); else obj_name_txt->setPlainText(selected_obj->getName()); } else obj_name_txt->setPlainText(QString("%1.%2") .arg(dynamic_cast(selected_obj)->getParentTable()->getSignature()) .arg(selected_obj->getName(true))); emit s_objectSelected(); emit s_selectorChanged(true); } else clearSelector(); } void ObjectSelectorWidget::setSelectedObject(const QString &obj_name, ObjectType obj_type) { try { BaseObject *object=nullptr; if(model && std::find(sel_obj_types.begin(), sel_obj_types.end(),obj_type)!=sel_obj_types.end()) object=model->getObject(obj_name, obj_type); setSelectedObject(object); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void ObjectSelectorWidget::setModel(DatabaseModel *modelo) { this->model=modelo; } void ObjectSelectorWidget::showSelectedObject(BaseObject *obj_sel, bool) { if(obj_sel) setSelectedObject(obj_sel); } void ObjectSelectorWidget::clearSelector(void) { this->selected_obj=nullptr; obj_name_txt->clear(); rem_object_tb->setEnabled(false); emit s_selectorCleared(); emit s_selectorChanged(false); } void ObjectSelectorWidget::showObjectView(void) { obj_name_txt->clearFocus(); for(unsigned i=0; i < sel_obj_types.size(); i++) obj_view_wgt->setObjectVisible(sel_obj_types[i], true); if(sel_obj_types.size()==1) obj_view_wgt->setWindowTitle(trUtf8("Select %1").arg(BaseObject::getTypeName(sel_obj_types[0]).toLower())); obj_view_wgt->setModel(this->model); obj_view_wgt->show(); } pgmodeler-0.9.2/libpgmodeler_ui/src/objectselectorwidget.h000066400000000000000000000065171360462764600240440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectSelectorWidget \brief Implements a simple object picker based upon the object view widget. */ #ifndef OBJECT_SELECTOR_WIDGET_H #define OBJECT_SELECTOR_WIDGET_H #include #include "databasemodel.h" #include "syntaxhighlighter.h" #include "modelobjectswidget.h" #include "ui_objectselectorwidget.h" class ObjectSelectorWidget: public QWidget, public Ui::ObjectSelectorWidget { private: Q_OBJECT //! \brief An object view widget instance used as object picker ModelObjectsWidget *obj_view_wgt; //! \brief Selected object name highlighter SyntaxHighlighter *obj_name_hl; //! \brief Selected object reference BaseObject *selected_obj; //! \brief Object types that the selector is able to pick vector sel_obj_types; //! \brief Stores the database model which the selector must search the object DatabaseModel *model; //! \brief Configures the selectors attributes at construction time void configureSelector(bool install_highlighter); bool eventFilter(QObject *obj, QEvent *evnt); public: ObjectSelectorWidget(ObjectType sel_obj_type, bool install_highlighter, QWidget * parent = nullptr); ObjectSelectorWidget(vector sel_obj_types, bool install_highlighter, QWidget * parent = nullptr); ~ObjectSelectorWidget(void); //! \brief Enables the creation of new objects from withing the object selector dialog void enableObjectCreation(bool value); //! \brief Returns the reference to the selected object BaseObject *getSelectedObject(void); //! \brief Returns the selected object formated name QString getSelectedObjectName(void); //! \brief Defines the initial selected object to be show on the selector void setSelectedObject(BaseObject *object); //! \brief Defines the initial selected object to be show on the selector by searching it using the obj_name void setSelectedObject(const QString &obj_name, ObjectType obj_type); //! \brief Defines the model which the selector will search the objects void setModel(DatabaseModel *model); private slots: void showSelectedObject(BaseObject *obj_sel, bool=false); //! \brief Shows the object view widget (picker) void showObjectView(void); public slots: void clearSelector(void); signals: //! \brief Signal emitted when the user selects an object void s_objectSelected(void); //! \brief Signal emitted when the user clears the selector void s_selectorCleared(void); /*! \brief Signal emitted when the user clears the selector or selects and object * The boolean param indicates if there's an object selected or not */ void s_selectorChanged(bool); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/objectstablewidget.cpp000066400000000000000000000455651360462764600240370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "objectstablewidget.h" ObjectsTableWidget::ObjectsTableWidget(unsigned button_conf, bool conf_exclusion, QWidget *parent): QWidget(parent) { setupUi(this); connect(move_down_tb, SIGNAL(clicked(bool)), this, SLOT(moveRows(void))); connect(move_up_tb, SIGNAL(clicked(bool)), this, SLOT(moveRows(void))); connect(move_first_tb, SIGNAL(clicked(bool)), this, SLOT(moveRows(void))); connect(move_last_tb, SIGNAL(clicked(bool)), this, SLOT(moveRows(void))); connect(add_tb, SIGNAL(clicked(bool)), this, SLOT(addRow(void))); connect(remove_tb, SIGNAL(clicked(bool)), this, SLOT(removeRow(void))); connect(edit_tb, SIGNAL(clicked(bool)), this, SLOT(editRow(void))); connect(update_tb, SIGNAL(clicked(bool)), this, SLOT(updateRow(void))); connect(duplicate_tb, SIGNAL(clicked(bool)), this, SLOT(duplicateRow(void))); connect(remove_all_tb, SIGNAL(clicked(bool)), this, SLOT(removeRows(void))); connect(table_tbw, SIGNAL(cellClicked(int,int)), this, SLOT(setButtonsEnabled(void))); connect(table_tbw, SIGNAL(cellActivated(int,int)), this, SLOT(setButtonsEnabled(void))); connect(table_tbw, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(editRow(void))); connect(table_tbw, SIGNAL(itemSelectionChanged(void)), this, SLOT(setButtonsEnabled(void))); connect(table_tbw, SIGNAL(itemSelectionChanged(void)), this, SLOT(emitRowSelected(void))); connect(table_tbw, &QTableWidget::cellClicked, [&](int row, int col){ emit s_cellClicked(row, col); }); connect(resize_cols_tb, &QToolButton::clicked, [&](){ table_tbw->resizeColumnsToContents(); table_tbw->resizeRowsToContents(); table_tbw->horizontalHeader()->setSectionResizeMode(table_tbw->horizontalHeader()->count() - 1, QHeaderView::Stretch); }); this->conf_exclusion=conf_exclusion; cells_editable = false; setButtonConfiguration(button_conf); setColumnCount(1); add_tb->setToolTip(add_tb->toolTip() + QString(" (%1)").arg(add_tb->shortcut().toString())); remove_tb->setToolTip(remove_tb->toolTip() + QString(" (%1)").arg(remove_tb->shortcut().toString())); remove_all_tb->setToolTip(remove_all_tb->toolTip() + QString(" (%1)").arg(remove_all_tb->shortcut().toString())); update_tb->setToolTip(update_tb->toolTip() + QString(" (%1)").arg(update_tb->shortcut().toString())); edit_tb->setToolTip(edit_tb->toolTip() + QString(" (%1)").arg(edit_tb->shortcut().toString())); duplicate_tb->setToolTip(duplicate_tb->toolTip() + QString(" (%1)").arg(duplicate_tb->shortcut().toString())); move_last_tb->setToolTip(move_last_tb->toolTip() + QString(" (%1)").arg(move_last_tb->shortcut().toString())); move_first_tb->setToolTip(move_first_tb->toolTip() + QString(" (%1)").arg(move_first_tb->shortcut().toString())); move_up_tb->setToolTip(move_up_tb->toolTip() + QString(" (%1)").arg(move_up_tb->shortcut().toString())); move_down_tb->setToolTip(move_down_tb->toolTip() + QString(" (%1)").arg(move_down_tb->shortcut().toString())); } void ObjectsTableWidget::setButtonConfiguration(unsigned button_conf) { bool move_btn = false; //Checking via bitwise operation the buttons available on the 'button_conf' move_btn=(button_conf & MoveButtons) == MoveButtons; move_down_tb->setVisible(move_btn); move_up_tb->setVisible(move_btn); move_first_tb->setVisible(move_btn); move_last_tb->setVisible(move_btn); edit_tb->setVisible((button_conf & EditButton) == EditButton); remove_all_tb->setVisible((button_conf & RemoveAllButton) == RemoveAllButton); add_tb->setVisible((button_conf & AddButton) == AddButton); remove_tb->setVisible((button_conf & RemoveButton) == RemoveButton); update_tb->setVisible((button_conf & UpdateButton) == UpdateButton); duplicate_tb->setVisible((button_conf & DuplicateButton) == DuplicateButton); //Disabling the horizontal spacers when no buttons are visible if(button_conf==NoButtons) { left_spc->changeSize(0,0,QSizePolicy::Ignored,QSizePolicy::Ignored); right_spc->changeSize(0,0,QSizePolicy::Ignored,QSizePolicy::Ignored); } //Restoring the horizontal spacers when some buttons are visible else { left_spc->changeSize(10,10,QSizePolicy::Expanding,QSizePolicy::Preferred); right_spc->changeSize(10,10,QSizePolicy::Expanding,QSizePolicy::Preferred); } } QTableWidgetItem *ObjectsTableWidget::getItem(unsigned row_idx, unsigned col_idx) { if(row_idx >= static_cast(table_tbw->rowCount())) throw Exception(ErrorCode::RefRowObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(col_idx >= static_cast(table_tbw->columnCount())) throw Exception(ErrorCode::RefColObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(table_tbw->item(row_idx, col_idx)); } void ObjectsTableWidget::adjustColumnToContents(int col) { table_tbw->resizeColumnToContents(col); table_tbw->resizeRowsToContents(); } void ObjectsTableWidget::setColumnCount(unsigned col_count) { if(col_count > 0) { unsigned i; QTableWidgetItem *item=nullptr; i=table_tbw->columnCount(); table_tbw->setColumnCount(col_count); for(;i < col_count; i++) { item=new QTableWidgetItem; item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); table_tbw->setHorizontalHeaderItem(static_cast(i),item); } } } void ObjectsTableWidget::setHeaderLabel(const QString &label, unsigned col_idx) { QTableWidgetItem *item=nullptr; if(col_idx >= static_cast(table_tbw->columnCount())) throw Exception(ErrorCode::RefColObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); item=table_tbw->horizontalHeaderItem(col_idx); item->setText(label); } void ObjectsTableWidget::setHeaderVisible(unsigned col_idx, bool visible) { if(col_idx >= static_cast(table_tbw->columnCount())) throw Exception(ErrorCode::RefColObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); table_tbw->horizontalHeader()->setSectionHidden(col_idx, !visible); } void ObjectsTableWidget::setHeaderIcon(const QIcon &icon, unsigned col_idx) { QTableWidgetItem *item=nullptr; if(col_idx >= static_cast(table_tbw->columnCount())) throw Exception(ErrorCode::RefColObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); item=table_tbw->horizontalHeaderItem(col_idx); item->setIcon(icon); } void ObjectsTableWidget::setCellIcon(const QIcon &icon, unsigned row_idx, unsigned col_idx) { getItem(row_idx, col_idx)->setIcon(icon); } void ObjectsTableWidget::setCellText(const QString &text, unsigned row_idx, unsigned col_idx) { getItem(row_idx, col_idx)->setText(text); } void ObjectsTableWidget::clearCellText(unsigned row_idx, unsigned col_idx) { try { setCellText(QString(), row_idx, col_idx); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ObjectsTableWidget::setRowFont(int row_idx, const QFont &font, const QColor &fg_color, const QColor &bg_color) { QTableWidgetItem *item=nullptr; int col_count, i; if(row_idx >= table_tbw->rowCount()) throw Exception(ErrorCode::RefRowObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); col_count=table_tbw->columnCount(); for(i=0; i < col_count; i++) { item=table_tbw->item(row_idx, i); item->setFont(font); item->setForeground(fg_color); item->setBackgroundColor(bg_color); } } void ObjectsTableWidget::setRowData(const QVariant &data, unsigned row_idx) { QTableWidgetItem *item=nullptr; if(row_idx >= static_cast(table_tbw->rowCount())) throw Exception(ErrorCode::RefRowObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Gets the vertical header of the row. This header stores the whole row data. item=table_tbw->verticalHeaderItem(row_idx); item->setData(Qt::UserRole, data); } unsigned ObjectsTableWidget::getColumnCount(void) { return(table_tbw->columnCount()); } unsigned ObjectsTableWidget::getRowCount(void) { return(table_tbw->rowCount()); } QString ObjectsTableWidget::getHeaderLabel(unsigned col_idx) { QTableWidgetItem *item=nullptr; if(col_idx >= static_cast(table_tbw->columnCount())) throw Exception(ErrorCode::RefColObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); item=table_tbw->horizontalHeaderItem(col_idx); return(item->text()); } QString ObjectsTableWidget::getCellText(unsigned row_idx, unsigned col_idx) { return(getItem(row_idx, col_idx)->text()); } Qt::CheckState ObjectsTableWidget::getCellCheckState(unsigned row_idx, unsigned col_idx) { return(getItem(row_idx, col_idx)->checkState()); } void ObjectsTableWidget::setCellCheckState(unsigned row_idx, unsigned col_idx, Qt::CheckState check_state) { getItem(row_idx, col_idx)->setCheckState(check_state); } void ObjectsTableWidget::setCellDisabled(unsigned row_idx, unsigned col_idx, bool disabled) { QTableWidgetItem *item = getItem(row_idx, col_idx); if(disabled) item->setFlags(Qt::NoItemFlags); else item->setFlags(Qt::ItemIsEnabled); } bool ObjectsTableWidget::isCellDisabled(unsigned row_idx, unsigned col_idx) { return(getItem(row_idx, col_idx)->flags() == Qt::NoItemFlags); } QVariant ObjectsTableWidget::getRowData(unsigned row_idx) { QTableWidgetItem *item=nullptr; if(row_idx >= static_cast(table_tbw->rowCount())) throw Exception(ErrorCode::RefRowObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); item=table_tbw->verticalHeaderItem(row_idx); return(item->data(Qt::UserRole)); } int ObjectsTableWidget::getSelectedRow(void) { return(table_tbw->currentRow()); } int ObjectsTableWidget::getRowIndex(const QVariant &data) { unsigned i, count; QTableWidgetItem *item=nullptr; bool found=false; count=table_tbw->rowCount(); for(i=0; !found && i < count; i++) { item=table_tbw->verticalHeaderItem(i); //Checking if the item data is equal to the passed data found=(item && item->data(Qt::UserRole).value() == data.value()); } if(!found) return(-1); else return(i); } void ObjectsTableWidget::addColumn(unsigned col_idx) { if(col_idx >= static_cast(table_tbw->columnCount())) col_idx=table_tbw->columnCount(); table_tbw->insertColumn(col_idx); table_tbw->clearSelection(); setButtonsEnabled(); emit s_columnAdded(col_idx); } void ObjectsTableWidget::selectRow(int lin_idx) { QTableWidgetItem *item=nullptr; item=table_tbw->item(0,lin_idx); if(item) { item=table_tbw->item(lin_idx,0); item->setSelected(true); table_tbw->setCurrentItem(item); setButtonsEnabled(); } } void ObjectsTableWidget::addRow(unsigned lin_idx) { QTableWidgetItem *item=nullptr; unsigned col_idx, col_cont=table_tbw->columnCount(); table_tbw->insertRow(lin_idx); item=new QTableWidgetItem; item->setText(QString("%1").arg(lin_idx+1)); table_tbw->setVerticalHeaderItem(lin_idx,item); for(col_idx=0; col_idx < col_cont; col_idx++) { item=new QTableWidgetItem; table_tbw->setItem(lin_idx,col_idx,item); } item=table_tbw->item(lin_idx,0); item->setSelected(true); table_tbw->setCurrentItem(item); } void ObjectsTableWidget::addRow(void) { this->addRow(table_tbw->rowCount()); setButtonsEnabled(); table_tbw->resizeRowsToContents(); emit s_rowAdded(table_tbw->rowCount()-1); } void ObjectsTableWidget::removeRow(unsigned row_idx) { unsigned i, count; bool conf; if(row_idx >= static_cast(table_tbw->rowCount())) throw Exception(ErrorCode::RefRowObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Before remove the row, clears the selection table_tbw->clearSelection(); count=table_tbw->columnCount(); //Selects all the columns of the row to be removed for(i=0; i < count; i++) table_tbw->item(row_idx, i)->setSelected(true); table_tbw->setCurrentItem(table_tbw->item(row_idx,0)); //Disable temporarily the exclusion confirmation conf=conf_exclusion; conf_exclusion=false; removeRow(); conf_exclusion=conf; } void ObjectsTableWidget::removeRow(void) { if(table_tbw->currentRow()>=0) { Messagebox msg_box; unsigned row_idx=table_tbw->currentRow(); QTableWidgetItem *item=table_tbw->currentItem(); if(item->isSelected()) { if(conf_exclusion) msg_box.show(trUtf8("Confirmation"),trUtf8("Do you really want to remove the selected item?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(!conf_exclusion || (conf_exclusion && msg_box.result()==QDialog::Accepted)) { setRowData(QVariant::fromValue(nullptr), row_idx); item->setData(Qt::UserRole, QVariant::fromValue(nullptr)); emit s_rowAboutToRemove(row_idx); table_tbw->removeRow(row_idx); table_tbw->setCurrentItem(nullptr); setButtonsEnabled(); emit s_rowRemoved(row_idx); } } } } void ObjectsTableWidget::duplicateRow(void) { if(table_tbw->currentRow() >= 0) { int row = table_tbw->rowCount(), curr_row = table_tbw->currentRow(); QTableWidgetItem *curr_item = nullptr, *dup_item=nullptr; addRow(row); for(int col = 0; col < table_tbw->columnCount(); col++) { curr_item = table_tbw->item(curr_row, col); dup_item = table_tbw->item(row, col); dup_item->setText(curr_item->text()); } emit s_rowDuplicated(curr_row, row); } } void ObjectsTableWidget::removeRows(void) { if(table_tbw->rowCount() > 0) { QObject *sender_obj=sender(); Messagebox msg_box; /* Only shows the confirmation message if the conf_exclusion is set and the user called the method activating the 'remove_all_tb' button */ if(conf_exclusion && sender_obj==remove_all_tb) msg_box.show(trUtf8("Confirmation"),trUtf8("Do you really want to remove all the items?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(!conf_exclusion || (conf_exclusion && sender_obj!=remove_all_tb) || (conf_exclusion && sender_obj==remove_all_tb && msg_box.result()==QDialog::Accepted)) { table_tbw->clearContents(); table_tbw->setRowCount(0); setButtonsEnabled(); emit s_rowsRemoved(); } } } void ObjectsTableWidget::removeColumn(unsigned col_idx) { if(col_idx >= static_cast(table_tbw->columnCount())) throw Exception(ErrorCode::RefColObjectTabInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); table_tbw->removeColumn(col_idx); table_tbw->clearSelection(); setButtonsEnabled(); emit s_columnRemoved(col_idx); } void ObjectsTableWidget::moveRows(void) { QObject *sender_obj=sender(); QTableWidgetItem *item=nullptr, *item1=nullptr; int row=-1, row1=-1; unsigned col, col_count=table_tbw->columnCount(); QVariant aux_data; //Get the current selected row. Based upon this index that rows are swaped row=table_tbw->currentRow(); //If the user click "move down" swap the selected row with the row imediately below if(sender_obj==move_down_tb) row1=row+1; //If the user click "move up" swap the selected row with the row imediately above else if(sender_obj==move_up_tb) row1=row-1; //If the user click "move first" swap the selected row with the first row else if(sender_obj==move_first_tb) { //Add a blank line to swap the data later this->addRow(0); row1=0; row++; } //If the user click "move last" swap the selected row with the last row else if(sender_obj==move_last_tb) { //Add a row at the end of the table this->addRow(table_tbw->rowCount()); row1=table_tbw->rowCount()-1; } //Checking if the row indexes are valid if(row >= 0 && row < table_tbw->rowCount() && row1 >= 0 && row1 < table_tbw->rowCount() && row != row1) { //To swap the rows is necessary to swap all columns one by one for(col=0; col < col_count; col++) { item=table_tbw->item(row, col); table_tbw->takeItem(row, col); item1=table_tbw->item(row1, col); table_tbw->takeItem(row1, col); table_tbw->setItem(row, col, item1); table_tbw->setItem(row1, col, item); item1->setSelected(false); item->setSelected(true); } table_tbw->setCurrentItem(item); //Swapping the row data item=table_tbw->verticalHeaderItem(row); item1=table_tbw->verticalHeaderItem(row1); if(item && item1) { aux_data=item->data(Qt::UserRole); item->setData(Qt::UserRole, item1->data(Qt::UserRole)); item1->setData(Qt::UserRole, aux_data); } //Special case for "move last" and "move first" if(sender_obj==move_last_tb || sender_obj==move_first_tb) { table_tbw->removeRow(row); if(sender_obj==move_first_tb) { row1=row-1; row=table_tbw->rowCount(); } } setButtonsEnabled(); table_tbw->resizeRowsToContents(); emit s_rowsMoved(row, row1); } } void ObjectsTableWidget::editRow(void) { emit s_rowEdited(table_tbw->currentRow()); } void ObjectsTableWidget::updateRow(void) { emit s_rowUpdated(table_tbw->currentRow()); } void ObjectsTableWidget::clearSelection(void) { table_tbw->clearSelection(); table_tbw->setCurrentItem(nullptr); setButtonsEnabled(); } void ObjectsTableWidget::setButtonsEnabled(unsigned button_conf, bool value) { int lin=-1; QTableWidgetItem *item=table_tbw->currentItem(); if(item) lin=item->row(); if((button_conf & MoveButtons) == MoveButtons) { move_up_tb->setEnabled(value && lin > 0); move_down_tb->setEnabled(value && lin >= 0 && lin < table_tbw->rowCount()-1); move_first_tb->setEnabled(value && lin > 0 && lin<=table_tbw->rowCount()-1); move_last_tb->setEnabled(value && lin >=0 && lin < table_tbw->rowCount()-1); } if((button_conf & EditButton) == EditButton) edit_tb->setEnabled(value && lin >= 0); if((button_conf & AddButton) == AddButton) add_tb->setEnabled(value); if((button_conf & RemoveButton) == RemoveButton) remove_tb->setEnabled(value && lin >= 0); if((button_conf & RemoveAllButton) == RemoveAllButton) remove_all_tb->setEnabled(value && table_tbw->rowCount() > 0); if((button_conf & UpdateButton) == UpdateButton) update_tb->setEnabled(value && lin >= 0); if((button_conf & DuplicateButton) == DuplicateButton) duplicate_tb->setEnabled(value && lin >= 0); if((button_conf & ResizeColsButton) == ResizeColsButton) resize_cols_tb->setEnabled(value && table_tbw->rowCount() > 0); } void ObjectsTableWidget::setCellsEditable(bool value) { table_tbw->setSelectionBehavior(value ? QAbstractItemView::SelectItems : QAbstractItemView::SelectRows); table_tbw->setEditTriggers(value ? QAbstractItemView::AllEditTriggers : QAbstractItemView::NoEditTriggers); } void ObjectsTableWidget::setButtonsEnabled(void) { setButtonsEnabled(AllButtons, true); } void ObjectsTableWidget::emitRowSelected(void) { QTableWidgetItem *item=table_tbw->currentItem(); if(item && item->row() >= 0) emit s_rowSelected(item->row()); } void ObjectsTableWidget::resizeEvent(QResizeEvent *) { table_tbw->resizeRowsToContents(); } pgmodeler-0.9.2/libpgmodeler_ui/src/objectstablewidget.h000066400000000000000000000175021360462764600234720ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ObjectsTableWidget \brief Implements a basic table (grid) which can be used commonly to store objects references and show information about them on it's rows. This class also implements operations to handle insertion/deletion/update/movements of rows on the table. */ #ifndef OBJECT_TABLE_WIDGET_H #define OBJECT_TABLE_WIDGET_H #include "ui_objectstablewidget.h" #include "messagebox.h" #include "baseobjectwidget.h" class ObjectsTableWidget: public QWidget, public Ui::ObjectsTableWidget { private: Q_OBJECT /*! \brief Indicates that a confirmation message must be shown when the user try to remove an element from table. By default, the exclusions are made without confirmation */ bool conf_exclusion; /*! \brief Indicates that cells' texts can be edited by the user. When changing the text of a cell * the signal s_cellTextChanged(int,int) is emitted */ bool cells_editable; QTableWidgetItem *getItem(unsigned row_idx, unsigned col_idx); public: //! \brief Constants used to configure the table buttons static constexpr unsigned AddButton=1, RemoveButton=2, UpdateButton=4, MoveButtons=8, EditButton=16, DuplicateButton=32, RemoveAllButton=64, ResizeColsButton=128, AllButtons=255, NoButtons=0; ObjectsTableWidget(unsigned button_conf=AllButtons, bool conf_exclusion=false, QWidget * parent = nullptr); //! \brief Sets the table's column count void setColumnCount(unsigned col_count); //! \brief Sets the specified column header label void setHeaderLabel(const QString &label, unsigned col_idx); //! \brief Sets the specified column header to be visible or not void setHeaderVisible(unsigned col_idx, bool visible); //! \brief Sets the specified column header icon void setHeaderIcon(const QIcon &icon, unsigned col_idx); //! \brief Sets the icon of the specified cell void setCellIcon(const QIcon &icon, unsigned row_idx, unsigned col_idx); //! \brief Sets the text of the specified cell void setCellText(const QString &text, unsigned row_idx, unsigned col_idx); //! \brief Sets the data which the specified row stores void setRowData(const QVariant &data, unsigned row_idx); //! \brief Sets a individual font configuration for the specified row void setRowFont(int row_idx, const QFont &font, const QColor &fg_color, const QColor &bg_color); //! \brief Returns the table column count unsigned getColumnCount(void); //! \brief Returns the table row count unsigned getRowCount(void); //! \brief Returns the specified column header label QString getHeaderLabel(unsigned col_idx); //! \brief Returns the specified cell text QString getCellText(unsigned row_idx, unsigned col_idx); Qt::CheckState getCellCheckState(unsigned row_idx, unsigned col_idx); void setCellCheckState(unsigned row_idx, unsigned col_idx, Qt::CheckState check_state); void setCellDisabled(unsigned row_idx, unsigned col_idx, bool disabled); bool isCellDisabled(unsigned row_idx, unsigned col_idx); //! \brief Returns the data relative to the specified row QVariant getRowData(unsigned row_idx); //! \brief Remove the specified column from table void removeColumn(unsigned col_idx); //! \brief Adds a new column at the specified index void addColumn(unsigned col_idx); //! \brief Adds a new row at the specified index void addRow(unsigned lin_idx); //! \brief Returns the row index currently selected int getSelectedRow(void); /*! \brief Returns the row index search it through the specified row data. If no row is found returns -1 */ int getRowIndex(const QVariant &data); //! \brief Clears the specified cell text void clearCellText(unsigned row_idx, unsigned col_idx); //! \brief Sets the table button configuration. Use the constants ???_BUTTON combined via bitwise operation. void setButtonConfiguration(unsigned button_conf); void adjustColumnToContents(int col); private slots: //! \brief Moves a row up or down according to the button that triggers the slot void moveRows(void); //! \brief Removes the currently selected line void removeRow(void); //! \brief Duplicate the selected row creating a new item in the end of the grid void duplicateRow(void); /*! \brief This method does not execute any action, only emit a signal indicating that the row is ready to the edition. The edit operation must be implemented by the user and be connected to the emitted signal. */ void editRow(void); /*! \brief This method does not execute any action, only emit a signal indicating that the row is ready to the update. The update operation must be implemented by the user and be connected to the emitted signal. */ void updateRow(void); //! \brief Enables the handle buttons according to the selected row void setButtonsEnabled(void); void emitRowSelected(void); public slots: //! \brief Adds a new row at the end of the table void addRow(void); //! \brief Removes all the rows from table void removeRows(void); //! \brief Remove the specified row void removeRow(unsigned row_idx); //! \brief Clears the row selection disabling the buttons if necessary void clearSelection(void); //! \brief Selects the specified row void selectRow(int lin_idx); //! \brief Controls the enable state of each button void setButtonsEnabled(unsigned button_conf, bool value); void setCellsEditable(bool value); signals: //! \brief Signal emitted when a new row is added. The new row index is send with the signal void s_rowAdded(int); //! \brief Signal emitted when two rows are swapped. The rows indexes are send together with the signal void s_rowsMoved(int,int); //! \brief Signal emitted when all rows are removed from table void s_rowsRemoved(void); //! \brief Signal emitted when a single row is removed. The row index is sent together with the signal void s_rowRemoved(int); //! \brief Signal emitted when a single row is about to be removed. The row index is sent together with the signal void s_rowAboutToRemove(int); //! \brief Signal emitted when a row is selected. The row index is sent together with the signal void s_rowSelected(int); //! \brief Signal emitted when a row is edited. The row index is sent together with the signal void s_rowEdited(int); //! \brief Signal emitted when a row is duplicated. The indexes of the selected and generated rows are sent together with the signal void s_rowDuplicated(int, int); //! \brief Signal emitted when a row is updated. The row index is sent together with the signal void s_rowUpdated(int); //! \brief Signal emitted when a column is removed. The column index is sent together with the signal void s_columnRemoved(int); //! \brief Signal emitted when a column is added. The column index is sent together with the signal void s_columnAdded(int); //! \brief Signal emitted when a specific cell is clicked. The column and rows indexes are sent together with the signal void s_cellClicked(int, int); //! \brief Signal emitted when a specific cell has its text changed. The column and rows indexes are sent together with the signal void s_cellTextChanged(int, int); protected: void resizeEvent(QResizeEvent *); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/operationlistwidget.cpp000066400000000000000000000140771360462764600242640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operationlistwidget.h" #include "taskprogresswidget.h" #include "pgmodeleruins.h" OperationListWidget::OperationListWidget(QWidget *parent) : QWidget(parent) { setupUi(this); setModel(nullptr); operations_tw->headerItem()->setHidden(true); connect(undo_tb,SIGNAL(clicked()),this,SLOT(undoOperation(void))); connect(redo_tb,SIGNAL(clicked()),this,SLOT(redoOperation(void))); connect(rem_operations_tb,SIGNAL(clicked()),this,SLOT(removeOperations(void))); connect(operations_tw,SIGNAL(itemClicked(QTreeWidgetItem *, int)),this,SLOT(selectItem(QTreeWidgetItem *, int))); connect(hide_tb, SIGNAL(clicked(bool)), this, SLOT(hide(void))); } void OperationListWidget::hide(void) { QWidget::hide(); emit s_visibilityChanged(false); } void OperationListWidget::selectItem(QTreeWidgetItem *item, int) { operations_tw->clearSelection(); if(item) { if(item->parent()) item=item->parent(); item->setSelected(true); operations_tw->setCurrentItem(item); } } void OperationListWidget::updateOperationList(void) { content_wgt->setEnabled(this->model_wgt!=nullptr); if(!model_wgt) { operations_tw->clear(); op_count_lbl->setText(QString("-")); current_pos_lbl->setText(QString("-")); } else { unsigned count, i, op_type; ObjectType obj_type; QString obj_name, str_aux, op_name, op_icon; QTreeWidgetItem *item=nullptr,*item1=nullptr, *item2=nullptr; QFont font=this->font(); bool value=false; operations_tw->setUpdatesEnabled(false); op_count_lbl->setText(QString("%1").arg(model_wgt->op_list->getCurrentSize())); current_pos_lbl->setText(QString("%1").arg(model_wgt->op_list->getCurrentIndex())); redo_tb->setEnabled(model_wgt->op_list->isRedoAvailable()); undo_tb->setEnabled(model_wgt->op_list->isUndoAvailable()); count=model_wgt->op_list->getCurrentSize(); operations_tw->clear(); rem_operations_tb->setEnabled(count > 0); for(i=0; i < count; i++) { model_wgt->op_list->getOperationData(i,op_type,obj_name,obj_type); value=(i==static_cast(model_wgt->op_list->getCurrentIndex()-1)); font.setBold(value); font.setItalic(value); item=new QTreeWidgetItem; str_aux=QString(BaseObject::getSchemaName(obj_type)); item->setData(0, Qt::UserRole, QVariant(enum_cast(obj_type))); if(obj_type==ObjectType::BaseRelationship) str_aux+=QString("tv"); item->setIcon(0,QPixmap(PgModelerUiNs::getIconPath(str_aux))); operations_tw->insertTopLevelItem(i,item); item->setFont(0,font); item->setText(0,trUtf8("Object: %1").arg(BaseObject::getTypeName(obj_type))); item2=new QTreeWidgetItem(item); item2->setIcon(0,QPixmap(PgModelerUiNs::getIconPath("uid"))); item2->setFont(0,font); item2->setText(0,trUtf8("Name: %1").arg(obj_name)); if(op_type==Operation::ObjectCreated) { op_icon=QString("criado"); op_name=trUtf8("created"); } else if(op_type==Operation::ObjectRemoved) { op_icon=QString("removido"); op_name=trUtf8("removed"); } else if(op_type==Operation::ObjectModified) { op_icon=QString("modificado"); op_name=trUtf8("modified"); } else if(op_type==Operation::ObjectMoved) { op_icon=QString("movimentado"); op_name=trUtf8("moved"); } item1=new QTreeWidgetItem(item); item1->setIcon(0,QPixmap(PgModelerUiNs::getIconPath(op_icon))); item1->setFont(0,font); item1->setText(0,trUtf8("Operation: %1").arg(op_name)); operations_tw->expandItem(item); if(value) operations_tw->scrollToItem(item1); } operations_tw->setUpdatesEnabled(true); } emit s_operationListUpdated(); } void OperationListWidget::setModel(ModelWidget *model) { operations_tw->clear(); this->model_wgt=model; updateOperationList(); } void OperationListWidget::undoOperation(void) { try { QApplication::setOverrideCursor(Qt::WaitCursor); model_wgt->op_list->undoOperation(); notifyUpdateOnModel(); model_wgt->scene->clearSelection(); QApplication::restoreOverrideCursor(); } catch(Exception &e) { QApplication::restoreOverrideCursor(); this->updateOperationList(); if(e.getErrorCode()==ErrorCode::UndoRedoOperationInvalidObject) { Messagebox msg_box; msg_box.show(e, "", Messagebox::AlertIcon); } else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void OperationListWidget::redoOperation(void) { try { QApplication::setOverrideCursor(Qt::WaitCursor); model_wgt->op_list->redoOperation(); notifyUpdateOnModel(); model_wgt->scene->clearSelection(); QApplication::restoreOverrideCursor(); } catch(Exception &e) { QApplication::restoreOverrideCursor(); if(e.getErrorCode()==ErrorCode::UndoRedoOperationInvalidObject) { Messagebox msg_box; msg_box.show(e, "", Messagebox::AlertIcon); } else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void OperationListWidget::removeOperations(void) { Messagebox msg_box; msg_box.show(trUtf8("Operation history exclusion"), trUtf8("Delete the executed operations history is an irreversible action, do you want to continue?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { model_wgt->op_list->removeOperations(); updateOperationList(); rem_operations_tb->setEnabled(false); } } void OperationListWidget::notifyUpdateOnModel(void) { updateOperationList(); emit s_operationExecuted(); } pgmodeler-0.9.2/libpgmodeler_ui/src/operationlistwidget.h000066400000000000000000000034111360462764600237170ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class OperationListWidget \brief Implements the widget representation for the operation list, giving access to the undo/redo action over the model. */ #ifndef OPERATION_LIST_WIDGET_H #define OPERATION_LIST_WIDGET_H #include #include "ui_operationlistwidget.h" #include "modelwidget.h" #include "messagebox.h" class OperationListWidget: public QWidget, public Ui::OperationListWidget { private: Q_OBJECT ModelWidget *model_wgt; //! \brief Updates the operation list and emits the signal s_operationListUpdated to the connected objects void notifyUpdateOnModel(void); public: OperationListWidget(QWidget * parent = nullptr); public slots: void updateOperationList(void); void setModel(ModelWidget *model); void undoOperation(void); void redoOperation(void); void removeOperations(void); void hide(void); private slots: void selectItem(QTreeWidgetItem *item, int coluna); signals: void s_operationExecuted(void); void s_operationListUpdated(void); void s_visibilityChanged(bool); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/operatorclasswidget.cpp000066400000000000000000000225271360462764600242500ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operatorclasswidget.h" OperatorClassWidget::OperatorClassWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::OpClass) { try { QStringList tipos; QGridLayout *grid=nullptr; map > fields_map; map > values_map; QFrame *frame=nullptr; Ui_OperatorClassWidget::setupUi(this); family_sel=new ObjectSelectorWidget(ObjectType::OpFamily, true, this); data_type=new PgSQLTypeWidget(this); operator_sel=new ObjectSelectorWidget(ObjectType::Operator, true, this); elem_family_sel=new ObjectSelectorWidget(ObjectType::OpFamily, true, this); function_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); storage_type=new PgSQLTypeWidget(this, trUtf8("Storage Type")); elements_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::DuplicateButton, true, this); elements_tab->setColumnCount(4); elements_tab->setHeaderLabel(trUtf8("Object"),0); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("table")),0); elements_tab->setHeaderLabel(trUtf8("Type"),1); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); elements_tab->setHeaderLabel(trUtf8("Support/Strategy"),2); elements_tab->setHeaderLabel(trUtf8("Operator Family"),3); elements_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("opfamily")),3); grid=new QGridLayout; grid->setContentsMargins(0,0,0,0); grid->addWidget(def_class_lbl,0,2,1,1); grid->addWidget(def_class_chk,0,3,1,1); grid->addWidget(indexing_lbl,0,0,1,1); grid->addWidget(indexing_cmb,0,1,1,1); grid->addWidget(family_lbl,2,0,1,1); grid->addWidget(family_sel,2,1,1,4); grid->addWidget(data_type,4,0,1,5); grid->addWidget(elements_grp,5,0,1,5); this->setLayout(grid); configureFormLayout(grid, ObjectType::OpClass); fields_map[BaseObjectWidget::generateVersionsInterval(BaseObjectWidget::AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(indexing_lbl); values_map[indexing_lbl].push_back(~IndexingType(IndexingType::Brin)); frame=BaseObjectWidget::generateVersionWarningFrame(fields_map, &values_map); frame->setParent(this); grid=dynamic_cast(this->layout()); grid->addWidget(frame, grid->count(), 0, 1, 5); grid=dynamic_cast(elements_grp->layout()); grid->addWidget(function_sel, 1,1,1,4); grid->addWidget(operator_sel, 2,1,1,4); grid->addWidget(elem_family_sel, 3,1,1,4); grid->addWidget(storage_type, 5,0,1,5); grid->addWidget(elements_tab, 6,0,1,4); connect(elem_type_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(selectElementType(int))); connect(elements_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleElement(int))); connect(elements_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleElement(int))); connect(elements_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editElement(int))); selectElementType(0); IndexingType::getTypes(tipos); indexing_cmb->addItems(tipos); setRequiredField(elements_grp); configureTabOrder({ indexing_cmb, def_class_chk , family_sel, data_type, elem_type_cmb, operator_sel, elem_family_sel, function_sel, stg_num_sb, storage_type }); setMinimumSize(640, 730); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void OperatorClassWidget::selectElementType(int elem_type) { unsigned sel_idx=static_cast(elem_type); function_lbl->setVisible(sel_idx==OperatorClassElement::FunctionElem); function_sel->setVisible(sel_idx==OperatorClassElement::FunctionElem); operator_lbl->setVisible(sel_idx==OperatorClassElement::OperatorElem); operator_sel->setVisible(sel_idx==OperatorClassElement::OperatorElem); elem_family_lbl->setVisible(sel_idx==OperatorClassElement::OperatorElem); elem_family_sel->setVisible(sel_idx==OperatorClassElement::OperatorElem); storage_type->setVisible(sel_idx==OperatorClassElement::StorageElem); stg_num_lbl->setVisible(sel_idx!=OperatorClassElement::StorageElem); stg_num_sb->setVisible(sel_idx!=OperatorClassElement::StorageElem); } void OperatorClassWidget::editElement(int lin_idx) { OperatorClassElement elem; //Get the element from the selected line elem=elements_tab->getRowData(lin_idx).value(); elem_type_cmb->setCurrentIndex(elem.getElementType()); selectElementType(elem_type_cmb->currentIndex()); function_sel->setSelectedObject(elem.getFunction()); operator_sel->setSelectedObject(elem.getOperator()); stg_num_sb->setValue(elem.getStrategyNumber()); storage_type->setAttributes(elem.getStorage(),this->model); } void OperatorClassWidget::showElementData(OperatorClassElement elem, int lin_idx) { unsigned elem_type; elem_type=elem.getElementType(); if(elem_type==OperatorClassElement::FunctionElem) { elements_tab->setCellText(elem.getFunction()->getSignature(), lin_idx, 0); elements_tab->setCellText(elem.getFunction()->getTypeName(), lin_idx, 1); } else if(elem_type==OperatorClassElement::OperatorElem) { elements_tab->setCellText(elem.getOperator()->getSignature(), lin_idx, 0); elements_tab->setCellText(elem.getOperator()->getTypeName(), lin_idx, 1); } else { elements_tab->setCellText(*elem.getStorage(), lin_idx, 0); elements_tab->setCellText(BaseObject::getTypeName(ObjectType::Type), lin_idx, 1); } if(elem_type!=OperatorClassElement::StorageElem) elements_tab->setCellText(QString("%1").arg(elem.getStrategyNumber()), lin_idx, 2); else elements_tab->setCellText(QString(" "), lin_idx, 2); if(elem_type==OperatorClassElement::OperatorElem && elem.getOperatorFamily()) elements_tab->setCellText(elem.getOperatorFamily()->getName(true), lin_idx, 3); else elements_tab->clearCellText(lin_idx, 3); //Define as the line data the element itself elements_tab->setRowData(QVariant::fromValue(elem), lin_idx); } void OperatorClassWidget::handleElement(int lin_idx) { OperatorClassElement elem; unsigned elem_type; elem_type=elem_type_cmb->currentIndex(); try { if(elem_type==OperatorClassElement::FunctionElem) elem.setFunction(dynamic_cast(function_sel->getSelectedObject()), stg_num_sb->value()); else if(elem_type==OperatorClassElement::OperatorElem) { elem.setOperator(dynamic_cast(operator_sel->getSelectedObject()), stg_num_sb->value()); elem.setOperatorFamily(dynamic_cast(elem_family_sel->getSelectedObject())); } else elem.setStorage(storage_type->getPgSQLType()); showElementData(elem, lin_idx); function_sel->clearSelector(); operator_sel->clearSelector(); stg_num_sb->setValue(1); elements_tab->clearSelection(); } catch(Exception &e) { //In case of error removes the recently added table line if(elements_tab->getCellText(lin_idx, 0).isEmpty()) elements_tab->removeRow(lin_idx); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void OperatorClassWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, OperatorClass *op_class) { PgSqlType type; unsigned i, count; BaseObjectWidget::setAttributes(model, op_list, op_class, schema); family_sel->setModel(model); function_sel->setModel(model); operator_sel->setModel(model); elem_family_sel->setModel(model); storage_type->setAttributes(type, model); if(op_class) { type=op_class->getDataType(); family_sel->setSelectedObject(op_class->getFamily()); def_class_chk->setChecked(op_class->isDefault()); indexing_cmb->setCurrentIndex(indexing_cmb->findText(~(op_class->getIndexingType()))); elements_tab->blockSignals(true); count=op_class->getElementCount(); for(i=0; i < count; i++) { elements_tab->addRow(); showElementData(op_class->getElement(i), i); } elements_tab->blockSignals(false); elements_tab->clearSelection(); } data_type->setAttributes(type, model); } void OperatorClassWidget::applyConfiguration(void) { try { OperatorClass *op_class=nullptr; unsigned i, count; startConfiguration(); op_class=dynamic_cast(this->object); op_class->setDefault(op_class->isDefault()); op_class->setFamily(dynamic_cast(family_sel->getSelectedObject())); op_class->setIndexingType(IndexingType(indexing_cmb->currentText())); op_class->setDataType(data_type->getPgSQLType()); op_class->removeElements(); count=elements_tab->getRowCount(); for(i=0; i < count; i++) op_class->addElement(elements_tab->getRowData(i).value()); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/operatorclasswidget.h000066400000000000000000000046661360462764600237210ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class OperatorClassWidget \brief Implements the operations to create/edit operator class via form. */ #ifndef OPERATOR_CLASS_WIDGET_H #define OPERATOR_CLASS_WIDGET_H #include "baseobjectwidget.h" #include "ui_operatorclasswidget.h" #include "pgsqltypewidget.h" #include "objectstablewidget.h" /* Declaring the OperatorClassElement class as a Qt metatype in order to permit that instances of the class be used as data of QVariant and QMetaType */ #include Q_DECLARE_METATYPE(OperatorClassElement) class OperatorClassWidget: public BaseObjectWidget, public Ui::OperatorClassWidget { private: Q_OBJECT //! \brief Family, funciton and operator selectors ObjectSelectorWidget *family_sel, *function_sel, *operator_sel, *elem_family_sel; PgSQLTypeWidget *data_type, *storage_type; //! \brief Stores the elements of operator class ObjectsTableWidget *elements_tab; public: OperatorClassWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, OperatorClass *op_class); private slots: //! \brief Configures the element form according to the passed element type void selectElementType(int elem_type); //! \brief Shows the data from the passed element on the element table void showElementData(OperatorClassElement elem, int lin_idx); /*! \brief Configures an instance of OperatorClassElement using the data on the form, additionally the configured element is shown on the specified line on table */ void handleElement(int lin_idx); //! \brief Fill the form fields with the element data on the specified table line void editElement(int lin_idx); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/operatorfamilywidget.cpp000066400000000000000000000050321360462764600244140ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operatorfamilywidget.h" OperatorFamilyWidget::OperatorFamilyWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::OpFamily) { QStringList types; map > fields_map; map > values_map; QFrame *frame=nullptr; Ui_OperatorFamilyWidget::setupUi(this); configureFormLayout(opfamily_grid, ObjectType::OpFamily); IndexingType::getTypes(types); indexing_cmb->addItems(types); setRequiredField(indexing_lbl); fields_map[BaseObjectWidget::generateVersionsInterval(BaseObjectWidget::AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(indexing_lbl); values_map[indexing_lbl].push_back(~IndexingType(IndexingType::Brin)); opfamily_grid->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding), opfamily_grid->count()+1, 0, 1, 0); frame=BaseObjectWidget::generateVersionWarningFrame(fields_map, &values_map); frame->setParent(this); opfamily_grid->addWidget(frame, opfamily_grid->count()+1, 0, 1, 5); configureTabOrder(); setMinimumSize(500, 290); } void OperatorFamilyWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, OperatorFamily *op_family) { BaseObjectWidget::setAttributes(model, op_list, op_family, schema); if(op_family) indexing_cmb->setCurrentIndex(indexing_cmb->findText(~(op_family->getIndexingType()))); } void OperatorFamilyWidget::applyConfiguration(void) { try { OperatorFamily *op_family=nullptr; startConfiguration(); op_family=dynamic_cast(this->object); op_family->setIndexingType(IndexingType(indexing_cmb->currentText())); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/operatorfamilywidget.h000066400000000000000000000024721360462764600240660ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class OperatorFamilyWidget \brief Implements the operations to create/edit operator family via form. */ #ifndef OPERATOR_FAMILY_WIDGET_H #define OPERATOR_FAMILY_WIDGET_H #include "baseobjectwidget.h" #include "ui_operatorfamilywidget.h" class OperatorFamilyWidget: public BaseObjectWidget, public Ui::OperatorFamilyWidget { private: Q_OBJECT public: OperatorFamilyWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, OperatorFamily *op_family); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/operatorwidget.cpp000066400000000000000000000112001360462764600232040ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "operatorwidget.h" OperatorWidget::OperatorWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Operator) { try { QGridLayout *grid=nullptr; unsigned i, i1; QFrame *frame=nullptr; Ui_OperatorWidget::setupUi(this); arg_types[0]=nullptr; arg_types[0]=new PgSQLTypeWidget(this, trUtf8("Left Argument Type")); arg_types[1]=nullptr; arg_types[1]=new PgSQLTypeWidget(this, trUtf8("Right Argument Type")); grid=new QGridLayout; grid->setContentsMargins(4,4,4,4); grid->addWidget(arg_types[0],0,0); grid->addWidget(arg_types[1],1,0); grid->addItem(new QSpacerItem(10,1,QSizePolicy::Fixed,QSizePolicy::Expanding), 2, 0); frame=generateInformationFrame(trUtf8("To create a unary operator it is necessary to specify as 'any' one of its arguments. Additionally, the function that defines the operator must have only one parameter and this, in turn, must have the same data type of the the argument of unary operator.")); grid->addWidget(frame, 3, 0); attributes_twg->widget(0)->setLayout(grid); grid=dynamic_cast(attributes_twg->widget(1)->layout()); for(i=Operator::FuncOperator; i <= Operator::FuncRestrict; i++) { functions_sel[i]=nullptr; functions_sel[i]=new ObjectSelectorWidget(ObjectType::Function, true, this); if(i!=Operator::FuncOperator) grid->addWidget(functions_sel[i],i,1,1,1); } for(i=Operator::OperCommutator, i1=3; i <= Operator::OperNegator; i++,i1++) { operators_sel[i]=nullptr; operators_sel[i]=new ObjectSelectorWidget(ObjectType::Operator, true, this); grid->addWidget(operators_sel[i],i1,1,1,1); } operator_grid->addWidget(functions_sel[0],0,1,1,3); configureFormLayout(operator_grid, ObjectType::Operator); setRequiredField(operator_func_lbl); setRequiredField(functions_sel[0]); configureTabOrder({ functions_sel[0], arg_types[0], arg_types[1] }); setMinimumSize(600, 620); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void OperatorWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Operator *oper) { unsigned i; PgSqlType left_type, right_type; BaseObjectWidget::setAttributes(model,op_list, oper, schema); for(i=Operator::FuncOperator; i <= Operator::FuncRestrict; i++) functions_sel[i]->setModel(model); for(i=Operator::OperCommutator; i <= Operator::OperNegator; i++) operators_sel[i]->setModel(model); if(oper) { hashes_chk->setChecked(oper->isHashes()); merges_chk->setChecked(oper->isMerges()); for(i=Operator::FuncOperator; i <= Operator::FuncRestrict; i++) functions_sel[i]->setSelectedObject(oper->getFunction(i)); for(i=Operator::OperCommutator; i <= Operator::OperNegator; i++) operators_sel[i]->setSelectedObject(oper->getOperator(i)); left_type=oper->getArgumentType(Operator::LeftArg); right_type=oper->getArgumentType(Operator::RightArg); } arg_types[0]->setAttributes(left_type, model); arg_types[1]->setAttributes(right_type, model); } void OperatorWidget::applyConfiguration(void) { try { unsigned i; Operator *oper=nullptr; startConfiguration(); oper=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); oper->setHashes(hashes_chk->isChecked()); oper->setMerges(merges_chk->isChecked()); for(i=Operator::LeftArg; i <= Operator::RightArg; i++) oper->setArgumentType(arg_types[i]->getPgSQLType(), i); for(i=Operator::FuncOperator; i <= Operator::FuncRestrict; i++) oper->setFunction(dynamic_cast(functions_sel[i]->getSelectedObject()), i); for(i=Operator::OperCommutator; i <= Operator::OperNegator; i++) oper->setOperator(dynamic_cast(operators_sel[i]->getSelectedObject()), i); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/operatorwidget.h000066400000000000000000000025751360462764600226700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class OperatorWidget \brief Implements the operations to create/edit operators via form. */ #ifndef OPERATOR_WIDGET_H #define OPERATOR_WIDGET_H #include "baseobjectwidget.h" #include "pgsqltypewidget.h" #include "ui_operatorwidget.h" class OperatorWidget: public BaseObjectWidget, public Ui::OperatorWidget { private: Q_OBJECT PgSQLTypeWidget *arg_types[2]; ObjectSelectorWidget *functions_sel[3], *operators_sel[2]; public: OperatorWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Operator *oper); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/parameterwidget.cpp000066400000000000000000000066301360462764600233440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "parameterwidget.h" ParameterWidget::ParameterWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Parameter) { try { QGridLayout *parameter_grid=nullptr; QSpacerItem *spacer=nullptr; Ui_ParameterWidget::setupUi(this); data_type=new PgSQLTypeWidget(this); parameter_grid=new QGridLayout(this); spacer=new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); parameter_grid->setContentsMargins(0, 0, 0, 0); parameter_grid->addWidget(default_value_lbl, 0, 0, 1, 1); parameter_grid->addWidget(default_value_edt, 0, 1, 1, 3); parameter_grid->addWidget(mode_lbl, 1, 0, 1, 1); parameter_grid->addWidget(param_in_chk, 1, 1, 1, 1); parameter_grid->addWidget(param_out_chk, 1, 2, 1, 1); parameter_grid->addWidget(param_variadic_chk, 1, 3, 1, 1); parameter_grid->addWidget(data_type,2, 0, 1, 4); parameter_grid->addItem(spacer, parameter_grid->count()+1,0); configureFormLayout(parameter_grid, ObjectType::Parameter); connect(param_variadic_chk, SIGNAL(toggled(bool)), param_in_chk, SLOT(setDisabled(bool))); connect(param_variadic_chk, SIGNAL(toggled(bool)), param_out_chk, SLOT(setDisabled(bool))); connect(param_in_chk, SIGNAL(toggled(bool)), this, SLOT(enableVariadic(void))); connect(param_out_chk, SIGNAL(toggled(bool)), this, SLOT(enableVariadic(void))); setMinimumSize(500, 200); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ParameterWidget::enableVariadic(void) { param_variadic_chk->setEnabled(!param_in_chk->isChecked() && !param_out_chk->isChecked()); if(!param_variadic_chk->isEnabled()) param_variadic_chk->setChecked(false); } void ParameterWidget::setAttributes(Parameter param, DatabaseModel *model) { this->parameter=param; param_in_chk->setChecked(param.isIn()); param_out_chk->setChecked(param.isOut()); param_variadic_chk->setChecked(param.isVariadic()); default_value_edt->setText(param.getDefaultValue()); data_type->setAttributes(param.getType(), model); BaseObjectWidget::setAttributes(model,&this->parameter, nullptr); } void ParameterWidget::applyConfiguration(void) { try { parameter.setDefaultValue(default_value_edt->text()); parameter.setType(data_type->getPgSQLType()); parameter.setIn(param_in_chk->isChecked()); parameter.setOut(param_out_chk->isChecked()); parameter.setVariadic(param_variadic_chk->isChecked()); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } Parameter ParameterWidget::getParameter(void) { return(parameter); } pgmodeler-0.9.2/libpgmodeler_ui/src/parameterwidget.h000066400000000000000000000026141360462764600230070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ParameterWidget \brief Implements the operations to create/edit function parameters via form. */ #ifndef PARAMETER_WIDGET_H #define PARAMETER_WIDGET_H #include "baseobjectwidget.h" #include "ui_parameterwidget.h" #include "pgsqltypewidget.h" class ParameterWidget: public BaseObjectWidget, public Ui::ParameterWidget { private: Q_OBJECT PgSQLTypeWidget *data_type; Parameter parameter; public: ParameterWidget(QWidget * parent = nullptr); void setAttributes(Parameter parameter, DatabaseModel *model); Parameter getParameter(void); public slots: void applyConfiguration(void); private slots: void enableVariadic(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/permissionwidget.cpp000066400000000000000000000375301360462764600235570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "permissionwidget.h" PermissionWidget::PermissionWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Permission) { QGridLayout *grid=nullptr; QFrame *frame=nullptr; QCheckBox *check=nullptr; unsigned i; QString privs[]={ Attributes::SelectPriv, Attributes::InsertPriv, Attributes::UpdatePriv, Attributes::DeletePriv, Attributes::TruncatePriv, Attributes::ReferencesPriv, Attributes::TriggerPriv, Attributes::CreatePriv, Attributes::ConnectPriv, Attributes::TemporaryPriv, Attributes::ExecutPriv, Attributes::UsagePriv }; Ui_PermissionWidget::setupUi(this); code_hl=new SyntaxHighlighter(code_txt); code_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); object_selection_wgt=new ModelObjectsWidget(true); permission=nullptr; configureFormLayout(permission_grid, ObjectType::Permission); roles_tab=new ObjectsTableWidget(ObjectsTableWidget::AddButton | ObjectsTableWidget::RemoveButton | ObjectsTableWidget::EditButton, false, this); roles_tab->setColumnCount(1); roles_tab->setHeaderLabel(trUtf8("Name"),0); roles_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); grid=new QGridLayout; grid->addWidget(roles_tab,0,0,1,1); grid->setContentsMargins(2,2,2,2); roles_gb->setLayout(grid); permissions_tab=new ObjectsTableWidget(ObjectsTableWidget::RemoveButton | ObjectsTableWidget::EditButton | ObjectsTableWidget::RemoveAllButton, true, this); permissions_tab->setColumnCount(3); permissions_tab->setHeaderLabel(trUtf8("Id"),0); permissions_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); permissions_tab->setHeaderLabel(trUtf8("Roles"),1); permissions_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("role")),1); permissions_tab->setHeaderLabel(trUtf8("Privileges"),2); permissions_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("grant")),2); grid=new QGridLayout; grid->addWidget(permissions_tab,0,0,1,1); grid->setContentsMargins(2,2,2,2); permissions_gb->setLayout(grid); for(i=Permission::PrivSelect; i<=Permission::PrivUsage; i++) { check=new QCheckBox; check->setText(privs[i].toUpper()); privileges_tbw->insertRow(i); privileges_tbw->setCellWidget(i,0,check); connect(check, SIGNAL(clicked(bool)), this, SLOT(checkPrivilege(void))); check=new QCheckBox; check->setText(QString("GRANT OPTION")); check->setEnabled(false); privileges_tbw->setCellWidget(i,1,check); connect(check, SIGNAL(clicked(bool)), this, SLOT(checkPrivilege(void))); } frame=generateInformationFrame(trUtf8("Leave the Roles grid empty in order to create a %1 applicable to PUBLIC.") .arg(BaseObject::getTypeName(ObjectType::Permission).toLower())); permission_grid->addWidget(frame, permission_grid->count()+1, 0, 1, 0); frame->setParent(this); connect(roles_tab, SIGNAL(s_rowAdded(int)), roles_tab, SLOT(selectRow(int))); connect(roles_tab, SIGNAL(s_rowEdited(int)), this, SLOT(selectRole(void))); connect(roles_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(enableEditButtons(void))); connect(roles_tab, SIGNAL(s_rowAdded(int)), this, SLOT(enableEditButtons(void))); connect(roles_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(disableGrantOptions(void))); connect(roles_tab, SIGNAL(s_rowAdded(int)), this, SLOT(disableGrantOptions(void))); connect(permissions_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removePermission(int))); connect(permissions_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editPermission(void))); connect(permissions_tab, SIGNAL(s_rowSelected(int)), this, SLOT(selectPermission(int))); connect(cancel_tb, SIGNAL(clicked(bool)), this, SLOT(cancelOperation(void))); connect(add_perm_tb, SIGNAL(clicked(bool)), this, SLOT(addPermission(void))); connect(upd_perm_tb, SIGNAL(clicked(bool)), this, SLOT(updatePermission(void))); connect(revoke_rb, SIGNAL(toggled(bool)), cascade_chk, SLOT(setEnabled(bool))); connect(revoke_rb, SIGNAL(toggled(bool)), this, SLOT(disableGrantOptions(void))); connect(grant_rb, SIGNAL(toggled(bool)), this, SLOT(disableGrantOptions(void))); setMinimumSize(670,600); } PermissionWidget::~PermissionWidget(void) { delete(object_selection_wgt); } void PermissionWidget::setAttributes(DatabaseModel *model, BaseObject *parent_obj, BaseObject *object) { BaseObjectWidget::setAttributes(model,object,parent_obj); perms_changed=false; protected_obj_frm->setVisible(false); obj_id_lbl->setVisible(false); if(object) { unsigned priv; QCheckBox *chk=nullptr, *chk1=nullptr; connect(object_selection_wgt, SIGNAL(s_visibilityChanged(BaseObject*,bool)), this, SLOT(showSelectedRoleData(void))); connect(roles_tab, SIGNAL(s_rowAdded(int)), this, SLOT(selectRole(void))); connect(permissions_tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removePermissions(void))); name_edt->setText(QString("%1 (%2)").arg(object->getSignature()).arg(object->getTypeName())); for(priv=Permission::PrivSelect; priv<=Permission::PrivUsage; priv++) { //Gets the checkboxes that represents the privilege and the GRANT OPTION chk=dynamic_cast(privileges_tbw->cellWidget(priv,0)); chk1=dynamic_cast(privileges_tbw->cellWidget(priv,1)); chk->setChecked(false); chk1->setChecked(false); //Enabling the checkboxes using a validation of privilege type against the curret object type. privileges_tbw->setRowHidden(priv, !Permission::acceptsPermission(object->getObjectType(), priv)); } listPermissions(); permissions_tab->blockSignals(true); permissions_tab->clearSelection(); permissions_tab->blockSignals(false); updateCodePreview(); } } void PermissionWidget::selectRole(void) { object_selection_wgt->setObjectVisible(ObjectType::Role, true); object_selection_wgt->setModel(this->model); object_selection_wgt->show(); } void PermissionWidget::selectPermission(int perm_id) { if(perm_id >= 0) permission=reinterpret_cast(permissions_tab->getRowData(perm_id).value()); else permission=nullptr; } void PermissionWidget::disableGrantOptions(void) { QCheckBox *check=nullptr; for(unsigned i=Permission::PrivSelect; i<=Permission::PrivUsage; i++) { check=dynamic_cast(privileges_tbw->cellWidget(i,1)); check->setEnabled(roles_tab->getRowCount() > 0); if(!check->isEnabled()) check->setChecked(false); } cascade_chk->setEnabled(revoke_rb->isChecked() && roles_tab->getRowCount() > 0); if(!cascade_chk->isEnabled()) cascade_chk->setChecked(false); } void PermissionWidget::listPermissions(void) { if(model) { vector permissions; Permission *perm=nullptr; unsigned i, count, i1, count1; QString str_aux; model->getPermissions(this->object, permissions); count=permissions.size(); permissions_tab->blockSignals(true); permissions_tab->removeRows(); permissions_tab->blockSignals(false); for(i=0; i < count; i++) { perm=permissions[i]; permissions_tab->blockSignals(true); permissions_tab->addRow(); permissions_tab->setRowData(QVariant::fromValue(reinterpret_cast(perm)),i); permissions_tab->setCellText(perm->getName(),i,0); permissions_tab->setCellText(perm->getPermissionString(),i,2); permissions_tab->blockSignals(false); count1=perm->getRoleCount(); for(i1=0; i1 < count1; i1++) { str_aux+=perm->getRole(i1)->getName(); str_aux+=QString(","); } str_aux.remove(str_aux.size()-1,1); permissions_tab->setCellText(str_aux,i,1); str_aux.clear(); } permission=nullptr; } } void PermissionWidget::showSelectedRoleData(void) { int row, row_idx=-1; Role *role=nullptr; role=dynamic_cast(object_selection_wgt->getSelectedObject()); row=roles_tab->getSelectedRow(); if(role) row_idx=roles_tab->getRowIndex(QVariant::fromValue(dynamic_cast(role))); if(role && row_idx < 0) { roles_tab->setCellText(role->getName(), row, 0); roles_tab->setRowData(QVariant::fromValue(dynamic_cast(role)), row); } else { if(!roles_tab->getRowData(row).value()) roles_tab->removeRow(row); //Raise an error if the role already exists on selected role table if(role && row_idx >= 0) { throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObjectContainer) .arg(role->getName()) .arg(role->getTypeName()) .arg(roles_gb->title()), ErrorCode::InsDuplicatedRole,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } } void PermissionWidget::addPermission(void) { Permission *perm=nullptr; try { perm=new Permission(this->object); configurePermission(perm); model->addPermission(perm); listPermissions(); cancelOperation(); perms_changed=true; updateCodePreview(); } catch(Exception &e) { if(perm) { model->removePermission(perm); delete(perm); } cancelOperation(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PermissionWidget::updatePermission(void) { Permission *perm=nullptr,*perm_bkp=nullptr; int perm_idx=-1; try { perm=new Permission(this->object); /* Creates a backup permission. This will receive the current values of the editing permission, in case of errors these values can be restored */ perm_bkp=new Permission(this->object); (*perm_bkp)=(*permission); configurePermission(perm); //Checking if the permission already exists on model perm_idx=model->getPermissionIndex(perm, false); if(perm_idx < 0 || (perm_idx >=0 && model->getObject(perm_idx,ObjectType::Permission)==permission)) { (*permission)=(*perm); listPermissions(); cancelOperation(); } else { //Raises an error if the configured permission already exists throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedPermission) .arg(permission->getObject()->getName()) .arg(permission->getObject()->getTypeName()), ErrorCode::AsgDuplicatedPermission,__PRETTY_FUNCTION__,__FILE__,__LINE__); } delete(perm_bkp); perms_changed=true; updateCodePreview(); } catch(Exception &e) { (*permission)=(*perm_bkp); delete(perm); delete(perm_bkp); cancelOperation(); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PermissionWidget::editPermission(void) { if(permission) { unsigned priv, i, count; QCheckBox *chk=nullptr, *chk1=nullptr; Role *role=nullptr; roles_tab->blockSignals(true); roles_tab->removeRows(); perm_disable_sql_chk->setChecked(permission->isSQLDisabled()); perm_id_edt->setText(permission->getName()); revoke_rb->setChecked(permission->isRevoke()); cascade_chk->setChecked(permission->isCascade()); count=permission->getRoleCount(); for(i=0; i < count; i++) { roles_tab->addRow(); role=permission->getRole(i); roles_tab->setRowData(QVariant::fromValue(reinterpret_cast(role)), i); roles_tab->setCellText(role->getName(),i,0); } roles_tab->blockSignals(false); for(priv=Permission::PrivSelect; priv<=Permission::PrivUsage; priv++) { chk=dynamic_cast(privileges_tbw->cellWidget(priv,0)); chk1=dynamic_cast(privileges_tbw->cellWidget(priv,1)); chk->setChecked(permission->getPrivilege(priv)); chk1->setChecked(permission->getGrantOption(priv)); } enableEditButtons(); } } void PermissionWidget::removePermission(int) { model->removePermission(permission); cancelOperation(); permission=nullptr; permissions_tab->clearSelection(); perms_changed=true; updateCodePreview(); } void PermissionWidget::removePermissions(void) { model->removePermissions(object); cancelOperation(); perms_changed=true; updateCodePreview(); } void PermissionWidget::configurePermission(Permission *perm) { if(perm) { unsigned count, i, priv; QCheckBox *chk=nullptr, *chk1=nullptr; perm->setSQLDisabled(perm_disable_sql_chk->isChecked()); perm->setCascade(cascade_chk->isChecked()); perm->setRevoke(revoke_rb->isChecked()); perm->removeRoles(); count=roles_tab->getRowCount(); for(i=0; i < count; i++) perm->addRole(reinterpret_cast(roles_tab->getRowData(i).value())); for(priv=Permission::PrivSelect; priv <= Permission::PrivUsage; priv++) { if(!privileges_tbw->isRowHidden(priv)) { chk=dynamic_cast(privileges_tbw->cellWidget(priv,0)); chk1=dynamic_cast(privileges_tbw->cellWidget(priv,1)); perm->setPrivilege(priv, chk->isChecked(), chk1->isChecked()); } } } } void PermissionWidget::cancelOperation(void) { unsigned priv; QCheckBox *chk=nullptr; permission=nullptr; for(priv=Permission::PrivSelect; priv<=Permission::PrivUsage; priv++) { chk=dynamic_cast(privileges_tbw->cellWidget(priv,0)); chk->setChecked(false); chk=dynamic_cast(privileges_tbw->cellWidget(priv,1)); chk->setChecked(false); } roles_tab->removeRows(); perm_id_edt->clear(); enableEditButtons(); cancel_tb->setEnabled(false); permissions_tab->clearSelection(); perm_disable_sql_chk->setChecked(false); } void PermissionWidget::checkPrivilege(void) { QObject *obj_sender=sender(); if(obj_sender && obj_sender->metaObject()->className()==QString("QCheckBox")) { QCheckBox *chk=nullptr, *chk_priv=nullptr, *chk_gop=nullptr; unsigned priv; chk=dynamic_cast(obj_sender); for(priv=Permission::PrivSelect; priv<=Permission::PrivUsage; priv++) { chk_priv=dynamic_cast(privileges_tbw->cellWidget(priv,0)); chk_gop=dynamic_cast(privileges_tbw->cellWidget(priv,1)); if(chk==chk_gop) { chk_priv->setChecked(chk_gop->isChecked()); break; } else if(chk==chk_priv && !chk->isChecked()) { chk_gop->setChecked(false); break; } } enableEditButtons(); } } void PermissionWidget::enableEditButtons(void) { bool checked_privs=false; unsigned priv; QCheckBox *chk=nullptr, *chk1=nullptr; for(priv=Permission::PrivSelect; priv<=Permission::PrivUsage && !checked_privs; priv++) { chk=dynamic_cast(privileges_tbw->cellWidget(priv,0)); chk1=dynamic_cast(privileges_tbw->cellWidget(priv,1)); checked_privs=(chk->isChecked() || chk1->isChecked()); } upd_perm_tb->setEnabled(checked_privs && permission!=nullptr); add_perm_tb->setEnabled(checked_privs); cancel_tb->setEnabled(add_perm_tb->isEnabled() || upd_perm_tb->isEnabled() || permissions_tab->getRowCount() > 0); } void PermissionWidget::updateCodePreview(void) { try { QString code; vector perms; unsigned i=0, cnt=0; model->getPermissions(this->object, perms); cnt=perms.size(); for(i=0; i < cnt; i++) code+=perms[i]->getCodeDefinition(SchemaParser::SqlDefinition); if(code.isEmpty()) code=trUtf8("-- No permissions defined for the specified object!"); code_txt->setPlainText(code); } catch(Exception &e) { QString str_aux; //In case of error no code is outputed, showing a error message in the code preview widget str_aux=trUtf8("/* Could not generate the SQL code preview for permissions!"); str_aux+=QString("\n\n>> Returned error(s): \n\n%1*/").arg(e.getExceptionsText()); code_txt->setPlainText(str_aux); } } void PermissionWidget::applyConfiguration(void) { if(perms_changed) emit s_objectManipulated(); emit s_closeRequested(); } pgmodeler-0.9.2/libpgmodeler_ui/src/permissionwidget.h000066400000000000000000000062701360462764600232210ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class PermissionWidget \brief Implements the operations to create/edit permissions via form. */ #ifndef PERMISSION_WIDGET_H #define PERMISSION_WIDGET_H #include "baseobjectwidget.h" #include "ui_permissionwidget.h" #include "objectstablewidget.h" #include "modelobjectswidget.h" class PermissionWidget: public BaseObjectWidget, public Ui::PermissionWidget { private: Q_OBJECT SyntaxHighlighter *code_hl; //! \brief Stores the permission to be edited Permission *permission; //! \brief Table widget that stores the roles that has permission over the object ObjectsTableWidget *roles_tab, //! \brief Table widget that stores the permissions related to the object *permissions_tab; //! \brief Widget used to select roles on the database model ModelObjectsWidget *object_selection_wgt; /*! \brief Indicates if some permission was changed. This flag is used to know when emit the signal s_objectManipulated() */ bool perms_changed; public: PermissionWidget(QWidget * parent = nullptr); ~PermissionWidget(void); void setAttributes(DatabaseModel *model, BaseObject *objeto_pai, BaseObject *object); public slots: void applyConfiguration(void); private slots: //! \brief Shows the object selection window void selectRole(void); //! \brief Select a permission which the index is specified on parameter void selectPermission(int perm_id); //! \brief Adds the configured permission onto the model void addPermission(void); //! \brief Configures a permission based upon the values assinged on the form void configurePermission(Permission *perm); //! \brief Fills the form with the selected permission attributes void editPermission(void); //! \brief Removes the selected permission void removePermission(int); //! \brief Removes all permissions from the permissions table void removePermissions(void); //! \brief Updates the attributes of the currently edited permission void updatePermission(void); //! \brief Lists all permissions related to the object void listPermissions(void); //! \brief Cancel de permission's creation/edition cleaning the form and blocking the edition buttons void cancelOperation(void); //! \brief Shows the selected role data on the role tables void showSelectedRoleData(void); //! \brief Updates the sql code for object's permissions void updateCodePreview(void); void enableEditButtons(void); void checkPrivilege(void); void disableGrantOptions(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/pgmodelerplugin.cpp000066400000000000000000000065101360462764600233520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pgmodelerplugin.h" PgModelerPlugin::PgModelerPlugin(void) { QGridLayout *gridLayout=nullptr; QSpacerItem *verticalSpacer=nullptr; QFont font; QWidget *widget=nullptr; main_window = nullptr; plugin_info_frm=new BaseForm; gridLayout=new QGridLayout; widget=new QWidget; widget->setWindowTitle(QT_TRANSLATE_NOOP("PgModelerPlugin", "Plugin Information")); gridLayout->setHorizontalSpacing(10); gridLayout->setVerticalSpacing(6); gridLayout->setContentsMargins(6, 6, 6, 6); icon_lbl = new QLabel(widget); icon_lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); icon_lbl->setMinimumSize(QSize(32, 32)); icon_lbl->setMaximumSize(QSize(32, 32)); gridLayout->addWidget(icon_lbl, 0, 0, 2, 1); title_lbl = new QLabel(widget); title_lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); font.setPointSize(12); font.setBold(true); font.setItalic(true); font.setWeight(75); title_lbl->setFont(font); gridLayout->addWidget(title_lbl, 0, 1, 1, 1); author_lbl = new QLabel(widget); author_lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); gridLayout->addWidget(author_lbl, 1, 1, 2, 1); verticalSpacer = new QSpacerItem(20, 18, QSizePolicy::Minimum, QSizePolicy::Expanding); gridLayout->addItem(verticalSpacer, 2, 0, 2, 1); version_lbl = new QLabel(widget); version_lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); gridLayout->addWidget(version_lbl, 3, 1, 1, 1); description_lbl = new QLabel(widget); description_lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); description_lbl->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); description_lbl->setWordWrap(true); gridLayout->addWidget(description_lbl, 4, 0, 1, 2); widget->setLayout(gridLayout); widget->setMinimumSize(400, 200); plugin_info_frm->setMainWidget(widget); } PgModelerPlugin::~PgModelerPlugin(void) { delete(plugin_info_frm); } void PgModelerPlugin::initPlugin(QMainWindow *main_window) { this->main_window = main_window; } QKeySequence PgModelerPlugin::getPluginShortcut(void) { return(QKeySequence()); } bool PgModelerPlugin::hasMenuAction(void) { return (true); } void PgModelerPlugin::configurePluginInfo(const QString &title, const QString &version, const QString &author, const QString &description, const QString &ico_filename) { QPixmap ico; title_lbl->setText(title); version_lbl->setText(QString(QT_TRANSLATE_NOOP("PgModelerPlugin", "Version: %1")).arg(version)); author_lbl->setText(QString(QT_TRANSLATE_NOOP("PgModelerPlugin","Author: %1")).arg(author)); description_lbl->setText(description); ico.load(ico_filename); icon_lbl->setPixmap(ico); } pgmodeler-0.9.2/libpgmodeler_ui/src/pgmodelerplugin.h000066400000000000000000000101431360462764600230140ustar00rootroot00000000000000/* # Projeto: Modelador de Banco de Dados PostgreSQL (pgsqlDBM) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class PgModelerPlugin \brief Implements the basic operations to create third party plugins based upon shared libraries. */ #ifndef PGMODELER_PLUGIN_H #define PGMODELER_PLUGIN_H #include "modelwidget.h" #include "baseform.h" /* The plugins in pgModeler must be within the "plugins" folder in its own directory and must have the following basic structure: [PGMODELER_PLUGINS_DIR]/ | + - pluginA/ | + ---- (lib)*(pluginA.)(so|dylib|dll) (library) | + ---- pluginA.png (icon) > Library: it is the shared object that represents the plugin. The prefix (lib) and suffix (so|dylib|dll) are plataform dependent. > Icon: it is a PNG image that represents the plugin on the plugins toolbar. > Plugins can have a optional lang subdir in which are stored the translation for them. The translation files must be named as [plugin name].[lang code].qm, for instance, Brazilian Portuguese translation for "dummy" would be: "dummy.pt_BR.qm". Note: Plugins can have another additional subdirectories but any reference to them must be made programatically by the plugin author. */ class PgModelerPlugin { protected: BaseForm *plugin_info_frm; QMainWindow *main_window; private: QLabel *icon_lbl, *title_lbl, *author_lbl, *version_lbl, *description_lbl; public: PgModelerPlugin(void); virtual ~PgModelerPlugin(void); /*! \brief This method is executed right before the main window is created and can be used to perform * plugin's initializations like UI modications and other miscellaneous initialization that can't be done * in the constructor. Additionally, a main window instance can be passed to the plugin in order to facilitate * customization on the UI. The default implementation is to do nothing else then only expose main window to the plugin. */ virtual void initPlugin(QMainWindow *main_window); //! \brief Executes the plugins having a ModelWidget as input parameter. virtual void executePlugin(ModelWidget *modelo)=0; //! \brief Returns the plugin's title, this same text is used as action's text on plugins toolbar. virtual QString getPluginTitle(void)=0; //! \brief Returns the plugin's author virtual QString getPluginAuthor(void)=0; //! \brief Returns the plugin's version virtual QString getPluginVersion(void)=0; //! \brief Returns the plugin's complete description virtual QString getPluginDescription(void)=0; //! \brief Shows the plugin's information dialog virtual void showPluginInfo(void) = 0; /*! \brief Returns the plugin's action shortcut * The default implementation is to return an empty shortcut */ virtual QKeySequence getPluginShortcut(void); /*! \brief Indicates if the plugin's has an action to be installed in a Qmenu instance * The default implementation is to indicate the presence of an action */ virtual bool hasMenuAction(void); //! \brief Sets the plugin's all attributes at once. void configurePluginInfo(const QString &title, const QString &version, const QString &author, const QString &description, const QString &ico_filename); }; /* Declares the class PgModelerPlugin as interface, this means that the class is a base for plugin implementation. All plugin must inherit this class and use the Q_INTERFACE directive in its declaration */ Q_DECLARE_INTERFACE(PgModelerPlugin,"br.com.pgmodeler.PgModelerPlugin") #endif pgmodeler-0.9.2/libpgmodeler_ui/src/pgmodeleruins.cpp000066400000000000000000000300171360462764600230310ustar00rootroot00000000000000#include "pgmodeleruins.h" #include "messagebox.h" #include "databasemodel.h" #include #include #include "numberedtexteditor.h" #include #include #include "baseform.h" #include "bulkdataeditwidget.h" namespace PgModelerUiNs { NumberedTextEditor *createNumberedTextEditor(QWidget *parent, bool handle_ext_files) { NumberedTextEditor *editor=new NumberedTextEditor(parent, handle_ext_files); if(parent && !parent->layout()) { QHBoxLayout *layout=new QHBoxLayout(parent); layout->setContentsMargins(0,0,0,0); layout->addWidget(editor); } return(editor); } QTreeWidgetItem *createOutputTreeItem(QTreeWidget *output_trw, const QString &text, const QPixmap &ico, QTreeWidgetItem *parent, bool expand_item, bool word_wrap) { if(!output_trw) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); QTreeWidgetItem *item=nullptr; item=new QTreeWidgetItem(parent); item->setIcon(0, ico); if(!parent) output_trw->insertTopLevelItem(output_trw->topLevelItemCount(), item); if(!word_wrap) item->setText(0, text); else { QLabel *label=new QLabel; label->setUpdatesEnabled(false); label->setTextFormat(Qt::AutoText); label->setText(text); label->setWordWrap(true); label->setTextInteractionFlags(Qt::TextSelectableByMouse); label->setUpdatesEnabled(true); label->setMinimumHeight(output_trw->iconSize().height() * 1.5); label->setMaximumHeight(label->heightForWidth(label->width())); item->setSizeHint(0, QSize(label->width(), label->minimumHeight())); output_trw->setItemWidget(item, 0, label); } item->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); item->setExpanded(expand_item); output_trw->setItemHidden(item, false); output_trw->scrollToBottom(); return(item); } void createOutputListItem(QListWidget *output_lst, const QString &text, const QPixmap &ico, bool is_formated) { if(!output_lst) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); QListWidgetItem *item=new QListWidgetItem; item->setIcon(ico); output_lst->addItem(item); if(!is_formated) item->setText(text); else { QLabel *label=new QLabel; int txt_height = 0; txt_height = output_lst->fontMetrics().height() * text.count(QString("
")); if(txt_height == 0) txt_height = output_lst->fontMetrics().height() * 1.25; else txt_height *= 1.05; label->setUpdatesEnabled(false); label->setTextFormat(Qt::AutoText); label->setText(text); label->setWordWrap(true); label->setTextInteractionFlags(Qt::TextSelectableByMouse); label->setUpdatesEnabled(true); item->setSizeHint(QSize(output_lst->width(), txt_height)); output_lst->setItemWidget(item, label); } } void disableObjectSQL(BaseObject *object, bool disable) { if(object && object->getObjectType()!=ObjectType::BaseRelationship) { Messagebox msgbox; ObjectType obj_type=object->getObjectType(); bool curr_val=object->isSQLDisabled(); TableObject *tab_obj = dynamic_cast(object); if(object->isSystemObject()) throw Exception(Exception::getErrorMessage(ErrorCode::OprReservedObject) .arg(object->getName(true)) .arg(object->getTypeName()), ErrorCode::OprReservedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); object->setSQLDisabled(disable); if(tab_obj && tab_obj->getParentTable()) tab_obj->getParentTable()->setModified(true); if(obj_type!=ObjectType::Database && curr_val!=disable) { msgbox.show(QString(QT_TR_NOOP("Do you want to apply the SQL %1 status to the object's references too? This will avoid problems when exporting or validating the model.")).arg(disable ? QT_TR_NOOP("disabling") : QT_TR_NOOP("enabling")), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msgbox.result()==QDialog::Accepted) disableReferencesSQL(object); } /* Special case for tables. When disable the code there is the need to disable constraints * codes when the code of parent table is disabled too in order to avoid export errors */ if(PhysicalTable::isPhysicalTable(object->getObjectType())) { Constraint *constr = nullptr; vector *objects=dynamic_cast(object)->getObjectList(ObjectType::Constraint); for(auto &obj : (*objects)) { constr=dynamic_cast(obj); /* If the constraint is not FK but is declared outside table via alter (ALTER TABLE...ADD CONSTRAINT...) or * The constraint is FK and the reference table is disabled the FK will not be enabled */ if((constr->getConstraintType()!=ConstraintType::ForeignKey && !constr->isDeclaredInTable()) || (constr->getConstraintType()==ConstraintType::ForeignKey && (disable || (!disable && !constr->getReferencedTable()->isSQLDisabled())))) constr->setSQLDisabled(disable); } } } } void disableReferencesSQL(BaseObject *object) { if(object && object->getDatabase()) { vector refs; TableObject *tab_obj=nullptr; DatabaseModel *model=dynamic_cast(object->getDatabase()); model->getObjectReferences(object, refs); while(!refs.empty()) { tab_obj=dynamic_cast(refs.back()); //If the object is a relationship added does not do anything since the relationship itself will be disabled if(refs.back()->getObjectType()!=ObjectType::BaseRelationship && (!tab_obj || (tab_obj && !tab_obj->isAddedByRelationship()))) { refs.back()->setSQLDisabled(object->isSQLDisabled()); //Update the parent table graphical representation to show the disabled child object if(tab_obj) tab_obj->getParentTable()->setModified(true); //Disable the references of the current object too disableReferencesSQL(refs.back()); } refs.pop_back(); } } } QString formatMessage(const QString &msg) { QString fmt_msg=msg; QChar start_chrs[2]={'`','('}, end_chrs[2]={'\'', ')'}; QStringList start_tags={ QString(""), QString("(") }, end_tags={ QString(""), QString(")") }; int pos=-1, pos1=-1; // Replacing the form `' by and () by for(int chr_idx=0; chr_idx < 2; chr_idx++) { pos=0; do { pos=fmt_msg.indexOf(start_chrs[chr_idx], pos); pos1=fmt_msg.indexOf(end_chrs[chr_idx], pos); if(pos >= 0 && pos1 >=0) { fmt_msg.replace(pos, 1 , start_tags[chr_idx]); pos1 += start_tags[chr_idx].length() - 1; fmt_msg.replace(pos1, 1, end_tags[chr_idx]); } else break; pos=pos1; } while(pos >= 0 && pos < fmt_msg.size()); } fmt_msg.replace(QString("\n"), QString("
")); return(fmt_msg); } void configureWidgetFont(QWidget *widget, unsigned factor_id) { double factor = 1; switch(factor_id) { case SmallFontFactor: factor=0.80; break; case MediumFontFactor: factor=0.90; break; case BigFontFactor: factor=1.10; break; case HugeFontFactor: default: factor=1.40; break; } __configureWidgetFont(widget, factor); } void __configureWidgetFont(QWidget *widget, double factor) { if(!widget) return; QFont font=widget->font(); font.setPointSizeF(font.pointSizeF() * factor); widget->setFont(font); } void createExceptionsTree(QTreeWidget *exceptions_trw, Exception &e, QTreeWidgetItem *root) { vector list; vector::reverse_iterator itr, itr_end; QString text; int idx=0; QTreeWidgetItem *item=nullptr, *child_item=nullptr; if(!exceptions_trw) return; e.getExceptionsList(list); itr = list.rbegin(); itr_end = list.rend(); //for(Exception &ex : list) while(itr != itr_end) { text=QString("[%1] - %2").arg(idx).arg(itr->getMethod()); item=createOutputTreeItem(exceptions_trw, text, QPixmap(getIconPath("funcao")), root, false, true); text=QString("%1 (%2)").arg(itr->getFile()).arg(itr->getLine()); createOutputTreeItem(exceptions_trw, text, QPixmap(getIconPath("codigofonte")), item, false, true); text=QString("%1 (%2)").arg(Exception::getErrorCode(itr->getErrorCode())).arg(enum_cast(itr->getErrorCode())); createOutputTreeItem(exceptions_trw, text, QPixmap(getIconPath("msgbox_alerta")), item, false, true); child_item=createOutputTreeItem(exceptions_trw, itr->getErrorMessage(), QPixmap(getIconPath("msgbox_erro")), item, false, true); exceptions_trw->itemWidget(child_item, 0)->setStyleSheet(QString("color: #ff0000;")); if(!itr->getExtraInfo().isEmpty()) { child_item=createOutputTreeItem(exceptions_trw, itr->getExtraInfo(), QPixmap(getIconPath("msgbox_info")), item, false, true); exceptions_trw->itemWidget(child_item, 0)->setStyleSheet(QString("color: #000080;")); } idx++; itr++; /* If we have a stack bigger than 30 items we just ignore the rest in order to avoid * the production or reduntant/useless information on the exception message box */ if(static_cast(idx) >= Exception::MaximumStackSize) { text = QT_TR_NOOP("Another %1 error(s) were suppressed due to stacktrace size limits."); text = text.arg(list.size() - idx); createOutputTreeItem(exceptions_trw, text, QPixmap(getIconPath("msgbox_alerta")), item, false, false); break; } } } QString getIconPath(const QString &icon) { return(QString(":/icones/icones/%1.png").arg(icon)); } QString getIconPath(ObjectType obj_type) { return(getIconPath(BaseObject::getSchemaName(obj_type))); } void resizeDialog(QWidget *widget) { QSize min_size=widget->minimumSize(); int max_h = 0, curr_w =0, curr_h = 0, screen_id = qApp->desktop()->screenNumber(qApp->activeWindow()); QScreen *screen=qApp->screens().at(screen_id); double dpi_factor = 0; double pixel_ratio = 0; dpi_factor = screen->logicalDotsPerInch() / 96.0; pixel_ratio = screen->devicePixelRatio(); //If the dpi_factor is unchanged (1) we keep the dialog original dimension if(dpi_factor <= 1.01) return; max_h = screen->size().height() * 0.70; /* If the widget's minimum size is zero then we need to do a size adjustment on the widget prior to insert it into the dialog */ if(min_size.height() <= 0 || min_size.width() <= 0) { widget->adjustSize(); min_size=widget->size(); } widget->adjustSize(); curr_h=widget->height(); curr_w=min_size.width(); // If the current height is greater than the widget's minimum height we will use a medium value if(curr_h > min_size.height() && min_size.height() < max_h) curr_h = (curr_h + min_size.height())/2.5; //Using the maximum height if the widget's minimum height exceeds the maximum allowed else if(min_size.height() >= max_h) curr_h = max_h; curr_w *= dpi_factor * pixel_ratio; curr_h *= dpi_factor * pixel_ratio; if(curr_w > screen->size().width()) curr_w = screen->size().width() * 0.80; if(curr_h > screen->size().height()) curr_h = screen->size().height() * 0.80; widget->setMinimumSize(widget->minimumSize()); widget->resize(curr_w, curr_h); widget->adjustSize(); } void bulkDataEdit(QTableWidget *results_tbw) { if(!results_tbw) return; BaseForm base_frm; BulkDataEditWidget *bulkedit_wgt = new BulkDataEditWidget; base_frm.setMainWidget(bulkedit_wgt); base_frm.setButtonConfiguration(Messagebox::OkCancelButtons); if(base_frm.exec() == QDialog::Accepted) { QList sel_ranges=results_tbw->selectedRanges(); for(auto range : sel_ranges) { for(int row = range.topRow(); row <= range.bottomRow(); row++) { for(int col = range.leftColumn(); col <= range.rightColumn(); col++) { results_tbw->item(row, col)->setText(bulkedit_wgt->value_edt->toPlainText()); } } } } } void createDropShadow(QToolButton *btn, int x_offset, int y_offset, int radius) { QGraphicsDropShadowEffect *shadow=nullptr; shadow=new QGraphicsDropShadowEffect(btn); shadow->setXOffset(x_offset); shadow->setYOffset(y_offset); shadow->setBlurRadius(radius); shadow->setColor(QColor(0,0,0, 100)); btn->setGraphicsEffect(shadow); } } pgmodeler-0.9.2/libpgmodeler_ui/src/pgmodeleruins.h000066400000000000000000000075371360462764600225110ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler \namespace PgModelerUiNS \brief This namespace is used to organize all functions or constants used in the libpgmodeler_ui package. */ #ifndef PGMODELER_UI_NS_H #define PGMODELER_UI_NS_H #include #include #include #include #include "baseobject.h" #include "numberedtexteditor.h" namespace PgModelerUiNs { static constexpr unsigned SmallFontFactor = 0, MediumFontFactor = 1, BigFontFactor = 2, HugeFontFactor = 3; extern void configureWidgetFont(QWidget *widget, unsigned factor_id); extern void __configureWidgetFont(QWidget *widget, double factor); /*! \brief Creates a NumberedTextEditor instance automatically assigning it to 'parent'. This method will create a layout if 'parent' doesn't has one. If parent has a layout the method will do nothing. If parent is null creates an orphan object which means the user must take care of the destruction of the object */ extern NumberedTextEditor *createNumberedTextEditor(QWidget *parent, bool handle_ext_files = false); /*! \brief Creates an item in the specified QTreeWidget instance. The new item is automatically inserted on the QTreeWidget object. Setting word_wrap will create a QLabel instance into item's and assign the text to it. */ extern QTreeWidgetItem *createOutputTreeItem(QTreeWidget *output_trw, const QString &text, const QPixmap &ico=QPixmap(), QTreeWidgetItem *parent=nullptr, bool expand_item=true, bool word_wrap=false); //! \brief Creates an item in the specified QListWidget instance with the specified text and ico extern void createOutputListItem(QListWidget *output_lst, const QString &text, const QPixmap &ico=QPixmap(), bool is_formated=true); /*! \brief Toggles the SQL code for the object. This function also toggles the SQL of the references related to the input object */ extern void disableObjectSQL(BaseObject *object, bool disable); //! \brief Recursively toggles the specified object's references SQL extern void disableReferencesSQL(BaseObject *object); //! \brief Replaces the sequence of chars [`'] by html tags and [()] by extern QString formatMessage(const QString &msg); /*! \brief Fills a tree widget with all the stack trace provided by the passed Exception. A root item can be specified so all created child items are appended to it */ extern void createExceptionsTree(QTreeWidget *exceptions_trw, Exception &e, QTreeWidgetItem *root); //! \brief Returns the path, in the icon resource, to the provided icon name extern QString getIconPath(const QString &icon); //! \brief Returns the path, in the icon resource, to the icon of the provided object type extern QString getIconPath(ObjectType obj_type); //! \brief Resizes the provided dialog considering font dpi changes as well screen size extern void resizeDialog(QWidget *dialog); //! brief Changes the values of the grid selection at once extern void bulkDataEdit(QTableWidget *results_tbw); //! \brief Creates drop shadown on a tool button that represents an QAction extern void createDropShadow(QToolButton *btn, int x_offset = 2, int y_offset = 2, int radius = 5); } #endif pgmodeler-0.9.2/libpgmodeler_ui/src/pgsqltypewidget.cpp000066400000000000000000000152261360462764600234150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pgsqltypewidget.h" const QString PgSQLTypeWidget::InvalidType = QString("invalid_type"); PgSQLTypeWidget::PgSQLTypeWidget(QWidget *parent, const QString &label) : QWidget(parent) { try { QStringList interval_lst, spatial_lst; setupUi(this); if(!label.isEmpty()) groupBox->setTitle(label); this->setWindowTitle(groupBox->title()); format_hl=nullptr; format_hl=new SyntaxHighlighter(format_txt, true); format_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); this->adjustSize(); IntervalType::getTypes(interval_lst); interval_cmb->addItem(""); interval_cmb->addItems(interval_lst); SpatialType::getTypes(spatial_lst); spatial_lst.sort(); spatial_cmb->addItem(trUtf8("NONE")); spatial_cmb->addItems(spatial_lst); type_cmb->installEventFilter(this); connect(type_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeFormat(void))); connect(precision_sb, SIGNAL(valueChanged(int)), this, SLOT(updateTypeFormat(void))); connect(length_sb, SIGNAL(valueChanged(int)), this, SLOT(updateTypeFormat(void))); connect(dimension_sb, SIGNAL(valueChanged(int)), this, SLOT(updateTypeFormat(void))); connect(interval_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeFormat(void))); connect(timezone_chk, SIGNAL(toggled(bool)), this, SLOT(updateTypeFormat(void))); connect(spatial_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeFormat(void))); connect(var_m_chk, SIGNAL(toggled(bool)), this, SLOT(updateTypeFormat(void))); connect(var_z_chk, SIGNAL(toggled(bool)), this, SLOT(updateTypeFormat(void))); connect(srid_spb, SIGNAL(valueChanged(int)), this, SLOT(updateTypeFormat(void))); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } bool PgSQLTypeWidget::eventFilter(QObject *object, QEvent *event) { if(event->type() == QEvent::KeyRelease && object == type_cmb) { try { updateTypeFormat(); } catch(Exception &) { format_txt->setPlainText(InvalidType); } } return(QWidget::eventFilter(object, event)); } void PgSQLTypeWidget::updateTypeFormat(void) { try { QVariant data; //Gets the data related to the current selected data type data=type_cmb->itemData(type_cmb->currentIndex()); //If the data value (index) is 0 indicates that the type is a built-in one if(data.toUInt()==0) type=type_cmb->currentText(); else //Case the index is greated than zero indicates that the type is a user-defined one type=data.toUInt(); length_sb->setEnabled(type.hasVariableLength()); timezone_chk->setVisible(type==QString("timestamp") || type==QString("time")); timezone_lbl->setVisible(timezone_chk->isVisible()); precision_sb->setEnabled(type.acceptsPrecision()); dimension_sb->setEnabled(type!=QString("void")); interval_cmb->setVisible(type==QString("interval")); interval_lbl->setVisible(interval_cmb->isVisible()); spatial_cmb->setVisible(type.isGiSType()); spatial_lbl->setVisible(type.isGiSType()); variation_lbl->setVisible(type.isGiSType()); srid_lbl->setVisible(type.isGiSType()); srid_spb->setVisible(type.isGiSType()); var_m_chk->setVisible(type.isGiSType()); var_z_chk->setVisible(type.isGiSType()); if(spatial_cmb->isVisible()) { SpatialType spatial_tp; spatial_tp=SpatialType(spatial_cmb->currentText(), srid_spb->value()); if(var_z_chk->isChecked() && var_m_chk->isChecked()) spatial_tp.setVariation(SpatialType::VarZm); else if(var_m_chk->isChecked()) spatial_tp.setVariation(SpatialType::VarM); else if(var_z_chk->isChecked()) spatial_tp.setVariation(SpatialType::VarZ); type.setSpatialType(spatial_tp); } type.setLength(length_sb->value()); type.setPrecision(precision_sb->value()); type.setDimension(dimension_sb->value()); type.setIntervalType(interval_cmb->currentText()); type.setWithTimezone(timezone_chk->isChecked()); format_txt->setPlainText(*type); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PgSQLTypeWidget::listPgSQLTypes(QComboBox *combo, DatabaseModel *model, unsigned user_type_conf, bool oid_types, bool pseudo_types) { if(combo) { QStringList types; int idx, count; combo->clear(); //Getting the user defined type adding them into the combo PgSqlType::getUserTypes(types,model, user_type_conf); types.sort(); count=types.size(); for(idx=0; idx < count; idx++) combo->addItem(types[idx], QVariant(PgSqlType::getUserTypeIndex(types[idx],nullptr,model))); //Getting the built-in type adding them into the combo PgSqlType::getTypes(types, oid_types, pseudo_types); types.sort(); combo->addItems(types); } } void PgSQLTypeWidget::setAttributes(PgSqlType type, DatabaseModel *model, unsigned usr_type_conf, bool oid_types, bool pseudo_types) { try { int idx; QString type_name; type_cmb->blockSignals(true); listPgSQLTypes(type_cmb, model, usr_type_conf, oid_types, pseudo_types); type_cmb->blockSignals(false); //Get the passed type index type_name=~type; type_name.remove(QRegExp(QString("( )(with)(out)?(.)*"))); idx=type_cmb->findText(type_name); //Select the type on the combo type_cmb->setCurrentIndex(idx); length_sb->setValue(type.getLength()); precision_sb->setValue(type.getPrecision()); dimension_sb->setValue(type.getDimension()); idx=interval_cmb->findText(~(type.getIntervalType())); interval_cmb->setCurrentIndex(idx); idx=spatial_cmb->findText(~(type.getSpatialType())); if(idx < 0) idx = 0; spatial_cmb->setCurrentIndex(idx); timezone_chk->setChecked(type.isWithTimezone()); this->type=type; updateTypeFormat(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } PgSqlType PgSQLTypeWidget::getPgSQLType(void) { if(format_txt->toPlainText() == InvalidType) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); return(type); } pgmodeler-0.9.2/libpgmodeler_ui/src/pgsqltypewidget.h000066400000000000000000000043701360462764600230600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class PgSQLTypeWidget \brief Implements the operations to configure PostgreSQL types via form. */ #ifndef PGSQL_TYPE_WIDGET_H #define PGSQL_TYPE_WIDGET_H #include #include "ui_pgsqltypewidget.h" #include "pgsqltypes.h" #include "syntaxhighlighter.h" #include "databasemodel.h" #include "messagebox.h" class PgSQLTypeWidget: public QWidget, public Ui::PgSQLTypeWidget { private: Q_OBJECT //! \brief Stores the PostgreSQL type configured on the form PgSqlType type; //! \brief Syntax highlighter used on the format field SyntaxHighlighter *format_hl; bool eventFilter(QObject *watched, QEvent *event); static const QString InvalidType; public: PgSQLTypeWidget(QWidget * parent = nullptr, const QString &label=QString()); /*! \brief Lists the PostgreSQL types on the specified combo. The user can configure which types must be shown using the last tree parameters. The DatabaseModel parameter is used to gather the user-defined types of the specified model. */ static void listPgSQLTypes(QComboBox *combo, DatabaseModel *model, unsigned user_type_conf=UserTypeConfig::AllUserTypes, bool oid_types=true, bool pseudo_types=true); private slots: void updateTypeFormat(void); public slots: void setAttributes(PgSqlType type, DatabaseModel *model, unsigned usr_type_conf=UserTypeConfig::AllUserTypes, bool oid_types=true, bool pseudo_types=true); //! \brief Returns the PostgreSQL type configured via form PgSqlType getPgSQLType(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/plaintextitemdelegate.cpp000066400000000000000000000037441360462764600245450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "plaintextitemdelegate.h" #include #include PlainTextItemDelegate::PlainTextItemDelegate(QObject *parent, bool read_only) : QStyledItemDelegate(parent) { this->read_only = read_only; } PlainTextItemDelegate::~PlainTextItemDelegate(void) { } void PlainTextItemDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const { QPlainTextEdit *text_edt=qobject_cast(editor); QLineEdit *line_edt=qobject_cast(editor); if(text_edt) { text_edt->setReadOnly(read_only); text_edt->setPlainText(index.data(Qt::DisplayRole).toString()); text_edt->selectAll(); } else if(line_edt) { line_edt->setReadOnly(read_only); line_edt->setText(index.data(Qt::DisplayRole).toString()); } else QStyledItemDelegate::setEditorData(editor, index); } QWidget *PlainTextItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const { QWidget *editor = nullptr; if(index.data(Qt::DisplayRole).toString().contains(QChar('\n'))) { editor = new QPlainTextEdit(parent); qobject_cast(editor)->setFrameShape(QFrame::NoFrame); } else { editor = new QLineEdit(parent); qobject_cast(editor)->setFrame(false); } return(editor); } pgmodeler-0.9.2/libpgmodeler_ui/src/plaintextitemdelegate.h000066400000000000000000000030371360462764600242050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class PlainTextItemDelegate \brief Implements a custom item delegate based upon a QPlainTextEdit to help edit long texts with line breaks */ #ifndef PLAIN_TEXT_ITEM_DELEGATE_H #define PLAIN_TEXT_ITEM_DELEGATE_H #include #include class PlainTextItemDelegate : public QStyledItemDelegate { private: Q_OBJECT bool read_only; public: explicit PlainTextItemDelegate(QObject * parent, bool read_only); ~PlainTextItemDelegate(void); protected: //! \brief Overrides the default implementation and set the editor as read only/disable to prevent change the item data virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/pluginsconfigwidget.cpp000066400000000000000000000124721360462764600242340ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pluginsconfigwidget.h" PluginsConfigWidget::PluginsConfigWidget(QWidget *parent) : BaseConfigWidget(parent) { setupUi(this); QGridLayout *grid=new QGridLayout(loaded_plugins_gb); QDir dir=QDir(GlobalAttributes::PluginsDir); root_dir_edt->setText(dir.absolutePath()); plugins_tab=new ObjectsTableWidget(ObjectsTableWidget::EditButton, false, this); plugins_tab->setColumnCount(3); plugins_tab->setHeaderLabel(trUtf8("Plugin"),0); plugins_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("plugins")),0); plugins_tab->setHeaderLabel(trUtf8("Version"),1); plugins_tab->setHeaderLabel(trUtf8("Library"),2); connect(plugins_tab, SIGNAL(s_rowEdited(int)), this, SLOT(showPluginInfo(int))); connect(open_fm_tb, SIGNAL(clicked(void)), this, SLOT(openRootPluginDiretory(void))); grid->setContentsMargins(4,4,4,4); grid->addWidget(plugins_tab,0,0,1,1); loaded_plugins_gb->setLayout(grid); } PluginsConfigWidget::~PluginsConfigWidget(void) { while(!plugins.empty()) { delete(plugins.back()); plugins.pop_back(); } } void PluginsConfigWidget::openRootPluginDiretory(void) { QDesktopServices::openUrl(QUrl(QString("file://") + root_dir_edt->text())); } void PluginsConfigWidget::showPluginInfo(int idx) { plugins[idx]->showPluginInfo(); } void PluginsConfigWidget::loadConfiguration(void) { vector errors; QString lib, plugin_name, dir_plugins=GlobalAttributes::PluginsDir + GlobalAttributes::DirSeparator; QPluginLoader plugin_loader; QStringList dir_list; PgModelerPlugin *plugin=nullptr; QAction *plugin_action=nullptr; QPixmap icon; QFileInfo fi; //The plugin loader must resolve all symbols otherwise return an error if some symbol is missing on library plugin_loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); /* Configures an QDir instance to list only directories on the plugins/ subdir. If the user does not put the plugin in it's directory the file is ignored */ dir_list=QDir(dir_plugins, QString("*"), QDir::Name, QDir::AllDirs | QDir::NoDotAndDotDot).entryList(); while(!dir_list.isEmpty()) { plugin_name=dir_list.front(); /* Configures the basic path to the library on the form: [PLUGINS ROOT DIR]/[PLUGIN NAME]/lib[PLUGIN NAME].[EXTENSION] */ #ifdef Q_OS_WIN lib=dir_plugins + plugin_name + GlobalAttributes::DirSeparator + plugin_name + QString(".dll"); #else #ifdef Q_OS_MAC lib=dir_plugins + plugin_name + GlobalAttributes::DirSeparator + QString("lib") + plugin_name + QString(".dylib"); #else lib=dir_plugins + plugin_name + GlobalAttributes::DirSeparator + QString("lib") + plugin_name + QString(".so"); #endif #endif //Try to load the library plugin_loader.setFileName(lib); if(plugin_loader.load()) { fi.setFile(lib); //Inserts the loaded plugin on the vector plugin = qobject_cast(plugin_loader.instance()); plugins.push_back(plugin); if(plugin->hasMenuAction()) { //Configures the action related to plugin plugin_action=new QAction(this); plugin_action->setText(plugin->getPluginTitle()); plugin_action->setData(QVariant::fromValue(reinterpret_cast(plugin))); plugin_action->setShortcut(plugin->getPluginShortcut()); icon.load(dir_plugins + plugin_name + GlobalAttributes::DirSeparator + plugin_name + QString(".png")); plugin_action->setIcon(icon); plugins_actions.push_back(plugin_action); } plugins_tab->addRow(); plugins_tab->setCellText(plugin->getPluginTitle(), plugins_tab->getRowCount()-1, 0); plugins_tab->setCellText(plugin->getPluginVersion(), plugins_tab->getRowCount()-1, 1); plugins_tab->setCellText(fi.fileName(), plugins_tab->getRowCount()-1, 2); } else { errors.push_back(Exception(Exception::getErrorMessage(ErrorCode::PluginNotLoaded) .arg(dir_list.front()) .arg(lib) .arg(plugin_loader.errorString()), ErrorCode::PluginNotLoaded, __PRETTY_FUNCTION__,__FILE__,__LINE__)); } dir_list.pop_front(); plugins_tab->clearSelection(); } if(!errors.empty()) throw Exception(ErrorCode::PluginsNotLoaded,__PRETTY_FUNCTION__,__FILE__,__LINE__, errors); } void PluginsConfigWidget::installPluginsActions(QMenu *menu, QObject *recv, const char *slot) { if(menu && slot) { vector::iterator itr=plugins_actions.begin(); while(itr!=plugins_actions.end()) { if(menu) menu->addAction(*itr); connect(*itr, SIGNAL(triggered(void)), recv, slot); itr++; } } } void PluginsConfigWidget::initPlugins(QMainWindow *main_window) { for(auto &plugin : plugins) plugin->initPlugin(main_window); } pgmodeler-0.9.2/libpgmodeler_ui/src/pluginsconfigwidget.h000066400000000000000000000043411360462764600236750ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class PluginsConfigWidget \brief Implements the operations to manage plugins. */ #ifndef PLUGINS_CONFIG_WIDGET_H #define PLUGINS_CONFIG_WIDGET_H #include "baseconfigwidget.h" #include "ui_pluginsconfigwidget.h" #include "objectstablewidget.h" #include "pgmodelerplugin.h" class PluginsConfigWidget: public BaseConfigWidget, public Ui::PluginsConfigWidget { private: Q_OBJECT //! \brief Loaded plugins vector plugins; //! \brief Stores the actions assigned for each plugin vector plugins_actions; //! \brief Table used to show the loaded plugins ObjectsTableWidget *plugins_tab; /* Disabled methods */ void applyConfiguration(void){} void saveConfiguration(void){} void restoreDefaults(void){} void addConfigurationParam(const QString &, const attribs_map &){} public: PluginsConfigWidget(QWidget *parent = nullptr); ~PluginsConfigWidget(void); //! \brief Since plugins has its own configurations this method load all plugins instead void loadConfiguration(void); /*! \brief Install the created actions on menu. Additionally the user must specify the receiver object and slot executed when the actions is activated */ void installPluginsActions(QMenu *menu, QObject *recv, const char *slot); //*! \brief Performs the initialization of all loaded plugins (see PgModelerPlugin::initPlugin()) void initPlugins(QMainWindow *main_window); private slots: void showPluginInfo(int idx); void openRootPluginDiretory(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/policywidget.cpp000066400000000000000000000115021360462764600226550ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "policywidget.h" PolicyWidget::PolicyWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Policy) { try { Ui_PolicyWidget::setupUi(this); model_objs_wgt = new ModelObjectsWidget(true, this); model_objs_wgt->setObjectVisible(ObjectType::Role, true); using_edt = PgModelerUiNs::createNumberedTextEditor(using_wgt); using_edt->setTabChangesFocus(true); using_hl = new SyntaxHighlighter(using_edt); using_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); check_edt = PgModelerUiNs::createNumberedTextEditor(check_wgt); check_edt->setTabChangesFocus(true); check_hl = new SyntaxHighlighter(check_edt); check_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); roles_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::DuplicateButton | ObjectsTableWidget::UpdateButton | ObjectsTableWidget::EditButton), true, this); roles_tab->setColumnCount(1); roles_tab->setHeaderLabel(trUtf8("Name"), 0); roles_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")), 0); QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget(roles_tab); QFrame *frame=generateInformationFrame(trUtf8("Leave the Roles grid empty in order to create a %1 applicable to PUBLIC.") .arg(BaseObject::getTypeName(ObjectType::Policy).toLower())); vbox->addWidget(frame); frame->setParent(this); vbox->setContentsMargins(4,4,4,4); attribs_tbw->widget(0)->setLayout(vbox); QStringList cmds; PolicyCmdType::getTypes(cmds); command_cmb->addItems(cmds); configureFormLayout(policy_grid, ObjectType::Policy); configureTabOrder({ basics_grp, attribs_tbw }); connect(roles_tab, SIGNAL(s_rowAdded(int)), model_objs_wgt, SLOT(show())); connect(model_objs_wgt, SIGNAL(s_visibilityChanged(BaseObject*, bool)), this, SLOT(selectRole(BaseObject*, bool))); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PolicyWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *parent_obj, Policy *policy) { if(!parent_obj) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, policy, parent_obj); model_objs_wgt->setModel(model); if(policy) { command_cmb->setCurrentText(~policy->getPolicyCommand()); permissive_chk->setChecked(policy->isPermissive()); check_edt->setPlainText(policy->getCheckExpression()); using_edt->setPlainText(policy->getUsingExpression()); roles_tab->blockSignals(true); for(auto role : policy->getRoles()) { roles_tab->addRow(); roles_tab->setCellText(role->getName(), roles_tab->getRowCount() - 1, 0); roles_tab->setRowData(QVariant::fromValue(reinterpret_cast(role)), roles_tab->getRowCount() - 1); } roles_tab->blockSignals(false); } } void PolicyWidget::selectRole(BaseObject *role, bool show_wgt) { if(!show_wgt) { if(!role) roles_tab->removeRow(roles_tab->getRowCount() - 1); else { roles_tab->setCellText(role->getName(), roles_tab->getRowCount() - 1, 0); roles_tab->setRowData(QVariant::fromValue(reinterpret_cast(role)), roles_tab->getRowCount() - 1); } } } void PolicyWidget::applyConfiguration(void) { try { Policy *policy = nullptr; unsigned count, i; startConfiguration(); policy =dynamic_cast(this->object); policy->removeRoles(); policy->setUsingExpression(using_edt->toPlainText()); policy->setCheckExpression(check_edt->toPlainText()); policy->setPermissive(permissive_chk->isChecked()); policy->setPolicyCommand(command_cmb->currentText()); count=roles_tab->getRowCount(); for(i=0; i < count; i++) policy->addRole(reinterpret_cast(roles_tab->getRowData(i).value())); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/policywidget.h000066400000000000000000000027061360462764600223300ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #ifndef POLICY_WIDGET_H #define POLICY_WIDGET_H #include #include "baseobjectwidget.h" #include "ui_policywidget.h" #include "policy.h" #include "objectstablewidget.h" #include "modelobjectswidget.h" class PolicyWidget : public BaseObjectWidget, Ui::PolicyWidget { private: Q_OBJECT ModelObjectsWidget *model_objs_wgt; ObjectsTableWidget *roles_tab; SyntaxHighlighter *using_hl, *check_hl; NumberedTextEditor *using_edt, *check_edt; public: PolicyWidget(QWidget *parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *parent_obj, Policy *policy); public slots: void applyConfiguration(void); private slots: void selectRole(BaseObject *role, bool show_wgt); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/referencewidget.cpp000066400000000000000000000313421360462764600233200ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "referencewidget.h" #include "baseobjectwidget.h" ReferenceWidget::ReferenceWidget(QWidget *parent) : QWidget(parent) { setupUi(this); model = nullptr; ref_flags = 0; ref_alias_ht=new HintTextWidget(ref_alias_hint, this); ref_alias_ht->setText(ref_alias_edt->statusTip()); used_in_ht=new HintTextWidget(used_in_hint, this); used_in_ht->setText(select_from_chk->statusTip()); ref_object_ht=new HintTextWidget(ref_object_hint, this); ref_object_ht->setText(trUtf8("To reference all columns of a table select only a table in the object selector, this is the same as write [schema].[table].*. In order to reference a only a single column of a table select a column object in the selector.")); alias_ht=new HintTextWidget(alias_hint, this); alias_ht->setText(alias_edt->statusTip()); expression_txt=new NumberedTextEditor(this, true); expression_hl=new SyntaxHighlighter(expression_txt, false, true); expression_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); ref_object_sel=new ObjectSelectorWidget({ ObjectType::Table, ObjectType::ForeignTable, ObjectType::Column }, true, this); ref_object_sel->enableObjectCreation(false); expression_cp=new CodeCompletionWidget(expression_txt, true); QGridLayout *grid = dynamic_cast(properties_tbw->widget(0)->layout()); grid->addWidget(ref_object_sel, 2, 1, 1, 3); grid->addWidget(expression_txt, 4, 1, 1, 4); properties_tbw->setTabEnabled(1, false); properties_tbw->setTabEnabled(2, false); pgsqltype_wgt = new PgSQLTypeWidget(this); columns_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons, true, this); columns_tab->setColumnCount(3); columns_tab->setHeaderLabel(trUtf8("Name"), 0); columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); columns_tab->setHeaderLabel(trUtf8("Type"), 1); columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); columns_tab->setHeaderLabel(trUtf8("Alias"), 2); QFrame *info_frm=BaseObjectWidget::generateInformationFrame(trUtf8("This tab can be used to inform the columns that the view owns. This is just a convenience to make the visualization of this kind of object more intuitive. If no column is specified here the columns of the view displayed in the canvas will be a fragment of the expression defined in the previous tab.")); QVBoxLayout *vbox = dynamic_cast(properties_tbw->widget(1)->layout()); vbox->addWidget(pgsqltype_wgt); vbox->addWidget(columns_tab); info_frm->setParent(this); vbox->addWidget(info_frm); ref_tables_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton | ObjectsTableWidget::DuplicateButton| ObjectsTableWidget::EditButton), true, this); ref_tables_tab->setColumnCount(3); ref_tables_tab->setHeaderLabel(trUtf8("Name"), 0); ref_tables_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); ref_tables_tab->setHeaderLabel(trUtf8("Schema"), 1); ref_tables_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("schema")),1); ref_table_sel=new ObjectSelectorWidget({ ObjectType::Table, ObjectType::ForeignTable }, true, this); ref_table_sel->enableObjectCreation(false); QHBoxLayout *hbox = new QHBoxLayout; hbox->addWidget(ref_table_lbl); hbox->addWidget(ref_table_sel); info_frm=BaseObjectWidget::generateInformationFrame(trUtf8("This tab can be used to inform the tables that the view references. This is just a convenience to make the visualization of this kind of object more intuitive. If no table is specified here no relationship will be displayed in the canvas. Note that no validation will be done to check if the provided tables are really referenced by the view.")); vbox = new QVBoxLayout; vbox->setContentsMargins(4,4,4,4); vbox->addLayout(hbox); vbox->addWidget(ref_tables_tab); vbox->addWidget(info_frm); properties_tbw->widget(2)->setLayout(vbox); selectReferenceType(); setMinimumSize(640, 480); connect(columns_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addColumn(int))); connect(columns_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(updateColumn(int))); connect(columns_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editColumn(int))); connect(columns_tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateColumn(int,int))); connect(ref_tables_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addRefTable(int))); connect(view_def_chk, SIGNAL(toggled(bool)), select_from_chk, SLOT(setDisabled(bool))); connect(view_def_chk, SIGNAL(toggled(bool)), from_where_chk, SLOT(setDisabled(bool))); connect(view_def_chk, SIGNAL(toggled(bool)), after_where_chk, SLOT(setDisabled(bool))); connect(view_def_chk, SIGNAL(toggled(bool)), end_expr_chk, SLOT(setDisabled(bool))); connect(view_def_chk, &QCheckBox::toggled, [&](bool checked){ properties_tbw->setTabEnabled(1, checked); properties_tbw->setTabEnabled(2, checked); }); connect(ref_type_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(selectReferenceType(void))); connect(ref_object_sel, &ObjectSelectorWidget::s_objectSelected, [&](){ col_alias_edt->setEnabled(dynamic_cast(ref_object_sel->getSelectedObject())); }); connect(ref_object_sel, &ObjectSelectorWidget::s_selectorCleared, [&](){ col_alias_edt->setEnabled(false); }); connect(ref_table_sel, &ObjectSelectorWidget::s_selectorChanged, [&](bool selected){ ref_tables_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, selected); }); } void ReferenceWidget::setAttributes(Reference ref, unsigned ref_flags, DatabaseModel *model) { this->ref_flags = ref_flags; this->reference = ref; this->model = model; pgsqltype_wgt->setAttributes(PgSqlType(), model, UserTypeConfig::AllUserTypes ^ UserTypeConfig::SequenceType, true, false); expression_cp->configureCompletion(model, expression_hl); ref_object_sel->setModel(model); ref_table_sel->setModel(model); ref_type_cmb->setCurrentIndex(ref.getReferenceType()); ref_alias_edt->setText(ref.getReferenceAlias()); if(ref.getReferenceType()==Reference::ReferColumn) { if(ref.getColumn()) ref_object_sel->setSelectedObject(ref.getColumn()); else ref_object_sel->setSelectedObject(ref.getTable()); tab_alias_edt->setText(ref.getAlias()); col_alias_edt->setText(ref.getColumnAlias()); } else { expression_txt->setPlainText(ref.getExpression()); expr_alias_edt->setText(ref.getAlias()); } if(ref_flags == Reference::SqlViewDefinition) { int row = 0; view_def_chk->setChecked(true); columns_tab->blockSignals(true); for(auto &col : ref.getColumns()) { columns_tab->addRow(); columns_tab->setCellText(col.name, row, 0); columns_tab->setCellText(col.type, row, 1); columns_tab->setCellText(col.alias, row, 2); columns_tab->setRowData(QVariant::fromValue(PgSqlType::parseString(col.type)), row); row++; } columns_tab->blockSignals(false); ref_tables_tab->blockSignals(true); row = 0; for(auto &tab : ref.getReferencedTables()) { ref_tables_tab->addRow(); ref_tables_tab->setCellText(tab->getName(), row, 0); ref_tables_tab->setCellText(tab->getSchema()->getName(), row, 1); ref_tables_tab->setRowData(QVariant::fromValue(reinterpret_cast(tab)), row); row++; } ref_tables_tab->blockSignals(false); columns_tab->clearSelection(); ref_tables_tab->clearSelection(); } else { select_from_chk->setChecked((ref_flags & Reference::SqlReferSelect) == Reference::SqlReferSelect); from_where_chk->setChecked((ref_flags & Reference::SqlReferFrom) == Reference::SqlReferFrom); after_where_chk->setChecked((ref_flags & Reference::SqlReferWhere) == Reference::SqlReferWhere); end_expr_chk->setChecked((ref_flags & Reference::SqlReferEndExpr) == Reference::SqlReferEndExpr); } ref_tables_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, false); } Reference ReferenceWidget::getReference(void) { return(reference); } unsigned ReferenceWidget::getReferenceFlags(void) { return(ref_flags); } void ReferenceWidget::applyConfiguration(void) { try { //Creating a reference to a column if(static_cast(ref_type_cmb->currentIndex())==Reference::ReferColumn) { Column *column = dynamic_cast(ref_object_sel->getSelectedObject()); PhysicalTable *table = (column ? dynamic_cast(column->getParentTable()) : dynamic_cast(ref_object_sel->getSelectedObject())); reference = Reference(table, column, tab_alias_edt->text(), col_alias_edt->text()); } //Creating a reference to an expression else reference = Reference(expression_txt->toPlainText(), expr_alias_edt->text().toUtf8()); reference.setReferenceAlias(ref_alias_edt->text()); /* The reference must have an SQL application (be between SELECT-FROM, FROM-WHERE or after WHERE), if the user do not check some of these attributes raises an error */ if(!select_from_chk->isChecked() && !from_where_chk->isChecked() && !after_where_chk->isChecked() && !end_expr_chk->isChecked() && !view_def_chk->isChecked()) throw Exception(ErrorCode::InvSQLScopeViewReference,__PRETTY_FUNCTION__,__FILE__,__LINE__); ref_flags = 0; if(view_def_chk->isChecked()) { ref_flags = Reference::SqlViewDefinition; reference.removeColumns(); for(unsigned row = 0; row < columns_tab->getRowCount(); row++) reference.addColumn(columns_tab->getCellText(row, 0), columns_tab->getRowData(row).value(), columns_tab->getCellText(row, 2)); for(unsigned row = 0; row < ref_tables_tab->getRowCount(); row++) reference.addReferencedTable(reinterpret_cast(ref_tables_tab->getRowData(row).value())); } if(select_from_chk->isChecked()) ref_flags |= Reference::SqlReferSelect; if(from_where_chk->isChecked()) ref_flags |= Reference::SqlReferFrom; if(after_where_chk->isChecked()) ref_flags |= Reference::SqlReferWhere; if(end_expr_chk->isChecked()) ref_flags |= Reference::SqlReferEndExpr; emit s_closeRequested(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ReferenceWidget::handleColumn(int row) { PgSqlType type = pgsqltype_wgt->getPgSQLType(); columns_tab->setCellText(name_edt->text(), row, 0); columns_tab->setCellText(*type, row, 1); columns_tab->setCellText(alias_edt->text(), row, 2); columns_tab->setRowData(QVariant::fromValue(type), row); name_edt->clear(); alias_edt->clear(); name_edt->setFocus(); } void ReferenceWidget::addColumn(int row) { if(!name_edt->text().isEmpty()) handleColumn(row); else columns_tab->removeRow(row); } void ReferenceWidget::addRefTable(int row) { PhysicalTable *table = dynamic_cast(ref_table_sel->getSelectedObject()); ref_tables_tab->setRowData(QVariant::fromValue(reinterpret_cast(table)), row); ref_tables_tab->setCellText(table->getName(), row, 0); ref_tables_tab->setCellText(table->getSchema()->getName(), row, 1); ref_table_sel->clearSelector(); } void ReferenceWidget::updateColumn(int row) { if(!name_edt->text().isEmpty()) handleColumn(row); } void ReferenceWidget::editColumn(int row) { name_edt->setText(columns_tab->getCellText(row, 0)); alias_edt->setText(columns_tab->getCellText(row, 2)); pgsqltype_wgt->setAttributes(columns_tab->getRowData(row).value(), model, UserTypeConfig::AllUserTypes ^ UserTypeConfig::SequenceType, true, false); } void ReferenceWidget::duplicateColumn(int src_row, int new_row) { columns_tab->setRowData(columns_tab->getRowData(src_row), new_row); } void ReferenceWidget::selectReferenceType(void) { //Marks if the select reference type treats a reference to an object bool ref_obj=(ref_type_cmb->currentIndex()==static_cast(Reference::ReferColumn)); ref_object_sel->setEnabled(ref_obj); tab_alias_edt->setEnabled(ref_obj); col_alias_edt->setEnabled(ref_obj); view_def_chk->setChecked(false); expression_txt->setEnabled(!ref_obj); expr_alias_edt->setEnabled(!ref_obj); view_def_chk->setVisible(!ref_obj); properties_tbw->setTabEnabled(1, !ref_obj && view_def_chk->isChecked()); } pgmodeler-0.9.2/libpgmodeler_ui/src/referencewidget.h000066400000000000000000000040701360462764600227630ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #ifndef REFERENCE_WIDGET_H #define REFERENCE_WIDGET_H #include #include "ui_referencewidget.h" #include "numberedtexteditor.h" #include "syntaxhighlighter.h" #include "codecompletionwidget.h" #include "objectselectorwidget.h" #include "hinttextwidget.h" #include "pgsqltypewidget.h" #include "objectstablewidget.h" class ReferenceWidget : public QWidget, Ui::ReferenceWidget { private: Q_OBJECT HintTextWidget *ref_alias_ht, *used_in_ht, *ref_object_ht, *alias_ht; NumberedTextEditor *expression_txt; SyntaxHighlighter *expression_hl; CodeCompletionWidget *expression_cp; ObjectSelectorWidget *ref_object_sel, *ref_table_sel; PgSQLTypeWidget *pgsqltype_wgt; ObjectsTableWidget *columns_tab, *ref_tables_tab; unsigned ref_flags; Reference reference; DatabaseModel *model; void handleColumn(int row); public: explicit ReferenceWidget(QWidget *parent = nullptr); void setAttributes(Reference ref, unsigned ref_flags, DatabaseModel *model); Reference getReference(void); unsigned getReferenceFlags(void); public slots: void applyConfiguration(void); private slots: void selectReferenceType(void); void addColumn(int row); void addRefTable(int row); void updateColumn(int row); void editColumn(int row); void duplicateColumn(int src_row, int new_row); signals: void s_closeRequested(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/relationshipconfigwidget.cpp000066400000000000000000000262331360462764600252540ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "relationshipconfigwidget.h" map RelationshipConfigWidget::config_params; RelationshipConfigWidget::RelationshipConfigWidget(QWidget * parent) : BaseConfigWidget(parent) { QStringList list, rel_types={ Attributes::Relationship11, Attributes::Relationship1n, Attributes::RelationshipNn, Attributes::RelationshipGen, Attributes::RelationshipDep, Attributes::RelationshipPart }; unsigned rel_types_id[]={ BaseRelationship::Relationship11, BaseRelationship::Relationship1n, BaseRelationship::RelationshipNn, BaseRelationship::RelationshipGen, BaseRelationship::RelationshipDep, BaseRelationship::RelationshipPart}; Ui_RelationshipConfigWidget::setupUi(this); SyntaxHighlighter *pattern_hl=nullptr; QList pattern_fields={ src_col_pattern_txt, dst_col_pattern_txt, src_fk_pattern_txt, dst_fk_pattern_txt, pk_pattern_txt, uq_pattern_txt, pk_col_pattern_txt }; for(int i=0; i < pattern_fields.size(); i++) { pattern_hl=new SyntaxHighlighter(pattern_fields[i], true); pattern_hl->loadConfiguration(GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::PatternHighlightConf + GlobalAttributes::ConfigurationExt); connect(pattern_fields[i], SIGNAL(textChanged()), this, SLOT(updatePattern())); } fk_to_pk_ht=new HintTextWidget(fk_to_pk_hint, this); fk_to_pk_ht->setText(fk_to_pk_rb->statusTip()); center_pnts_ht=new HintTextWidget(center_pnts_hint, this); center_pnts_ht->setText(center_pnts_rb->statusTip()); tab_edges_ht=new HintTextWidget(tab_edges_hint, this); tab_edges_ht->setText(tab_edges_rb->statusTip()); crows_foot_ht=new HintTextWidget(crows_foot_hint, this); crows_foot_ht->setText(crows_foot_rb->statusTip()); DeferralType::getTypes(list); deferral_cmb->addItems(list); ActionType::getTypes(list); list.push_front(trUtf8("Default")); del_action_cmb->addItems(list); upd_action_cmb->addItems(list); for(int i=0; i < rel_types.size(); i++) rel_type_cmb->addItem(BaseRelationship::getRelationshipTypeName(rel_types_id[i]), rel_types[i]); connect(crows_foot_rb, SIGNAL(toggled(bool)), this, SLOT(enableConnModePreview(void))); connect(fk_to_pk_rb, SIGNAL(toggled(bool)), this, SLOT(enableConnModePreview(void))); connect(center_pnts_rb, SIGNAL(toggled(bool)), this, SLOT(enableConnModePreview(void))); connect(tab_edges_rb, SIGNAL(toggled(bool)), this, SLOT(enableConnModePreview(void))); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_lbl, SLOT(setEnabled(bool))); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_cmb, SLOT(setEnabled(bool))); connect(deferrable_chk, SIGNAL(toggled(bool)), this, SLOT(setConfigurationChanged(bool))); connect(rel_type_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(fillNamePatterns())); connect(del_action_cmb, &QComboBox::currentTextChanged, [&](){ setConfigurationChanged(true); }); connect(upd_action_cmb, &QComboBox::currentTextChanged, [&](){ setConfigurationChanged(true); }); connect(deferral_cmb, &QComboBox::currentTextChanged, [&](){ setConfigurationChanged(true); }); } map RelationshipConfigWidget::getConfigurationParams(void) { return(config_params); } void RelationshipConfigWidget::loadConfiguration(void) { try { int idx; vector key_attribs={Attributes::Type}; BaseConfigWidget::loadConfiguration(GlobalAttributes::RelationshipsConf, config_params, key_attribs); fk_to_pk_rb->setChecked(config_params[Attributes::Connection][Attributes::Mode]==Attributes::ConnectFkToPk); center_pnts_rb->setChecked(config_params[Attributes::Connection][Attributes::Mode]==Attributes::ConnectCenterPnts); tab_edges_rb->setChecked(config_params[Attributes::Connection][Attributes::Mode]==Attributes::ConnectTableEdges); crows_foot_rb->setChecked(config_params[Attributes::Connection][Attributes::Mode]==Attributes::CrowsFoot); deferrable_chk->setChecked(config_params[Attributes::ForeignKeys][Attributes::Deferrable]==Attributes::True); deferral_cmb->setCurrentText(config_params[Attributes::ForeignKeys][Attributes::DeferType]); idx=upd_action_cmb->findText(config_params[Attributes::ForeignKeys][Attributes::UpdAction]); upd_action_cmb->setCurrentIndex(idx < 0 ? 0 : idx); idx=del_action_cmb->findText(config_params[Attributes::ForeignKeys][Attributes::DelAction]); del_action_cmb->setCurrentIndex(idx < 0 ? 0 : idx); patterns[Attributes::Relationship11]=config_params[Attributes::Relationship11]; patterns[Attributes::Relationship1n]=config_params[Attributes::Relationship1n]; patterns[Attributes::RelationshipNn]=config_params[Attributes::RelationshipNn]; patterns[Attributes::RelationshipGen]=config_params[Attributes::RelationshipGen]; patterns[Attributes::RelationshipDep]=config_params[Attributes::RelationshipDep]; patterns[Attributes::RelationshipPart]=config_params[Attributes::RelationshipPart]; fillNamePatterns(); this->applyConfiguration(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo()); } } void RelationshipConfigWidget::saveConfiguration(void) { try { QString patterns_sch, root_dir; root_dir=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator; patterns_sch=root_dir + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + Attributes::Patterns + GlobalAttributes::SchemaExt; if(crows_foot_rb->isChecked()) config_params[Attributes::Connection][Attributes::Mode]=Attributes::CrowsFoot; else if(fk_to_pk_rb->isChecked()) config_params[Attributes::Connection][Attributes::Mode]=Attributes::ConnectFkToPk; else if(tab_edges_rb->isChecked()) config_params[Attributes::Connection][Attributes::Mode]=Attributes::ConnectTableEdges; else config_params[Attributes::Connection][Attributes::Mode]=Attributes::ConnectCenterPnts; config_params[Attributes::ForeignKeys][Attributes::Deferrable]=(deferrable_chk->isChecked() ? Attributes::True : Attributes::False); config_params[Attributes::ForeignKeys][Attributes::DeferType]=deferral_cmb->currentText(); config_params[Attributes::ForeignKeys][Attributes::UpdAction]=(upd_action_cmb->currentIndex() > 0 ? upd_action_cmb->currentText() : QString()); config_params[Attributes::ForeignKeys][Attributes::DelAction]=(del_action_cmb->currentIndex() > 0 ? del_action_cmb->currentText() : QString()); config_params[Attributes::NamePatterns][Attributes::Patterns]=QString(); for(auto &itr : patterns) { schparser.ignoreUnkownAttributes(true); schparser.ignoreEmptyAttributes(true); config_params[itr.first]=itr.second; config_params[Attributes::NamePatterns][Attributes::Patterns]+=schparser.getCodeDefinition(patterns_sch, itr.second); } BaseConfigWidget::saveConfiguration(GlobalAttributes::RelationshipsConf, config_params); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipConfigWidget::applyConfiguration(void) { RelationshipView::setCrowsFoot(crows_foot_rb->isChecked()); if(!crows_foot_rb->isChecked()) { if(fk_to_pk_rb->isChecked()) RelationshipView::setLineConnectionMode(RelationshipView::ConnectFkToPk); else if(tab_edges_rb->isChecked()) RelationshipView::setLineConnectionMode(RelationshipView::ConnectTableEdges); else RelationshipView::setLineConnectionMode(RelationshipView::ConnectCenterPoints); } } void RelationshipConfigWidget::restoreDefaults(void) { try { BaseConfigWidget::restoreDefaults(GlobalAttributes::RelationshipsConf, false); this->loadConfiguration(); setConfigurationChanged(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipConfigWidget::fillNamePatterns(void) { QString rel_type=rel_type_cmb->currentData().toString(); bool relnn=false, reldep=false, relgen=false; QList inputs={ pk_pattern_txt, uq_pattern_txt, src_col_pattern_txt, dst_col_pattern_txt, src_fk_pattern_txt, dst_fk_pattern_txt, pk_col_pattern_txt }; QList pattern_ids={ Attributes::PkPattern, Attributes::UqPattern, Attributes::SrcColPattern, Attributes::DstColPattern, Attributes::SrcFkPattern, Attributes::DstFkPattern, Attributes::PkColPattern }; relnn=(rel_type==Attributes::RelationshipNn); reldep=(rel_type==Attributes::RelationshipDep || rel_type==Attributes::RelationshipPart); relgen=(rel_type==Attributes::RelationshipGen); dst_col_pattern_txt->setEnabled(relnn); dst_fk_pattern_txt->setEnabled(relnn); src_col_pattern_txt->setEnabled(!relgen && !reldep); src_fk_pattern_txt->setEnabled(!relgen && !reldep); uq_pattern_txt->setEnabled(!relgen && !reldep); pk_col_pattern_txt->setEnabled(relnn); dst_col_pattern_lbl->setEnabled(relnn); dst_fk_pattern_lbl->setEnabled(relnn); src_col_pattern_lbl->setEnabled(!relgen && !reldep); src_fk_pattern_lbl->setEnabled(!relgen && !reldep); uq_pattern_lbl->setEnabled(!relgen && !reldep); pk_col_pattern_lbl->setEnabled(relnn); for(int i=0; i < inputs.size(); i++) { inputs[i]->blockSignals(true); inputs[i]->clear(); if(inputs[i]->isEnabled() && patterns[rel_type].count(pattern_ids[i])) inputs[i]->setPlainText(patterns[rel_type][pattern_ids[i]]); inputs[i]->blockSignals(false); } } void RelationshipConfigWidget::updatePattern(void) { QPlainTextEdit *input=qobject_cast(sender()); QString rel_type=rel_type_cmb->currentData().toString(); map inputs_map={ { pk_pattern_txt, Attributes::PkPattern }, { uq_pattern_txt, Attributes::UqPattern }, { src_col_pattern_txt, Attributes::SrcColPattern }, { dst_col_pattern_txt, Attributes::DstColPattern }, { src_fk_pattern_txt, Attributes::SrcFkPattern }, { dst_fk_pattern_txt, Attributes::DstFkPattern }, { pk_col_pattern_txt, Attributes::PkColPattern } }; setConfigurationChanged(true); patterns[rel_type][inputs_map[input]]=input->toPlainText(); } void RelationshipConfigWidget::enableConnModePreview(void) { crows_foot_lbl->setEnabled(crows_foot_rb->isChecked()); conn_cnt_pnts_lbl->setEnabled(center_pnts_rb->isChecked()); conn_tab_edges_lbl->setEnabled(tab_edges_rb->isChecked()); conn_fk_pk_lbl->setEnabled(fk_to_pk_rb->isChecked()); setConfigurationChanged(true); } void RelationshipConfigWidget::hideEvent(QHideEvent *) { settings_twg->setCurrentIndex(0); } pgmodeler-0.9.2/libpgmodeler_ui/src/relationshipconfigwidget.h000066400000000000000000000035001360462764600247110ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class RelationshipConfigWidget \brief Implements the operations to manage global settings for relationship objects. */ #ifndef RELATIONSHIP_CONFIG_WIDGET_H #define RELATIONSHIP_CONFIG_WIDGET_H #include "ui_relationshipconfigwidget.h" #include "baseconfigwidget.h" #include "pgsqltypes.h" #include "syntaxhighlighter.h" #include "relationshipview.h" #include "hinttextwidget.h" class RelationshipConfigWidget: public BaseConfigWidget, public Ui::RelationshipConfigWidget { private: Q_OBJECT static map config_params; map patterns; HintTextWidget *fk_to_pk_ht, *center_pnts_ht, *tab_edges_ht, *crows_foot_ht; void hideEvent(QHideEvent *); public: RelationshipConfigWidget(QWidget * parent = nullptr); void saveConfiguration(void); void loadConfiguration(void); static map getConfigurationParams(void); public slots: void applyConfiguration(void); void restoreDefaults(void); private slots: void fillNamePatterns(void); void updatePattern(void); void enableConnModePreview(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/relationshipwidget.cpp000066400000000000000000001232551360462764600240700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "relationshipwidget.h" #include "constraintwidget.h" #include "columnwidget.h" #include "tablewidget.h" #include "baseform.h" #include "relationshipconfigwidget.h" #include "generalconfigwidget.h" RelationshipWidget::RelationshipWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Relationship) { try { Ui_RelationshipWidget::setupUi(this); QStringList list; QGridLayout *grid=nullptr; QVBoxLayout *vlayout=nullptr; QFrame *frame=nullptr; QWidgetList pattern_fields={ src_col_pattern_txt, dst_col_pattern_txt, src_fk_pattern_txt, dst_fk_pattern_txt, pk_pattern_txt, uq_pattern_txt, pk_col_pattern_txt }; gen_tab_name_ht=new HintTextWidget(gen_tab_name_hint, this); gen_tab_name_ht->setText(relnn_tab_name_edt->statusTip()); ref_table_ht=new HintTextWidget(ref_table_hint, this); recv_table_ht=new HintTextWidget(recv_table_hint, this); identifier_ht=new HintTextWidget(identifier_hint, this); identifier_ht->setText(identifier_chk->statusTip()); single_pk_ht=new HintTextWidget(single_pk_hint, this); single_pk_ht->setText(single_pk_chk->statusTip()); default_part_ht=new HintTextWidget(default_part_hint, this); default_part_ht->setText(default_part_chk->statusTip()); table1_hl=nullptr; table1_hl=new SyntaxHighlighter(ref_table_txt, true); table1_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); table2_hl=nullptr; table2_hl=new SyntaxHighlighter(recv_table_txt, true); table2_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); for(int i=0; i < pattern_fields.size(); i++) { patterns_hl[i]=new SyntaxHighlighter(qobject_cast(pattern_fields[i]), true); patterns_hl[i]->loadConfiguration(GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::PatternHighlightConf + GlobalAttributes::ConfigurationExt); } attributes_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton | ObjectsTableWidget::MoveButtons), true, this); constraints_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton | ObjectsTableWidget::MoveButtons), true, this); advanced_objs_tab=new ObjectsTableWidget(ObjectsTableWidget::EditButton, true, this); attributes_tab->setColumnCount(2); attributes_tab->setHeaderLabel(trUtf8("Attribute"), 0); attributes_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); attributes_tab->setHeaderLabel(trUtf8("Type"), 1); attributes_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); constraints_tab->setColumnCount(2); constraints_tab->setHeaderLabel(trUtf8("Constraint"), 0); constraints_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("constraint")),0); constraints_tab->setHeaderLabel(trUtf8("Type"), 1); constraints_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); advanced_objs_tab->setColumnCount(2); advanced_objs_tab->setHeaderLabel(trUtf8("Name"), 0); advanced_objs_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); advanced_objs_tab->setHeaderLabel(trUtf8("Type"), 1); advanced_objs_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); connect(advanced_objs_tab, SIGNAL(s_rowEdited(int)), this, SLOT(showAdvancedObject(int))); grid=new QGridLayout; grid->addWidget(attributes_tab, 0,0,1,1); grid->setContentsMargins(4,4,4,4); rel_attribs_tbw->widget(AttributesTab)->setLayout(grid); grid=new QGridLayout; grid->addWidget(constraints_tab, 0,0,1,1); grid->setContentsMargins(4,4,4,4); rel_attribs_tbw->widget(ConstraintsTab)->setLayout(grid); grid=dynamic_cast(rel_attribs_tbw->widget(SpecialPkTab)->layout()); frame=generateInformationFrame(trUtf8("Use the special primary key if you want to include a primary key containing generated columns to the receiver table. Important: if this is a new relationship there is a need to finish its creation and reopen this dialog to create the special primary key.")); grid->addWidget(frame, 1, 0, 1, 1); frame->setParent(rel_attribs_tbw->widget(SpecialPkTab)); grid=new QGridLayout; grid->setContentsMargins(4,4,4,4); grid->addWidget(advanced_objs_tab, 0, 0, 1, 1); frame=generateInformationFrame(trUtf8("This advanced tab shows the objects (columns or table) auto created by the relationship's connection as well the foreign keys that represents the link between the participant tables.")); grid->addWidget(frame, 1, 0, 1, 1); rel_attribs_tbw->widget(AdvancedTab)->setLayout(grid); color_picker=new ColorPickerWidget(1,this); color_picker->setEnabled(false); grid=dynamic_cast(rel_attribs_tbw->widget(GeneralTab)->layout()); grid->addWidget(color_picker, 0, 1); configureFormLayout(relationship_grid, ObjectType::Relationship); DeferralType::getTypes(list); deferral_cmb->addItems(list); frame=generateInformationFrame(trUtf8("Available tokens to define name patterns:
\ %1 = Reference (source) primary key column name. (Ignored on constraint patterns)
\ %2 = Reference (source) table name.
\ %3 = Receiver (destination) table name.
\ %4 = Generated table name. (Only for n:n relationships)") .arg(Relationship::SrcColToken) .arg(Relationship::SrcTabToken) .arg(Relationship::DstTabToken) .arg(Relationship::GenTabToken)); vlayout=dynamic_cast(name_patterns_grp->layout()); vlayout->addWidget(frame); ActionType::getTypes(list); list.push_front(trUtf8("Default")); del_action_cmb->addItems(list); upd_action_cmb->addItems(list); tabs={ nullptr, rel_attribs_tbw->widget(SettingsTab), rel_attribs_tbw->widget(AttributesTab), rel_attribs_tbw->widget(ConstraintsTab), rel_attribs_tbw->widget(SpecialPkTab), rel_attribs_tbw->widget(AdvancedTab) }; tab_labels=QStringList{ QString(), rel_attribs_tbw->tabText(SettingsTab), rel_attribs_tbw->tabText(AttributesTab), rel_attribs_tbw->tabText(ConstraintsTab), rel_attribs_tbw->tabText(SpecialPkTab), rel_attribs_tbw->tabText(AdvancedTab)}; part_bound_expr_txt=new NumberedTextEditor(this, true); part_bound_expr_hl=new SyntaxHighlighter(part_bound_expr_txt); part_bound_expr_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); dynamic_cast(part_bound_expr_gb->layout())->addWidget(part_bound_expr_txt, 1, 0); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_cmb, SLOT(setEnabled(bool))); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_lbl, SLOT(setEnabled(bool))); connect(identifier_chk, &QCheckBox::toggled, [&](){ table1_mand_chk->setDisabled(identifier_chk->isChecked()); table2_mand_chk->setEnabled(!identifier_chk->isChecked() && this->object && dynamic_cast(this->object)->getRelationshipType() != BaseRelationship::Relationship1n); }); connect(attributes_tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removeObjects(void))); connect(attributes_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addObject(void))); connect(attributes_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editObject(int))); connect(attributes_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removeObject(int))); connect(attributes_tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateObject(int,int))); connect(constraints_tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removeObjects(void))); connect(constraints_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addObject(void))); connect(constraints_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editObject(int))); connect(constraints_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removeObject(int))); connect(constraints_tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateObject(int,int))); connect(defaults_rb, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(including_rb, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(excluding_rb, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(defaults_chk, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(constraints_chk, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(comments_chk, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(indexes_chk, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(storage_chk, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(all_chk, SIGNAL(toggled(bool)), this, SLOT(selectCopyOptions(void))); connect(custom_color_chk, SIGNAL(toggled(bool)), color_picker, SLOT(setEnabled(bool))); connect(fk_gconf_chk, SIGNAL(toggled(bool)), this, SLOT(useFKGlobalSettings(bool))); connect(patterns_gconf_chk, SIGNAL(toggled(bool)), this, SLOT(usePatternGlobalSettings(bool))); connect(gen_bound_expr_tb, SIGNAL(clicked(bool)), this, SLOT(generateBoundingExpr())); connect(default_part_chk, SIGNAL(toggled(bool)), part_bound_expr_txt, SLOT(setDisabled(bool))); setMinimumSize(600, 380); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::setAttributes(DatabaseModel *model, OperationList *op_list, PhysicalTable *src_tab, PhysicalTable *dst_tab, unsigned rel_type) { Relationship *rel=nullptr; try { rel=new Relationship(rel_type, src_tab, dst_tab); color_picker->generateRandomColors(); rel->setCustomColor(color_picker->getColor(0)); this->new_object=true; this->setAttributes(model, op_list, rel); op_list->startOperationChain(); operation_count=op_list->getCurrentSize(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseRelationship *base_rel) { unsigned rel_type, i; Relationship *aux_rel=nullptr; bool rel1n=false, relnn=false, relgen_dep=false, use_name_patterns=false, has_foreign_tab=false; if(!base_rel) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, base_rel); if(!this->new_object) { op_list->startOperationChain(); operation_count=op_list->getCurrentSize(); } rel_type=base_rel->getRelationshipType(); rel_type_name_lbl->setText(base_rel->getRelationshipTypeName()); rel_icon_lbl->setPixmap(PgModelerUiNs::getIconPath(base_rel->getRelTypeAttribute().replace("rel", "relationship"))); aux_rel=dynamic_cast(base_rel); has_foreign_tab = (base_rel->getTable(BaseRelationship::SrcTable)->getObjectType() == ObjectType::ForeignTable || base_rel->getTable(BaseRelationship::DstTable)->getObjectType() == ObjectType::ForeignTable); if(base_rel->getObjectType()==ObjectType::BaseRelationship) { if(base_rel->getRelationshipType()!=BaseRelationship::RelationshipFk) { ref_table_lbl->setText(trUtf8("Referer View:")); ref_table_ht->setText(trUtf8("Referer view references one or more columns of a table to construct it's own columns.")); recv_table_ht->setText(trUtf8("Referenced table has its columns referenced by a view in order to construct the columns of this latter.")); } else { ref_table_lbl->setText(trUtf8("Referer Table:")); ref_table_ht->setText(trUtf8("Referer table references one or more columns of a table through foreign keys. This is the (n) side of relationship.")); recv_table_ht->setText(trUtf8("Referenced table has its columns referenced by a table's foreign key. This is the (1) side of relationship.")); } recv_table_lbl->setText(trUtf8("Referenced Table:")); ref_table_txt->setPlainText(base_rel->getTable(BaseRelationship::SrcTable)->getName(true)); recv_table_txt->setPlainText(base_rel->getTable(BaseRelationship::DstTable)->getName(true)); } else if(aux_rel) { if(rel_type == BaseRelationship::RelationshipPart) { ref_table_lbl->setText(trUtf8("Partitioned Table:")); ref_table_ht->setText(trUtf8("Partitioned table is the one which is splitted into smaller pieces (partitions). This table is where the partitioning strategy or type is defined.")); recv_table_lbl->setText(trUtf8("Partition Table:")); recv_table_ht->setText(trUtf8("Partition table is the one attached to a partitioned table in which operations over data will be routed (according to the paritionig rule) when trying to handle the partitioned table.")); ref_table_txt->setPlainText(aux_rel->getReferenceTable()->getName(true)); recv_table_txt->setPlainText(aux_rel->getReceiverTable()->getName(true)); } else if(rel_type!=BaseRelationship::RelationshipNn) { ref_table_lbl->setText(trUtf8("Reference Table:")); ref_table_ht->setText(trUtf8("Reference table has the columns from its primary key will copied to the receiver table in order to represent the linking between them. This is the (1) side of relationship.")); recv_table_lbl->setText(trUtf8("Receiver Table:")); recv_table_ht->setText(trUtf8("Receiver (or referer) table will receive the generated columns and the foreign key in order to represent the linking between them. This is the (n) side of relationship.")); ref_table_txt->setPlainText(aux_rel->getReferenceTable()->getName(true)); recv_table_txt->setPlainText(aux_rel->getReceiverTable()->getName(true)); } else { ref_table_lbl->setText(trUtf8("Reference Table:")); ref_table_ht->setText(trUtf8("In many-to-many relationships both tables are used as reference to generate the table that represents the linking. Columns from both tables are copied to the resultant table and two foreign keys are created as well in order to reference each participant table.")); recv_table_lbl->setText(trUtf8("Reference Table:")); recv_table_ht->setText(ref_table_ht->getText()); ref_table_txt->setPlainText(base_rel->getTable(BaseRelationship::SrcTable)->getName(true)); recv_table_txt->setPlainText(base_rel->getTable(BaseRelationship::DstTable)->getName(true)); } if(rel_type == BaseRelationship::RelationshipPart) { part_type_lbl->setText(~aux_rel->getReferenceTable()->getPartitioningType()); // Default partitions can't be used by foreign tables default_part_chk->setChecked(!has_foreign_tab && aux_rel->getPartitionBoundingExpr().isEmpty()); default_part_chk->setEnabled(!has_foreign_tab); } } disable_sql_chk->setVisible(base_rel->getObjectType()==ObjectType::Relationship); table1_mand_chk->setText(base_rel->getTable(BaseRelationship::SrcTable)->getName() + trUtf8(" is required")); table2_mand_chk->setText(base_rel->getTable(BaseRelationship::DstTable)->getName() + trUtf8(" is required")); if(aux_rel) { single_pk_chk->setChecked(aux_rel->isSiglePKColumn()); table1_mand_chk->setChecked(aux_rel->isTableMandatory(BaseRelationship::SrcTable)); table2_mand_chk->setChecked(aux_rel->isTableMandatory(BaseRelationship::DstTable)); identifier_chk->setChecked(aux_rel->isIdentifier()); relnn_tab_name_edt->setText(aux_rel->getTableNameRelNN()); attributes_tab->setButtonsEnabled(ObjectsTableWidget::AllButtons, !aux_rel->isProtected()); constraints_tab->setButtonsEnabled(ObjectsTableWidget::AllButtons, !aux_rel->isProtected()); //Lists the relationship attributes listObjects(ObjectType::Column); //Lists the relationship constraints listObjects(ObjectType::Constraint); listSpecialPkColumns(); if(rel_type!=BaseRelationship::RelationshipNn) { if(rel_type==BaseRelationship::RelationshipDep) { CopyOptions copy_op=aux_rel->getCopyOptions(); including_rb->setChecked(copy_op.isIncluding()); excluding_rb->setChecked(copy_op.isExcluding()); all_chk->setChecked(copy_op.isOptionSet(CopyOptions::All)); defaults_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Defaults)); constraints_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Constraints)); storage_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Storage)); comments_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Comments)); indexes_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Indexes)); identity_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Identity)); statistics_chk->setChecked(!all_chk->isChecked() && copy_op.isOptionSet(CopyOptions::Statistics)); } else if(rel_type == BaseRelationship::RelationshipPart) { if(this->new_object) generateBoundingExpr(); else part_bound_expr_txt->setPlainText(aux_rel->getPartitionBoundingExpr()); } } } rel1n=(rel_type==BaseRelationship::Relationship11 || rel_type==BaseRelationship::Relationship1n); relnn=(rel_type==BaseRelationship::RelationshipNn); relgen_dep=(rel_type==BaseRelationship::RelationshipDep || rel_type==BaseRelationship::RelationshipGen || rel_type==BaseRelationship::RelationshipPart || rel_type==BaseRelationship::RelationshipFk); use_name_patterns=(rel1n || relnn || (relgen_dep && base_rel->getObjectType()==ObjectType::Relationship)); name_patterns_grp->setVisible(use_name_patterns); dst_col_pattern_txt->setEnabled(relnn); dst_fk_pattern_txt->setEnabled(relnn); dst_col_pattern_lbl->setEnabled(relnn); dst_fk_pattern_lbl->setEnabled(relnn); src_col_pattern_lbl->setEnabled(!relgen_dep); src_col_pattern_txt->setEnabled(!relgen_dep); src_fk_pattern_lbl->setEnabled(!relgen_dep); src_fk_pattern_txt->setEnabled(!relgen_dep); uq_pattern_lbl->setEnabled(!relgen_dep); uq_pattern_txt->setEnabled(!relgen_dep); pk_col_pattern_lbl->setEnabled(relnn); pk_col_pattern_txt->setEnabled(relnn); card_lbl->setVisible(rel1n); table1_mand_chk->setEnabled(rel1n); table1_mand_chk->setVisible(rel1n); table2_mand_chk->setEnabled(rel_type==BaseRelationship::Relationship11); table2_mand_chk->setVisible(rel1n); identifier_wgt->setVisible(rel1n && !base_rel->isSelfRelationship()); foreign_key_gb->setVisible(rel1n || relnn); single_pk_wgt->setVisible(relnn); relnn_tab_name_lbl->setVisible(relnn); relnn_tab_name_edt->setVisible(relnn); gen_tab_name_hint->setVisible(relnn); part_bound_expr_gb->setVisible(rel_type==BaseRelationship::RelationshipPart); for(i=SettingsTab; i <= AdvancedTab; i++) rel_attribs_tbw->removeTab(1); if(!relgen_dep) { for(i=SettingsTab; i <= SpecialPkTab; i++) rel_attribs_tbw->addTab(tabs[i], tab_labels[i]); } else if(relgen_dep && base_rel->getObjectType()==ObjectType::Relationship && !has_foreign_tab) rel_attribs_tbw->addTab(tabs[SpecialPkTab], tab_labels[SpecialPkTab]); if(base_rel->getObjectType()==ObjectType::Relationship || (base_rel->getObjectType()==ObjectType::BaseRelationship && base_rel->getRelationshipType()==BaseRelationship::RelationshipFk)) rel_attribs_tbw->addTab(tabs[AdvancedTab], tab_labels[AdvancedTab]); copy_options_grp->setVisible(base_rel->getObjectType()==ObjectType::Relationship && base_rel->getRelationshipType()==BaseRelationship::RelationshipDep); custom_color_chk->setChecked(base_rel->getCustomColor()!=Qt::transparent); color_picker->setColor(0, base_rel->getCustomColor()); listAdvancedObjects(); if(rel1n || relnn) { fk_gconf_chk->blockSignals(true); fk_gconf_chk->setChecked(this->new_object); useFKGlobalSettings(this->new_object); fk_gconf_chk->blockSignals(false); } if(use_name_patterns) { patterns_gconf_chk->blockSignals(true); patterns_gconf_chk->setChecked(this->new_object); usePatternGlobalSettings(this->new_object); patterns_gconf_chk->blockSignals(false); } } QSize RelationshipWidget::getIdealSize(void) { unsigned rel_type = 0; if(this->object) rel_type = dynamic_cast(this->object)->getRelationshipType(); if(rel_type == BaseRelationship::RelationshipFk || (BaseRelationship::RelationshipDep && this->object && this->object->getObjectType()==ObjectType::BaseRelationship)) return(QSize(640, 320)); else if(BaseRelationship::RelationshipGen) return(QSize(640, 520)); else return(QSize(640, 680)); } void RelationshipWidget::useFKGlobalSettings(bool value) { fk_wgt->setEnabled(!value); if(value) { map confs=RelationshipConfigWidget::getConfigurationParams(); deferrable_chk->setChecked(confs[Attributes::ForeignKeys][Attributes::Deferrable]==Attributes::True); deferral_cmb->setCurrentText(confs[Attributes::ForeignKeys][Attributes::DeferType]); upd_action_cmb->setCurrentText(confs[Attributes::ForeignKeys][Attributes::UpdAction]); del_action_cmb->setCurrentText(confs[Attributes::ForeignKeys][Attributes::DelAction]); } else { Relationship *rel=dynamic_cast(this->object); int idx=-1; //Using the settings of the relatinship itself if(rel) { deferrable_chk->setChecked(rel->isDeferrable()); idx=deferral_cmb->findText(~rel->getDeferralType()); deferral_cmb->setCurrentIndex(idx < 0 ? 0 : idx); idx=del_action_cmb->findText(~rel->getActionType(Constraint::DeleteAction)); del_action_cmb->setCurrentIndex(idx < 0 ? 0 : idx); idx=upd_action_cmb->findText(~rel->getActionType(Constraint::UpdateAction)); upd_action_cmb->setCurrentIndex(idx < 0 ? 0 : idx); } } } void RelationshipWidget::usePatternGlobalSettings(bool value) { Relationship *rel=dynamic_cast(this->object); patterns_wgt->setEnabled(!value); if(rel) { if(value) { map confs=RelationshipConfigWidget::getConfigurationParams(); QString rel_type=rel->getRelTypeAttribute(); //Using the global settings pk_pattern_txt->setPlainText(confs[rel_type][Attributes::PkPattern]); src_fk_pattern_txt->setPlainText(confs[rel_type][Attributes::SrcFkPattern]); dst_fk_pattern_txt->setPlainText(confs[rel_type][Attributes::DstFkPattern]); uq_pattern_txt->setPlainText(confs[rel_type][Attributes::UqPattern]); src_col_pattern_txt->setPlainText(confs[rel_type][Attributes::SrcColPattern]); dst_col_pattern_txt->setPlainText(confs[rel_type][Attributes::DstColPattern]); pk_col_pattern_txt->setPlainText(confs[rel_type][Attributes::PkColPattern]); } else { //Using the settings of the relatinship itself pk_pattern_txt->setPlainText(rel->getNamePattern(Relationship::PkPattern)); src_fk_pattern_txt->setPlainText(rel->getNamePattern(Relationship::SrcFkPattern)); dst_fk_pattern_txt->setPlainText(rel->getNamePattern(Relationship::DstFkPattern)); uq_pattern_txt->setPlainText(rel->getNamePattern(Relationship::UqPattern)); src_col_pattern_txt->setPlainText(rel->getNamePattern(Relationship::SrcColPattern)); dst_col_pattern_txt->setPlainText(rel->getNamePattern(Relationship::DstColPattern)); pk_col_pattern_txt->setPlainText(rel->getNamePattern(Relationship::PkColPattern)); } } } void RelationshipWidget::generateBoundingExpr(void) { PartitioningType part_type = part_type_lbl->text(); QString tmpl; if(part_type == PartitioningType::List) tmpl = QString("IN (value)"); else if(part_type == PartitioningType::Range) tmpl = QString("FROM (value) TO (value)"); else tmpl = QString("WITH (MODULUS m, REMAINDER r)"); part_bound_expr_txt->setPlainText(QString()); part_bound_expr_txt->setPlainText(tmpl); default_part_chk->setChecked(false); } void RelationshipWidget::listObjects(ObjectType obj_type) { ObjectsTableWidget *tab=nullptr; Relationship *rel=nullptr; unsigned count, i; try { if(obj_type==ObjectType::Column) tab=attributes_tab; else tab=constraints_tab; rel=dynamic_cast(this->object); tab->blockSignals(true); tab->removeRows(); count=rel->getObjectCount(obj_type); for(i=0; i < count; i++) { tab->addRow(); showObjectData(rel->getObject(i, obj_type), i); } tab->clearSelection(); tab->blockSignals(false); constraints_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, attributes_tab->getRowCount() > 0); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::listAdvancedObjects(void) { BaseRelationship *base_rel=nullptr; Relationship *rel=nullptr; Table *tab=nullptr; vector cols; vector constrs; unsigned count=0, i,i1; try { base_rel=dynamic_cast(this->object); rel=dynamic_cast(base_rel); advanced_objs_tab->blockSignals(true); advanced_objs_tab->removeRows(); if(rel) { if(rel->getRelationshipType()!=BaseRelationship::RelationshipNn) { cols=rel->getGeneratedColumns(); count=cols.size(); for(i=0; i < count; i++) { advanced_objs_tab->addRow(); advanced_objs_tab->setCellText(cols[i]->getName(),i,0); advanced_objs_tab->setCellText(cols[i]->getTypeName(),i,1); advanced_objs_tab->setRowData(QVariant::fromValue(dynamic_cast(cols[i])), i); } constrs=rel->getGeneratedConstraints(); count=constrs.size(); for(i=0, i1=advanced_objs_tab->getRowCount(); i < count; i++,i1++) { advanced_objs_tab->addRow(); advanced_objs_tab->setCellText(constrs[i]->getName(),i1,0); advanced_objs_tab->setCellText(constrs[i]->getTypeName(),i1,1); advanced_objs_tab->setRowData(QVariant::fromValue(dynamic_cast(constrs[i])), i1); } } else { tab=rel->getGeneratedTable(); if(tab) { advanced_objs_tab->addRow(); advanced_objs_tab->setCellText(tab->getName(),0,0); advanced_objs_tab->setCellText(tab->getTypeName(),0,1); advanced_objs_tab->setRowData(QVariant::fromValue(dynamic_cast(tab)), 0); } } } else if(base_rel->getRelationshipType()==BaseRelationship::RelationshipFk) { Constraint *fk = base_rel->getReferenceForeignKey(); if(fk) { int row = 0; advanced_objs_tab->addRow(); row = advanced_objs_tab->getRowCount() - 1; advanced_objs_tab->setCellText(fk->getName(), row ,0); advanced_objs_tab->setCellText(fk->getTypeName(), row, 1); advanced_objs_tab->setRowData(QVariant::fromValue(fk), row); } } advanced_objs_tab->clearSelection(); advanced_objs_tab->blockSignals(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::showAdvancedObject(int row) { BaseObject *object=reinterpret_cast(advanced_objs_tab->getRowData(row).value()); Table *tab=nullptr; Constraint *constr=nullptr; Column *col=nullptr; ObjectType obj_type=object->getObjectType(); bool is_protected = false; if(obj_type==ObjectType::Column) { col=dynamic_cast(object); is_protected = col->isProtected(); openEditingForm(col, col->getParentTable()); } else if(obj_type==ObjectType::Constraint) { constr=dynamic_cast(object); if(!constr->isAddedByRelationship()) { is_protected = constr->isProtected(); constr->setProtected(true); } openEditingForm(constr, constr->getParentTable()); if(!constr->isAddedByRelationship()) constr->setProtected(is_protected); } else { TableWidget *table_wgt=new TableWidget; BaseForm editing_form(this); tab=dynamic_cast
(object); tab->setProtected(true); table_wgt->setAttributes(this->model, this->op_list, dynamic_cast(tab->getSchema()), tab, tab->getPosition().x(), tab->getPosition().y()); editing_form.setMainWidget(table_wgt); GeneralConfigWidget::restoreWidgetGeometry(&editing_form, table_wgt->metaObject()->className()); editing_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&editing_form, table_wgt->metaObject()->className()); tab->setProtected(false); } } template int RelationshipWidget::openEditingForm(TableObject *object, BaseObject *parent) { BaseForm editing_form(this); WidgetClass *object_wgt=new WidgetClass; BaseObject *parent_aux = nullptr; int res = 0; if(this->object->getObjectType() == ObjectType::BaseRelationship) parent_aux = dynamic_cast(this->object)->getTable(BaseRelationship::SrcTable); else parent_aux = !parent ? this->object : parent; object_wgt->setAttributes(this->model, this->op_list, parent_aux, dynamic_cast(object)); editing_form.setMainWidget(object_wgt); GeneralConfigWidget::restoreWidgetGeometry(&editing_form, object_wgt->metaObject()->className()); res = editing_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&editing_form, object_wgt->metaObject()->className()); return(res); } void RelationshipWidget::addObject(void) { ObjectType obj_type=ObjectType::BaseObject; try { if(sender()==attributes_tab) { obj_type=ObjectType::Column; tab=attributes_tab; } else { obj_type=ObjectType::Constraint; tab=constraints_tab; } if(obj_type==ObjectType::Column) openEditingForm(nullptr); else openEditingForm(nullptr); listObjects(obj_type); } catch(Exception &e) { listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::duplicateObject(int curr_row, int new_row) { ObjectType obj_type=ObjectType::BaseObject; BaseObject *object = nullptr, *dup_object = nullptr; Relationship *rel = dynamic_cast(this->object); vector obj_list; ObjectsTableWidget *tab = nullptr; int op_id = -1; if(!rel) return; try { if(sender()==attributes_tab) { obj_type=ObjectType::Column; tab=attributes_tab; obj_list = rel->getAttributes(); } else { obj_type=ObjectType::Constraint; tab=constraints_tab; obj_list = rel->getConstraints(); } //Gets the object reference if there is an item select on table if(curr_row >= 0) object = reinterpret_cast(tab->getRowData(curr_row).value()); PgModelerNs::copyObject(&dup_object, object, obj_type); dup_object->setName(PgModelerNs::generateUniqueName(dup_object, obj_list, false, QString("_cp"))); op_id=op_list->registerObject(dup_object, Operation::ObjectCreated, new_row, rel); rel->addObject(dynamic_cast(dup_object)); listObjects(obj_type); } catch(Exception &e) { //If operation was registered if(op_id >= 0) { op_list->ignoreOperationChain(true); op_list->removeLastOperation(); op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::editObject(int row) { ObjectType obj_type=ObjectType::Column; TableObject *tab_obj=nullptr; try { op_list->ignoreOperationChain(true); if(sender()==attributes_tab) { obj_type=ObjectType::Column; tab_obj=reinterpret_cast(attributes_tab->getRowData(row).value()); openEditingForm(tab_obj); } else { obj_type=ObjectType::Constraint; tab_obj=reinterpret_cast(constraints_tab->getRowData(row).value()); openEditingForm(tab_obj); } listObjects(obj_type); op_list->ignoreOperationChain(false); } catch(Exception &e) { listObjects(obj_type); op_list->ignoreOperationChain(false); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::showObjectData(TableObject *object, int row) { ObjectsTableWidget *tab=nullptr; if(object->getObjectType()==ObjectType::Column) { tab=attributes_tab; attributes_tab->setCellText(*dynamic_cast(object)->getType(),row,1); } else { tab=constraints_tab; constraints_tab->setCellText(~dynamic_cast(object)->getConstraintType(),row,1); } tab->setCellText(object->getName(),row,0); tab->setRowData(QVariant::fromValue(object), row); } void RelationshipWidget::removeObjects(void) { Relationship *rel=nullptr; ObjectType obj_type=ObjectType::BaseObject; unsigned count, op_count=0, i; TableObject *object=nullptr; try { rel=dynamic_cast(this->object); if(sender()==attributes_tab) { obj_type=ObjectType::Column; count=rel->getAttributeCount(); } else { obj_type=ObjectType::Constraint; count=rel->getConstraintCount(); } op_count=op_list->getCurrentSize(); for(i=0; i < count; i++) { object=rel->getObject(0, obj_type); op_list->registerObject(object, Operation::ObjectRemoved, 0, rel); rel->removeObject(object); } if(obj_type==ObjectType::Column) listSpecialPkColumns(); } catch(Exception &e) { if(op_count < op_list->getCurrentSize()) { count=op_list->getCurrentSize()-op_count; op_list->ignoreOperationChain(true); for(i=0; i < count; i++) { op_list->undoOperation(); op_list->removeLastOperation(); } op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::removeObject(int row) { Relationship *rel=nullptr; ObjectType obj_type=ObjectType::BaseObject; TableObject *object=nullptr; int op_id=-1; try { rel=dynamic_cast(this->object); if(sender()==attributes_tab) obj_type=ObjectType::Column; else obj_type=ObjectType::Constraint; object=rel->getObject(row, obj_type); op_id=op_list->registerObject(object, Operation::ObjectRemoved, 0, rel); rel->removeObject(object); if(obj_type==ObjectType::Column) listSpecialPkColumns(); } catch(Exception &e) { //If operation was registered if(op_id >= 0) { op_list->ignoreOperationChain(true); op_list->removeLastOperation(); op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::selectCopyOptions(void) { all_chk->setEnabled(!defaults_rb->isChecked()); defaults_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); constraints_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); storage_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); comments_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); indexes_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); identity_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); statistics_chk->setEnabled(!all_chk->isChecked() && !defaults_rb->isChecked()); if(all_chk->isChecked() || defaults_rb->isChecked()) { if(defaults_rb->isChecked()) all_chk->setChecked(false); defaults_chk->setChecked(false); constraints_chk->setChecked(false); storage_chk->setChecked(false); comments_chk->setChecked(false); indexes_chk->setChecked(false); identity_chk->setChecked(false); statistics_chk->setChecked(false); } } void RelationshipWidget::listSpecialPkColumns(void) { Relationship *aux_rel=dynamic_cast(this->object); if(aux_rel) { vector cols; vector col_ids; int count, idx; QListWidgetItem *item=nullptr; rel_columns_lst->clear(); if(aux_rel->getRelationshipType()!=BaseRelationship::RelationshipNn) cols=aux_rel->getGeneratedColumns(); for(auto &attrib : aux_rel->getAttributes()) cols.push_back(dynamic_cast(attrib)); //Get the special primary key columns ids col_ids=aux_rel->getSpecialPrimaryKeyCols(); count=cols.size(); for(idx=0; idx < count; idx++) { rel_columns_lst->addItem(cols[idx]->getName().toUtf8() + QString(" (") + *cols[idx]->getType() + QString(")")); item=rel_columns_lst->item(idx); item->setCheckState(Qt::Unchecked); } count=col_ids.size(); for(idx=0; idx < count; idx++) { if(col_ids[idx] < static_cast(rel_columns_lst->count())) rel_columns_lst->item(col_ids[idx])->setCheckState(Qt::Checked); } } } void RelationshipWidget::applyConfiguration(void) { try { Relationship *rel=nullptr; BaseRelationship *base_rel=dynamic_cast(this->object); unsigned rel_type, count, i, copy_mode=0, copy_ops=0; vector col_ids; /* Due to the complexity of the Relationship class and the strong link between all the relationships on the model is necessary to store the XML of the special objects and disconnect all relationships, edit the relationshi and revalidate all the relationships again */ if(this->object->getObjectType()==ObjectType::Relationship) { model->storeSpecialObjectsXML(); model->disconnectRelationships(); } if(!this->new_object && this->object->getObjectType()==ObjectType::Relationship) op_list->registerObject(this->object, Operation::ObjectModified); else registerNewObject(); BaseObjectWidget::applyConfiguration(); if(custom_color_chk->isChecked()) base_rel->setCustomColor(color_picker->getColor(0)); else base_rel->setCustomColor(Qt::transparent); if(this->object->getObjectType()==ObjectType::Relationship) { QPlainTextEdit *pattern_fields[]={ src_col_pattern_txt, dst_col_pattern_txt, src_fk_pattern_txt, dst_fk_pattern_txt, pk_pattern_txt, uq_pattern_txt, pk_col_pattern_txt }; unsigned pattern_ids[]= { Relationship::SrcColPattern, Relationship::DstColPattern, Relationship::SrcFkPattern, Relationship::DstFkPattern, Relationship::PkPattern, Relationship::UqPattern, Relationship::PkColPattern }; rel=dynamic_cast(base_rel); if(name_patterns_grp->isVisible()) { count=sizeof(pattern_ids)/sizeof(unsigned); for(i=0; i < count; i++) rel->setNamePattern(pattern_ids[i], pattern_fields[i]->toPlainText()); } rel_type=rel->getRelationshipType(); rel->blockSignals(true); rel->setPartitionBoundingExpr(default_part_chk->isChecked() ? QString() : part_bound_expr_txt->toPlainText()); if(!defaults_rb->isChecked()) { if(including_rb->isChecked()) copy_mode=CopyOptions::Including; else copy_mode=CopyOptions::Excluding; copy_ops+=(all_chk->isChecked() ? CopyOptions::All : 0); copy_ops+=(defaults_chk->isChecked() ? CopyOptions::Defaults : 0); copy_ops+=(constraints_chk->isChecked() ? CopyOptions::Constraints : 0); copy_ops+=(comments_chk->isChecked() ? CopyOptions::Comments : 0); copy_ops+=(indexes_chk->isChecked() ? CopyOptions::Indexes : 0); copy_ops+=(storage_chk->isChecked() ? CopyOptions::Storage : 0); copy_ops+=(identity_chk->isChecked() ? CopyOptions::Identity : 0); copy_ops+=(statistics_chk->isChecked() ? CopyOptions::Statistics : 0); } rel->setCopyOptions(CopyOptions(copy_mode, copy_ops)); rel->setMandatoryTable(BaseRelationship::SrcTable, false); rel->setMandatoryTable(BaseRelationship::DstTable, false); if(table1_mand_chk->isEnabled()) rel->setMandatoryTable(BaseRelationship::SrcTable, table1_mand_chk->isChecked()); if(table2_mand_chk->isEnabled()) rel->setMandatoryTable(BaseRelationship::DstTable, table2_mand_chk->isChecked()); if(rel_type==BaseRelationship::Relationship1n || rel_type==BaseRelationship::Relationship11) rel->setIdentifier(identifier_chk->isChecked()); else if(rel_type==BaseRelationship::RelationshipNn) rel->setTableNameRelNN(relnn_tab_name_edt->text()); if(rel_type==BaseRelationship::Relationship1n || rel_type==BaseRelationship::Relationship11 || rel_type==BaseRelationship::RelationshipNn) { rel->setDeferrable(deferrable_chk->isChecked()); rel->setDeferralType(DeferralType(deferral_cmb->currentText())); rel->setActionType((del_action_cmb->currentIndex()!=0 ? ActionType(del_action_cmb->currentText()) : ActionType::Null), Constraint::DeleteAction); rel->setActionType((upd_action_cmb->currentIndex()!=0 ? ActionType(upd_action_cmb->currentText()) : ActionType::Null), Constraint::UpdateAction); if(rel_type==BaseRelationship::RelationshipNn) rel->setSiglePKColumn(single_pk_chk->isChecked()); } count=rel_columns_lst->count(); for(i=0; i < count; i++) { if(rel_columns_lst->item(i)->checkState()==Qt::Checked) col_ids.push_back(i); } rel->setSpecialPrimaryKeyCols(col_ids); try { //Checking if there is relationship redundancy if(rel_type==BaseRelationship::RelationshipDep || rel_type==BaseRelationship::RelationshipGen || rel_type==BaseRelationship::RelationshipPart || rel->isIdentifier()) model->checkRelationshipRedundancy(rel); if(rel_type!=BaseRelationship::RelationshipFk) model->validateRelationships(); rel->blockSignals(false); } catch(Exception &e) { Messagebox msg_box; if(e.getErrorCode()==ErrorCode::RemInvalidatedObjects) msg_box.show(e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } op_list->finishOperationChain(); finishConfiguration(); } catch(Exception &e) { model->validateRelationships(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RelationshipWidget::cancelConfiguration(void) { BaseObjectWidget::cancelChainedOperation(); } pgmodeler-0.9.2/libpgmodeler_ui/src/relationshipwidget.h000066400000000000000000000070121360462764600235250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class RelationshipWidget \brief Implements the operations to create/edit relationships via form. */ #ifndef RELATIONSHIP_WIDGET_H #define RELATIONSHIP_WIDGET_H #include "baseobjectwidget.h" #include "ui_relationshipwidget.h" #include "objectstablewidget.h" #include "colorpickerwidget.h" #include "hinttextwidget.h" class RelationshipWidget: public BaseObjectWidget, public Ui::RelationshipWidget { private: Q_OBJECT static constexpr unsigned GeneralTab=0, SettingsTab=1, AttributesTab=2, ConstraintsTab=3, SpecialPkTab=4, AdvancedTab=5; HintTextWidget *gen_tab_name_ht, *ref_table_ht, *recv_table_ht, *identifier_ht, *single_pk_ht, *default_part_ht; ColorPickerWidget *color_picker; NumberedTextEditor *part_bound_expr_txt; //! \brief Stores the tab objects to change the configuration of the form depending on the type of the relationship QWidgetList tabs; //! \brief Stores the original labels of the tabs QStringList tab_labels; SyntaxHighlighter *table1_hl, *table2_hl, *patterns_hl[7], *part_bound_expr_hl; //! \brief Table widgets that stores the attributes, constraint and advanced objects of relationship ObjectsTableWidget *attributes_tab, *constraints_tab, *advanced_objs_tab; //! \brief Lists the objects of relationship (attributes/constraints) on the respective table widget void listObjects(ObjectType obj_type); //! \brief Lists the advanced objects in the repective table widget void listAdvancedObjects(void); /*! \brief Shows the object data in the specified table row. The table widget is idenfied by the current object type */ void showObjectData(TableObject *object, int row); /*! \brief Template method that opens the editing form for the specified object. Class and ClassWidget should be compatible, e.g., "Column" can only be edited using ColumnWidget */ template int openEditingForm(TableObject *object, BaseObject *parent = nullptr); protected: void setAttributes(DatabaseModel *model, OperationList *op_list, PhysicalTable *src_tab, PhysicalTable *dst_tab, unsigned rel_type); public: RelationshipWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseRelationship *base_rel); QSize getIdealSize(void); private slots: void addObject(void); void editObject(int row); void removeObject(int row); void removeObjects(void); void showAdvancedObject(int row); void selectCopyOptions(void); void listSpecialPkColumns(void); void duplicateObject(int curr_row, int new_row); void useFKGlobalSettings(bool value); void usePatternGlobalSettings(bool value); void generateBoundingExpr(void); public slots: void applyConfiguration(void); void cancelConfiguration(void); friend class ModelWidget; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/resultsetmodel.cpp000066400000000000000000000107021360462764600232260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "resultsetmodel.h" ResultSetModel::ResultSetModel(ResultSet &res, Catalog &catalog, QObject *parent) : QAbstractTableModel(parent) { try { Catalog aux_cat = catalog; vector type_ids; vector::iterator end; vector types; map type_names; int col = 0; col_count = res.getColumnCount(); row_count = res.getTupleCount(); insertColumns(0, col_count); insertRows(0, row_count); for(col=0; col < col_count; col++) { header_data.push_back(res.getColumnName(col)); type_ids.push_back(res.getColumnTypeId(col)); } if(res.accessTuple(ResultSet::FirstTuple)) { do { //Fills the current row with the values of current tuple for(int col=0; col < col_count; col++) { if(res.isColumnBinaryFormat(col)) item_data.push_back(trUtf8("[binary data]")); else item_data.push_back(res.getColumnValue(col)); } } while(res.accessTuple(ResultSet::NextTuple)); } aux_cat.setFilter(Catalog::ListAllObjects); std::sort(type_ids.begin(), type_ids.end()); end=std::unique(type_ids.begin(), type_ids.end()); type_ids.erase(end, type_ids.end()); types = aux_cat.getObjectsAttributes(ObjectType::Type, QString(), QString(), type_ids); col = 0; for(auto &tp : types) type_names[tp[Attributes::Oid].toInt()]=tp[Attributes::Name]; for(col=0; col < col_count; col++) tooltip_data.push_back(type_names[res.getColumnTypeId(col)]); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } int ResultSetModel::rowCount(const QModelIndex &) const { return(row_count); } int ResultSetModel::columnCount(const QModelIndex &) const { return(col_count); } QModelIndex ResultSetModel::index(int row, int column, const QModelIndex &parent) const { return(QAbstractTableModel::index(row, column, parent)); } QModelIndex ResultSetModel::parent(const QModelIndex &) const { return(QModelIndex()); } QVariant ResultSetModel::data(const QModelIndex &index, int role) const { if(index.row() < row_count && index.column() < col_count) { if(role == Qt::DisplayRole) return(item_data.at(index.row() * col_count + index.column())); if(role == Qt::TextAlignmentRole) return(QVariant(Qt::AlignLeft | Qt::AlignVCenter)); } return(QVariant(QVariant::Invalid)); } QVariant ResultSetModel::headerData(int section, Qt::Orientation orientation, int role) const { if(orientation == Qt::Horizontal) { if(section >= col_count) return(QVariant(QVariant::Invalid)); if(role == Qt::DisplayRole) return(header_data.at(section)); if(role == Qt::ToolTipRole) return(tooltip_data.at(section)); if(role == Qt::TextAlignmentRole) return(QVariant(Qt::AlignLeft | Qt::AlignVCenter)); } return(QAbstractTableModel::headerData(section, orientation, role)); } Qt::ItemFlags ResultSetModel::flags(const QModelIndex &) const { return(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled ); } void ResultSetModel::append(ResultSet &res) { try { if(res.isValid() && !res.isEmpty()) { if(res.accessTuple(ResultSet::FirstTuple)) { do { for(int col=0; col < col_count; col++) { if(col < res.getColumnCount()) { if(res.isColumnBinaryFormat(col)) item_data.push_back(trUtf8("[binary data]")); else item_data.push_back(res.getColumnValue(col)); } else { item_data.push_back(QString()); } } } while(res.accessTuple(ResultSet::NextTuple)); } row_count += res.getTupleCount(); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } bool ResultSetModel::isEmpty(void) { return(row_count <= 0); } pgmodeler-0.9.2/libpgmodeler_ui/src/resultsetmodel.h000066400000000000000000000035751360462764600227050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ResultSetModel \brief Implements a model representation of ResultSet class which can be used to show large amount of data in instances of QTableView. */ #ifndef RESULT_SET_MODEL_H #define RESULT_SET_MODEL_H #include #include "resultset.h" #include "catalog.h" class ResultSetModel: public QAbstractTableModel { private: Q_OBJECT int col_count, row_count; QStringList item_data, header_data, tooltip_data; void insertColumn(int, const QModelIndex &){} void insertRow(int, const QModelIndex &){} public: ResultSetModel(ResultSet &res, Catalog &catalog, QObject *parent = 0); virtual int rowCount(const QModelIndex & = QModelIndex()) const; virtual int columnCount(const QModelIndex &) const; virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; virtual QModelIndex parent(const QModelIndex &) const; virtual QVariant data(const QModelIndex &index, int role) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; virtual Qt::ItemFlags flags(const QModelIndex &) const; void append(ResultSet &res); bool isEmpty(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/rolewidget.cpp000066400000000000000000000234741360462764600223320ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "rolewidget.h" #include "modelobjectswidget.h" RoleWidget::RoleWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Role) { ObjectsTableWidget *obj_tab=nullptr; QGridLayout *grid=nullptr; QFrame *frame=nullptr; map > fields_map; unsigned i; Ui_RoleWidget::setupUi(this); configureFormLayout(role_grid, ObjectType::Role); object_selection_wgt=new ModelObjectsWidget(true); frame=generateInformationFrame(trUtf8("Assigning -1 to Connections creates a role without connection limit.
\ Unchecking Validity creates an role that never expires.")); role_grid->addWidget(frame, role_grid->count()+1, 0, 1, 4); frame->setParent(this); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion91)].push_back(can_replicate_chk); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(bypass_rls_chk); frame=generateVersionWarningFrame(fields_map); role_grid->addWidget(frame, role_grid->count()+1, 0, 1, 0); frame->setParent(this); connect(validity_chk, SIGNAL(toggled(bool)), validity_dte, SLOT(setEnabled(bool))); connect(members_twg, SIGNAL(currentChanged(int)), this, SLOT(configureRoleSelection(void))); //Alocation of the member role tables for(i=0; i < 3; i++) { obj_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton | ObjectsTableWidget::DuplicateButton), true, this); members_tab[i]=obj_tab; obj_tab->setColumnCount(5); obj_tab->setHeaderLabel(trUtf8("Role"),0); obj_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("role")),0); obj_tab->setHeaderLabel(trUtf8("Validity"),1); obj_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("validade")),1); obj_tab->setHeaderLabel(trUtf8("Member of"),2); obj_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("role")),2); obj_tab->setHeaderLabel(trUtf8("Members"),3); obj_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("role")),3); obj_tab->setHeaderLabel(trUtf8("Members (Admin.)"),4); obj_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("role")),4); grid=new QGridLayout; grid->addWidget(obj_tab,0,0,1,1); grid->setContentsMargins(4,4,4,4); members_twg->widget(i)->setLayout(grid); } connect(object_selection_wgt, SIGNAL(s_visibilityChanged(BaseObject*,bool)), this, SLOT(showSelectedRoleData(void))); setMinimumSize(580, 550); } RoleWidget::~RoleWidget() { delete(object_selection_wgt); } void RoleWidget::configureRoleSelection(void) { unsigned i; //Disconnects all signals from the member role tables for(i=0; i < 3; i++) disconnect(members_tab[i], nullptr,this, nullptr); //Connects the signal/slots only on the current table connect(members_tab[members_twg->currentIndex()], SIGNAL(s_rowAdded(int)), this, SLOT(selectMemberRole(void))); connect(members_tab[members_twg->currentIndex()], SIGNAL(s_rowEdited(int)), this, SLOT(selectMemberRole(void))); } void RoleWidget::selectMemberRole(void) { object_selection_wgt->setObjectVisible(ObjectType::Role, true); object_selection_wgt->setModel(this->model); object_selection_wgt->show(); } void RoleWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Role *role) { if(role) { conn_limit_sb->setValue(role->getConnectionLimit()); passwd_edt->setText(role->getPassword()); validity_chk->setChecked(!role->getValidity().isEmpty()); validity_dte->setDateTime(QDateTime::fromString(role->getValidity(), QString("yyyy-MM-dd hh:mm:ss"))); superusr_chk->setChecked(role->getOption(Role::OpSuperuser)); create_db_chk->setChecked(role->getOption(Role::OpCreateDb)); create_role_chk->setChecked(role->getOption(Role::OpCreateRole)); encrypt_pass_chk->setChecked(role->getOption(Role::OpEncrypted)); inh_perm_chk->setChecked(role->getOption(Role::OpInherit)); can_login_chk->setChecked(role->getOption(Role::OpLogin)); can_replicate_chk->setChecked(role->getOption(Role::OpReplication)); bypass_rls_chk->setChecked(role->getOption(Role::OpBypassRls)); } BaseObjectWidget::setAttributes(model, op_list, role); fillMembersTable(); configureRoleSelection(); } void RoleWidget::showRoleData(Role *role, unsigned table_id, unsigned row) { if(role) { QString str_aux; Role *aux_role=nullptr; unsigned count, i, type_id, role_types[3]={ Role::RefRole, Role::MemberRole, Role::AdminRole }; if(table_id > 3) throw Exception(ErrorCode::RefObjectInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__); members_tab[table_id]->setRowData(QVariant::fromValue(reinterpret_cast(role)), row); members_tab[table_id]->setCellText(role->getName(), row, 0); members_tab[table_id]->setCellText(role->getValidity(), row, 1); for(type_id=0; type_id < 3; type_id++) { count=role->getRoleCount(role_types[type_id]); for(i=0; i < count; i++) { aux_role=role->getRole(role_types[type_id], i); str_aux+=aux_role->getName(); if(i < count-1) str_aux+=QString(", "); } members_tab[table_id]->setCellText(str_aux, row, 2 + type_id); str_aux.clear(); } } } void RoleWidget::fillMembersTable(void) { if(this->object) { Role *aux_role=nullptr, *role=nullptr; unsigned count, i, type_id, role_types[3]={ Role::RefRole, Role::MemberRole, Role::AdminRole }; role=dynamic_cast(this->object); for(type_id=0; type_id < 3; type_id++) { count=role->getRoleCount(role_types[type_id]); members_tab[type_id]->blockSignals(true); for(i=0; i < count; i++) { aux_role=role->getRole(role_types[type_id], i); members_tab[type_id]->addRow(); showRoleData(aux_role, type_id, i); } members_tab[type_id]->blockSignals(false); members_tab[type_id]->clearSelection(); } } } void RoleWidget::showSelectedRoleData(void) { unsigned idx_tab; int lin, idx_lin=-1; BaseObject *obj_sel=nullptr; Messagebox msg_box; //Get the selected role obj_sel=object_selection_wgt->getSelectedObject(); //Gets the index of the table where the role data is displayed idx_tab=members_twg->currentIndex(); lin=members_tab[idx_tab]->getSelectedRow(); if(obj_sel) idx_lin=members_tab[idx_tab]->getRowIndex(QVariant::fromValue(dynamic_cast(obj_sel))); //Raises an error if the user try to assign the role as member of itself if(obj_sel && obj_sel==this->object) { /* If the current row does not has a value indicates that it is recently added and does not have data, in this case it will be removed */ if(!members_tab[idx_tab]->getRowData(lin).value()) members_tab[idx_tab]->removeRow(lin); msg_box.show(Exception(Exception::getErrorMessage(ErrorCode::AsgRoleReferenceRedundancy) .arg(obj_sel->getName()) .arg(name_edt->text()), ErrorCode::AsgRoleReferenceRedundancy,__PRETTY_FUNCTION__,__FILE__,__LINE__)); } //If the role does not exist on table, show its data else if(obj_sel && idx_lin < 0) showRoleData(dynamic_cast(obj_sel), idx_tab, lin); else { /* If the current row does not has a value indicates that it is recently added and does not have data, in this case it will be removed */ if(!members_tab[idx_tab]->getRowData(lin).value()) members_tab[idx_tab]->removeRow(lin); //Raises an error if the role already is in the table if(obj_sel && idx_lin >= 0) { msg_box.show( Exception(Exception::getErrorMessage(ErrorCode::InsDuplicatedRole) .arg(obj_sel->getName()) .arg(name_edt->text()), ErrorCode::InsDuplicatedRole,__PRETTY_FUNCTION__,__FILE__,__LINE__)); } } } void RoleWidget::applyConfiguration(void) { Role *role=nullptr, *aux_role=nullptr; unsigned count, i, type_id, role_types[3]={ Role::RefRole, Role::MemberRole, Role::AdminRole }; try { startConfiguration(); role=dynamic_cast(this->object); role->setConnectionLimit(conn_limit_sb->value()); role->setPassword(passwd_edt->text()); if(validity_chk->isChecked()) role->setValidity(validity_dte->dateTime().toString(QString("yyyy-MM-dd hh:mm"))); else role->setValidity(QString()); role->setOption(Role::OpSuperuser, superusr_chk->isChecked()); role->setOption(Role::OpCreateDb, create_db_chk->isChecked()); role->setOption(Role::OpCreateRole, create_role_chk->isChecked()); role->setOption(Role::OpEncrypted, encrypt_pass_chk->isChecked()); role->setOption(Role::OpInherit, inh_perm_chk->isChecked()); role->setOption(Role::OpLogin, can_login_chk->isChecked()); role->setOption(Role::OpReplication, can_replicate_chk->isChecked()); role->setOption(Role::OpBypassRls, bypass_rls_chk->isChecked()); for(type_id=0; type_id < 3; type_id++) { count = members_tab[type_id]->getRowCount(); role->removeRoles(role_types[type_id]); for(i=0; i < count; i++) { aux_role=reinterpret_cast(members_tab[type_id]->getRowData(i).value()); role->addRole(role_types[type_id], aux_role); } } BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/rolewidget.h000066400000000000000000000036621360462764600217740ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class RoleWidget \brief Implements the operations to create/edit roles via form. */ #ifndef ROLE_WIDGET_H #define ROLE_WIDGET_H #include "baseobjectwidget.h" #include "ui_rolewidget.h" #include "objectstablewidget.h" class RoleWidget: public BaseObjectWidget, public Ui::RoleWidget { private: Q_OBJECT //! \brief Widget used to select roles on the database model ModelObjectsWidget *object_selection_wgt; //! \brief Store the table widgets used to reference the member roles ObjectsTableWidget *members_tab[3]; //! \brief Fills the tables with to member roles of the editing role void fillMembersTable(void); //! \brief Show the specified role data on the specified table index at the specified row void showRoleData(Role *role, unsigned table_id, unsigned row); public: RoleWidget(QWidget * parent = nullptr); ~RoleWidget(void); void setAttributes(DatabaseModel *model, OperationList *op_list, Role *role); private slots: void showSelectedRoleData(void); void selectMemberRole(void); //! \brief Configures the signals/slots to each role table related to object selection void configureRoleSelection(void); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/rulewidget.cpp000066400000000000000000000105731360462764600223340ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "rulewidget.h" RuleWidget::RuleWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Rule) { try { QStringList list; QFrame *frame=nullptr; Ui_RuleWidget::setupUi(this); cond_expr_hl=new SyntaxHighlighter(cond_expr_txt, false, true); cond_expr_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); command_hl=new SyntaxHighlighter(comando_txt, false, true); command_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); command_cp=new CodeCompletionWidget(comando_txt); commands_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::DuplicateButton, true, this); commands_tab->setHeaderLabel(trUtf8("SQL command"),0); commands_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("codigosql")),0); dynamic_cast(commands_gb->layout())->addWidget(commands_tab, 1, 0, 1, 2); frame=generateInformationFrame(trUtf8("To create a rule that does not perform any action (DO NOTHING) simply do not specify commands in the SQL commands table.")); rule_grid->addWidget(frame, rule_grid->count()+1, 0, 1, 0); frame->setParent(this); configureFormLayout(rule_grid, ObjectType::Rule); EventType::getTypes(list); event_cmb->addItems(list); ExecutionType::getTypes(list); exec_type_cmb->addItems(list); connect(commands_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleCommand(int))); connect(commands_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleCommand(int))); connect(commands_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editCommand(int))); setRequiredField(event_lbl); configureTabOrder(); setMinimumSize(550, 500); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void RuleWidget::editCommand(int row) { comando_txt->setPlainText(commands_tab->getCellText(row,0)); } void RuleWidget::handleCommand(int row) { if(!comando_txt->toPlainText().isEmpty()) { commands_tab->setCellText(comando_txt->toPlainText(),row,0); comando_txt->clear(); } else if(commands_tab->getCellText(row,0).isEmpty()) commands_tab->removeRow(row); } void RuleWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseTable *parent_tab, Rule *rule) { unsigned qtd, i; if(!parent_tab) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, rule, parent_tab); command_cp->configureCompletion(model, command_hl); if(rule) { event_cmb->setCurrentIndex(event_cmb->findText(~rule->getEventType())); exec_type_cmb->setCurrentIndex(exec_type_cmb->findText(~rule->getExecutionType())); cond_expr_txt->setPlainText(rule->getConditionalExpression()); commands_tab->blockSignals(true); qtd=rule->getCommandCount(); for(i=0; i < qtd; i++) { commands_tab->addRow(); commands_tab->setCellText(rule->getCommand(i),i,0); } commands_tab->blockSignals(false); } } void RuleWidget::applyConfiguration(void) { try { Rule *rule=nullptr; unsigned count, i; startConfiguration(); rule=dynamic_cast(this->object); rule->setEventType(EventType(event_cmb->currentText())); rule->setExecutionType(ExecutionType(exec_type_cmb->currentText())); rule->setConditionalExpression(cond_expr_txt->toPlainText().toUtf8()); rule->removeCommands(); count=commands_tab->getRowCount(); for(i=0; i < count; i++) rule->addCommand(commands_tab->getCellText(i,0).toUtf8()); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/rulewidget.h000066400000000000000000000027541360462764600220030ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class RuleWidget \brief Implements the operations to create/edit rules via form. */ #ifndef RULE_WIDGET_H #define RULE_WIDGET_H #include "baseobjectwidget.h" #include "ui_rulewidget.h" #include "objectstablewidget.h" #include "codecompletionwidget.h" class RuleWidget: public BaseObjectWidget, public Ui::RuleWidget { private: Q_OBJECT SyntaxHighlighter *cond_expr_hl, *command_hl; CodeCompletionWidget *command_cp; ObjectsTableWidget *commands_tab; public: RuleWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseTable *parent_tab, Rule *rule); private slots: void handleCommand(int row); void editCommand(int row); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/sceneinfowidget.cpp000066400000000000000000000056511360462764600233370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sceneinfowidget.h" #include "pgmodeleruins.h" #include "relationshipview.h" SceneInfoWidget::SceneInfoWidget(QWidget *parent): QWidget(parent) { QFont font; setupUi(this); font = obj_name_lbl->font(); font.setPointSizeF(font.pointSizeF() * 0.90); obj_name_lbl->setFont(font); obj_pos_info_lbl->setFont(font); mouse_pos_info_lbl->setFont(font); } void SceneInfoWidget::updateSelectedObject(BaseObjectView *object) { if(!object) { obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("fechar1"))); obj_name_lbl->setText(trUtf8("No selection")); obj_pos_info_lbl->setText(trUtf8("N/A")); } else { RelationshipView *rel_view = dynamic_cast(object); QRectF rect = rel_view ? rel_view->__boundingRect() : QRectF(object->pos().x(), object->pos().y(), object->boundingRect().width(), object->boundingRect().height()); obj_icon_lbl->setPixmap(PgModelerUiNs::getIconPath(object->getUnderlyingObject()->getSchemaName())); obj_name_lbl->setText(QString("%1 (%2)").arg(object->getUnderlyingObject()->getSignature()).arg(object->getUnderlyingObject()->getTypeName())); obj_pos_info_lbl->setText(QString("(%1, %2) [w: %3, h: %4]") .arg(round(rect.left())) .arg(round(rect.top())) .arg(round(rect.width())) .arg(round(rect.height()))); } } void SceneInfoWidget::updateSelectedObjects(int obj_count, const QRectF &objs_rect) { QRect rect = objs_rect.toRect(); if(!rect.isValid()) rect = QRect(0,0,0,0); obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("seltodos"))); obj_name_lbl->setText(trUtf8("Sel. objects: %1").arg(obj_count)); obj_pos_info_lbl->setText(QString("(%1, %2) [w: %3, h: %4]") .arg(rect.left()) .arg(rect.top()) .arg(rect.size().width()) .arg(rect.size().height())); } void SceneInfoWidget::updateMousePosition(const QPointF &mouse_pos) { mouse_pos_info_lbl->setText(QString("%1, %2").arg(round(mouse_pos.x())).arg(round(mouse_pos.y()))); } void SceneInfoWidget::updateSceneZoom(double zoom) { zoom_info_lbl->setText(QString("%1%").arg(zoom * 100)); } pgmodeler-0.9.2/libpgmodeler_ui/src/sceneinfowidget.h000066400000000000000000000025331360462764600230000ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SceneInfoWidget \brief Implements an widget to show info about canvas (scene) and selected objects */ #ifndef SCENE_INFO_WIDGET_H #define SCENE_INFO_WIDGET_H #include "ui_sceneinfowidget.h" #include "baseobjectview.h" class SceneInfoWidget: public QWidget, public Ui::SceneInfoWidget { private: Q_OBJECT public: SceneInfoWidget(QWidget * parent = nullptr); public slots: void updateSelectedObject(BaseObjectView *object); void updateSelectedObjects(int obj_count, const QRectF &objs_rect); void updateMousePosition(const QPointF &mouse_pos); void updateSceneZoom(double zoom); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/schemawidget.cpp000066400000000000000000000052751360462764600226300ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "schemawidget.h" SchemaWidget::SchemaWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Schema) { Ui_SchemaWidget::setupUi(this); QHBoxLayout *hbox=nullptr; configureFormLayout(nullptr, ObjectType::Schema); color_picker=new ColorPickerWidget(1, this); hbox=new QHBoxLayout; hbox->setContentsMargins(2,0,0,0); hbox->addWidget(fill_color_lbl); hbox->addWidget(color_picker); hbox->addWidget(show_rect_chk); baseobject_grid->addLayout(hbox, baseobject_grid->count(), 0, 1, baseobject_grid->columnCount()); baseobject_grid->addItem(new QSpacerItem(1,1,QSizePolicy::Minimum,QSizePolicy::Expanding), baseobject_grid->count(), 0); configureTabOrder({ color_picker, show_rect_chk }); setMinimumSize(480, 140); } void SchemaWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema) { bool enable=false; BaseObjectWidget::setAttributes(model, op_list, schema); enable=!(schema && schema->isSystemObject()); edt_perms_tb->setEnabled(enable); name_edt->setEnabled(enable); comment_edt->setEnabled(enable); owner_sel->setEnabled(enable); disable_sql_chk->setEnabled(enable); append_sql_tb->setEnabled(enable); if(schema) { if(schema->isSystemObject()) protected_obj_frm->setVisible(false); color_picker->setColor(0, schema->getFillColor()); show_rect_chk->setChecked(schema && schema->isRectVisible()); } else color_picker->setColor(0, QColor(225,225,225)); } void SchemaWidget::applyConfiguration(void) { try { Schema *schema=nullptr; startConfiguration(); schema=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); schema->setRectVisible(show_rect_chk->isChecked()); schema->setFillColor(color_picker->getColor(0)); model->validateSchemaRenaming(dynamic_cast(this->object), this->prev_name); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/schemawidget.h000066400000000000000000000024401360462764600222640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SchemaWidget \brief Implements the operations to create/edit schemas via form. */ #ifndef SCHEMA_WIDGET_H #define SCHEMA_WIDGET_H #include "baseobjectwidget.h" #include "colorpickerwidget.h" #include "ui_schemawidget.h" class SchemaWidget: public BaseObjectWidget, public Ui::SchemaWidget { private: Q_OBJECT ColorPickerWidget *color_picker; public: SchemaWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/sequencewidget.cpp000066400000000000000000000112701360462764600231700ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sequencewidget.h" SequenceWidget::SequenceWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Sequence) { try { Ui_SequenceWidget::setupUi(this); column_sel=nullptr; column_sel=new ObjectSelectorWidget(ObjectType::Column, true, this); sequence_grid->addWidget(column_sel, 4, 1, 1, 3); configureFormLayout(sequence_grid, ObjectType::Sequence); sequence_grid->addItem(new QSpacerItem(10,0,QSizePolicy::Minimum,QSizePolicy::Expanding), sequence_grid->count(), 0); configureTabOrder(); def_values_cmb->addItem(trUtf8("User defined")); def_values_cmb->addItem(QString("smallserial")); def_values_cmb->addItem(QString("serial")); def_values_cmb->addItem(QString("bigserial")); setMinimumSize(520, 350); connect(def_values_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(setDefaultValues())); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SequenceWidget::setAttributesReadonly(DatabaseModel *model, OperationList *op_list, Schema *schema, Sequence *sequence, Column *column) { setAttributes(model, sequence); BaseObjectWidget::setAttributes(model, op_list, sequence, schema, DNaN, DNaN, false); name_edt->setReadOnly(true); comment_edt->setEnabled(false); schema_sel->setEnabled(false); append_sql_tb->setEnabled(false); edt_perms_tb->setEnabled(false); column_sel->setSelectedObject(column); column_sel->setEnabled(false); disable_sql_chk->setEnabled(false); owner_sel->setSelectedObject(column && column->getParentTable() ? column->getParentTable()->getOwner() : nullptr); owner_sel->setEnabled(false); } void SequenceWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Sequence *sequence) { setAttributes(model, sequence); BaseObjectWidget::setAttributes(model, op_list, sequence, schema); } void SequenceWidget::setAttributes(DatabaseModel *model, Sequence *sequence) { column_sel->setModel(model); if(sequence) { column_sel->setSelectedObject(sequence->getOwnerColumn()); cyclic_chk->setChecked(sequence->isCycle()); start_edt->setText(sequence->getStart()); maximum_edt->setText(sequence->getMaxValue()); minimum_edt->setText(sequence->getMinValue()); cache_edt->setText(sequence->getCache()); increment_edt->setText(sequence->getIncrement()); } else { cyclic_chk->setChecked(false); start_edt->setText(QString("1")); maximum_edt->setText(Sequence::MaxPositiveValue); minimum_edt->setText(QString("0")); cache_edt->setText(QString("1")); increment_edt->setText(QString("1")); } } void SequenceWidget::applyConfiguration(void) { try { Sequence *sequence=nullptr; startConfiguration(); sequence=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); sequence->setCycle(cyclic_chk->isChecked()); sequence->setValues(minimum_edt->text(), maximum_edt->text(), increment_edt->text(), start_edt->text(), cache_edt->text()); sequence->setOwnerColumn(dynamic_cast(column_sel->getSelectedObject())); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SequenceWidget::setDefaultValues(void) { Sequence *seq = dynamic_cast(this->object); if(seq && def_values_cmb->currentIndex() == 0) { start_edt->setText(seq->getStart()); cache_edt->setText(seq->getCache()); minimum_edt->setText(seq->getMinValue()); maximum_edt->setText(seq->getMaxValue()); increment_edt->setText(seq->getIncrement()); } else { QString min = "0", max = Sequence::MaxPositiveValue; if(def_values_cmb->currentText() == "smallserial") max = Sequence::MaxSmallPositiveValue; else if(def_values_cmb->currentText() == "bigserial") max = Sequence::MaxBigPositiveValue; start_edt->setText("1"); cache_edt->setText("1"); increment_edt->setText("1"); minimum_edt->setText(min); maximum_edt->setText(max); } } pgmodeler-0.9.2/libpgmodeler_ui/src/sequencewidget.h000066400000000000000000000035471360462764600226450ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SequenceWidget \brief Implements the operations to create/edit sequences via form. */ #ifndef SEQUENCE_WIDGET_H #define SEQUENCE_WIDGET_H #include "baseobjectwidget.h" #include "ui_sequencewidget.h" class SequenceWidget: public BaseObjectWidget, public Ui::SequenceWidget { private: Q_OBJECT ObjectSelectorWidget *column_sel; protected: void setAttributes(DatabaseModel *model, Sequence *sequence); /*! \brief This auxiliary method is used in ColumnWidget to enable the user to edit the underlying sequence's attributes * when handling an indentity column. This method disable almost all fields in the form letting only the ones related to * sequence's values configuration enabled */ void setAttributesReadonly(DatabaseModel *model, OperationList *op_list, Schema *schema, Sequence *sequence, Column *column); public: SequenceWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Sequence *sequence); public slots: void applyConfiguration(void); private slots: void setDefaultValues(void); friend class ColumnWidget; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/snippetsconfigwidget.cpp000066400000000000000000000406661360462764600244260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "snippetsconfigwidget.h" #include "baseobject.h" #include "messagebox.h" #include "pgmodeleruins.h" map SnippetsConfigWidget::config_params; const QRegExp SnippetsConfigWidget::IdFormatRegExp=QRegExp(QString("^([a-z])([a-z]*|(\\d)*|(_)*)+"), Qt::CaseInsensitive); SnippetsConfigWidget::SnippetsConfigWidget(QWidget * parent) : BaseConfigWidget(parent) { QPixmap ico; QString gen_purpose=trUtf8("General purpose"); map types_map; vector types=BaseObject::getObjectTypes(true, {ObjectType::Relationship, ObjectType::Tag, ObjectType::Textbox, ObjectType::Permission, ObjectType::BaseRelationship }); setupUi(this); for(ObjectType type : types) types_map[BaseObject::getTypeName(type)]=type; //Creates a combo with the accepted object type for(auto &itr : types_map) { ico.load(PgModelerUiNs::getIconPath(itr.second)); applies_to_cmb->addItem(ico, itr.first, enum_cast(itr.second)); filter_cmb->addItem(ico, itr.first, enum_cast(itr.second)); } applies_to_cmb->insertItem(0, gen_purpose, enum_cast(ObjectType::BaseObject)); applies_to_cmb->setCurrentIndex(0); filter_cmb->insertItem(0, gen_purpose, enum_cast(ObjectType::BaseObject)); filter_cmb->insertItem(0, trUtf8("All snippets")); filter_cmb->setCurrentIndex(0); parsable_ht=new HintTextWidget(parsable_hint, this); parsable_ht->setText(parsable_chk->statusTip()); placeholders_ht=new HintTextWidget(placeholders_hint, this); placeholders_ht->setText(placeholders_chk->statusTip()); snippet_txt=PgModelerUiNs::createNumberedTextEditor(snippet_wgt); try { snippet_hl=new SyntaxHighlighter(snippet_txt); snippet_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } enableEditMode(false); connect(new_tb, SIGNAL(clicked()), this, SLOT(resetForm())); connect(edit_tb, SIGNAL(clicked()), this, SLOT(editSnippet())); connect(remove_tb, SIGNAL(clicked()), this, SLOT(removeSnippet())); connect(remove_all_tb, SIGNAL(clicked()), this, SLOT(removeAllSnippets())); connect(cancel_tb, &QToolButton::clicked, [&](){ enableEditMode(false); }); connect(snippets_cmb, &QComboBox::currentTextChanged, [&](){ enableEditMode(false); }); connect(id_edt, SIGNAL(textChanged(QString)), this, SLOT(enableSaveButtons())); connect(label_edt, SIGNAL(textChanged(QString)), this, SLOT(enableSaveButtons())); connect(snippet_txt, SIGNAL(textChanged()), this, SLOT(enableSaveButtons())); connect(parsable_chk, SIGNAL(toggled(bool)), this, SLOT(enableSaveButtons())); connect(filter_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(filterSnippets(int))); connect(update_tb, SIGNAL(clicked()), this, SLOT(handleSnippet())); connect(add_tb, SIGNAL(clicked()), this, SLOT(handleSnippet())); connect(parse_tb, SIGNAL(clicked()), this, SLOT(parseSnippet())); connect(parsable_chk, SIGNAL(toggled(bool)), placeholders_chk, SLOT(setEnabled(bool))); } map SnippetsConfigWidget::getConfigurationParams(void) { return(config_params); } attribs_map SnippetsConfigWidget::getSnippetById(const QString &snip_id) { if(config_params.count(snip_id)) return(config_params[snip_id]); else return(attribs_map()); } QStringList SnippetsConfigWidget::getSnippetsIdsByObject(ObjectType obj_type) { QStringList ids; QString type_name=(obj_type==ObjectType::BaseObject ? Attributes::General : BaseObject::getSchemaName(obj_type)); for(auto &snip : config_params) { if(snip.second[Attributes::Object]==type_name) ids.push_back(snip.second[Attributes::Id]); } return(ids); } vector SnippetsConfigWidget::getSnippetsByObject(ObjectType obj_type) { vector snippets; QString type_name=(obj_type==ObjectType::BaseObject ? Attributes::General : BaseObject::getSchemaName(obj_type)); for(auto &snip : config_params) { if(snip.second[Attributes::Object]==type_name) snippets.push_back(snip.second); } return(snippets); } QStringList SnippetsConfigWidget::getAllSnippetsAttribute(const QString &attrib) { QStringList attribs; for(auto &snip : config_params) { if(snip.second.count(attrib)) attribs.push_back(snip.second[attrib]); } return(attribs); } vector SnippetsConfigWidget::getAllSnippets(void) { vector snippets; for(auto &snip : config_params) snippets.push_back(snip.second); return(snippets); } QString SnippetsConfigWidget::parseSnippet(attribs_map snippet, attribs_map attribs) { SchemaParser schparser; QStringList aux_attribs; QString buf=snippet[Attributes::Contents]; if(snippet[Attributes::Parsable]!=Attributes::True) return(buf); try { schparser.loadBuffer(buf); //Assigning dummy values for empty attributes if(snippet[Attributes::Placeholders]==Attributes::True) { aux_attribs=schparser.extractAttributes(); for(QString attr : aux_attribs) { if(attribs.count(attr)==0 || (attribs.count(attr) && attribs[attr].isEmpty())) attribs[attr]=QString("{%1}").arg(attr); } } schparser.ignoreEmptyAttributes(true); schparser.ignoreUnkownAttributes(true); return(schparser.getCodeDefinition(attribs)); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } QString SnippetsConfigWidget::getParsedSnippet(const QString &snip_id, attribs_map attribs) { if(config_params.count(snip_id)) { try { return(parseSnippet(config_params[snip_id], attribs)); } catch(Exception &e) { return(trUtf8("/* Error parsing the snippet '%1':\n\n %2 */").arg(snip_id, e.getErrorMessage())); } } else return(QString()); } void SnippetsConfigWidget::fillSnippetsCombo(map &config) { snippets_cmb->clear(); for(auto &cfg : config) snippets_cmb->addItem(QString("[%1] %2").arg(cfg.first, cfg.second.at(Attributes::Label)), cfg.first); } bool SnippetsConfigWidget::isSnippetValid(attribs_map &attribs, const QString &orig_id) { Messagebox msg_box; QString snip_id=attribs.at(Attributes::Id), err_msg; if(!orig_id.isEmpty() && snip_id!=orig_id && config_params.count(snip_id)!=0) err_msg=trUtf8("Duplicated snippet id %1 detected. Please, specify a different one!").arg(snip_id); else if(!IdFormatRegExp.exactMatch(snip_id)) err_msg=trUtf8("Invalid ID pattern detected %1. This one must start with at leat one letter and be composed by letters, numbers and/or underscore!").arg(snip_id); else if(attribs[Attributes::Label].isEmpty()) err_msg=trUtf8("Empty label for snippet %1. Please, specify a value for it!").arg(snip_id); else if(attribs[Attributes::Contents].isEmpty()) err_msg=trUtf8("Empty code for snippet %1. Please, specify a value for it!").arg(snip_id); else if(attribs[Attributes::Parsable]==Attributes::True) { try { QString buf=snippet_txt->toPlainText(); attribs_map attribs; SchemaParser schparser; schparser.loadBuffer(buf); schparser.ignoreEmptyAttributes(true); schparser.ignoreUnkownAttributes(true); schparser.getCodeDefinition(attribs); } catch(Exception &e) { err_msg=trUtf8("The dynamic snippet contains syntax error(s). Additional info:
%1").arg(e.getErrorMessage()); } } if(!err_msg.isEmpty()) { msg_box.show(err_msg, Messagebox::ErrorIcon, Messagebox::OkButton); return(false); } else return(true); } void SnippetsConfigWidget::hideEvent(QHideEvent *) { enableEditMode(false); } void SnippetsConfigWidget::loadConfiguration(void) { try { QStringList inv_snippets; this->resetForm(); BaseConfigWidget::loadConfiguration(GlobalAttributes::SnippetsConf, config_params, { Attributes::Id }); //Check if there are invalid snippets loaded for(auto &snip : config_params) { if(!isSnippetValid(snip.second,QString())) inv_snippets.push_back(snip.first); } //Destroy any invalid snippets for(QString id : inv_snippets) config_params.erase(id); fillSnippetsCombo(config_params); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e, e.getExtraInfo()); } } void SnippetsConfigWidget::resetForm(void) { snippet_txt->clear(); id_edt->clear(); label_edt->clear(); applies_to_cmb->setCurrentIndex(0); parsable_chk->setChecked(false); placeholders_chk->setChecked(false); } attribs_map SnippetsConfigWidget::getSnippetAttributes(void) { QString object_id=BaseObject::getSchemaName(static_cast(applies_to_cmb->currentData().toUInt())); if(object_id.isEmpty()) object_id=Attributes::General; return(attribs_map{ {Attributes::Id, id_edt->text()}, {Attributes::Label, label_edt->text()}, {Attributes::Object, object_id}, {Attributes::Parsable, (parsable_chk->isChecked() ? Attributes::True : Attributes::False)}, {Attributes::Placeholders, (parsable_chk->isChecked() && placeholders_chk->isChecked() ? Attributes::True : Attributes::False)}, {Attributes::Contents, snippet_txt->toPlainText()} }); } void SnippetsConfigWidget::editSnippet(void) { QString snip_id=snippets_cmb->currentData().toString(); ObjectType obj_type=BaseObject::getObjectType(config_params[snip_id].at(Attributes::Object)); enableEditMode(true); snippet_txt->setPlainText(config_params[snip_id].at(Attributes::Contents)); id_edt->setText(snip_id); label_edt->setText(config_params[snip_id].at(Attributes::Label)); parsable_chk->setChecked(config_params[snip_id].at(Attributes::Parsable)==Attributes::True); placeholders_chk->setChecked(config_params[snip_id].at(Attributes::Placeholders)==Attributes::True); applies_to_cmb->setCurrentText(BaseObject::getTypeName(obj_type)); } void SnippetsConfigWidget::handleSnippet(void) { QString orig_id=snippets_cmb->currentData().toString(); attribs_map snippet; snippet=getSnippetAttributes(); if(isSnippetValid(snippet, orig_id)) { config_params[id_edt->text()]=snippet; //If the operation is update and the snippet id changed, remove the original one if(sender()==update_tb && id_edt->text() != orig_id) config_params.erase(orig_id); filterSnippets(filter_cmb->currentIndex()); resetForm(); setConfigurationChanged(true); } } void SnippetsConfigWidget::removeSnippet(void) { config_params.erase(snippets_cmb->currentData().toString()); filterSnippets(filter_cmb->currentIndex()); setConfigurationChanged(true); } void SnippetsConfigWidget::removeAllSnippets(void) { Messagebox msg_box; msg_box.show(trUtf8("Do you really want to remove all snippets?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { config_params.clear(); filterSnippets(0); setConfigurationChanged(true); } } void SnippetsConfigWidget::enableEditMode(bool enable) { bool has_snippets=(snippets_cmb->count() > 0); cancel_tb->setVisible(enable); new_tb->setVisible(!enable); snippets_cmb->setEnabled(!enable); filter_cmb->setEnabled(!enable); add_tb->setVisible(!enable); update_tb->setVisible(enable); edit_tb->setEnabled(!enable && has_snippets); remove_tb->setEnabled(!enable && has_snippets); remove_all_tb->setEnabled(!enable && has_snippets); if(!enable) resetForm(); } void SnippetsConfigWidget::enableSaveButtons(void) { bool enable=(!id_edt->text().isEmpty() && !label_edt->text().isEmpty() && !snippet_txt->toPlainText().isEmpty()); add_tb->setEnabled(enable); update_tb->setEnabled(enable); parse_tb->setEnabled(enable && parsable_chk->isChecked()); } void SnippetsConfigWidget::filterSnippets(int idx) { if(idx <= 0) fillSnippetsCombo(config_params); else { ObjectType obj_type=static_cast(filter_cmb->currentData().toUInt()); map flt_snippets; QString object_id=BaseObject::getSchemaName(obj_type); if(object_id.isEmpty()) object_id=Attributes::General; for(auto &cfg : config_params) { if(cfg.second.at(Attributes::Object)==object_id) flt_snippets[cfg.first]=cfg.second; } fillSnippetsCombo(flt_snippets); } } void SnippetsConfigWidget::parseSnippet(void) { Messagebox msg_box; try { parseSnippet(getSnippetAttributes(), attribs_map()); msg_box.show(trUtf8("No syntax errors found in the snippet."), Messagebox::InfoIcon); } catch(Exception &e) { msg_box.show(e); } } void SnippetsConfigWidget::saveConfiguration(void) { try { QString root_dir=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator, snippet_sch=root_dir + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + Attributes::Snippet + GlobalAttributes::SchemaExt; attribs_map attribs; ObjectType obj_type; vector snippets; //Saving the snippets sorting them by object type in the output file for(int i=0; i < applies_to_cmb->count(); i++) { obj_type=static_cast(applies_to_cmb->itemData(i).toUInt()); snippets=getSnippetsByObject(obj_type); for(auto &snip : snippets) { attribs[Attributes::Snippet]+= schparser.convertCharsToXMLEntities(schparser.getCodeDefinition(snippet_sch, snip)); } } config_params[GlobalAttributes::SnippetsConf]=attribs; BaseConfigWidget::saveConfiguration(GlobalAttributes::SnippetsConf, config_params); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SnippetsConfigWidget::restoreDefaults(void) { try { BaseConfigWidget::restoreDefaults(GlobalAttributes::SnippetsConf, false); this->loadConfiguration(); setConfigurationChanged(true); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SnippetsConfigWidget::configureSnippetsMenu(QMenu *snip_menu, vector types) { vector snippets, vet_aux; QAction *act=nullptr; QMenu *menu=nullptr; map submenus; QString object, snip_id, type_name; QPixmap ico; //Retrieve all snippets if the 'types' is empty if(types.empty()) snippets=SnippetsConfigWidget::getAllSnippets(); else { //Retreving only the snippets of the type specified by user for(ObjectType type : types) { vet_aux=SnippetsConfigWidget::getSnippetsByObject(type); snippets.insert(snippets.end(), vet_aux.begin(), vet_aux.end()); } } snip_menu->clear(); for(attribs_map snip : snippets) { object=snip[Attributes::Object]; snip_id=snip[Attributes::Id]; //Creating the snippet submenu for the current object type if(submenus.count(object)==0) { type_name=BaseObject::getTypeName(object); if(type_name.isEmpty()) { ico=QPixmap(); type_name=trUtf8("General"); } else ico=QPixmap(PgModelerUiNs::getIconPath(object)); menu=new QMenu(type_name, snip_menu); menu->setIcon(ico); menu->setToolTipsVisible(true); submenus[object]=menu; /* If the current group (object) is general does not include the submenu yet. This will be included as the last submenu */ if(object!=Attributes::General) snip_menu->addMenu(menu); } //Creating the action for the current snippet act=new QAction(QPixmap(PgModelerUiNs::getIconPath("codesnippet")), snip_id, submenus[object]); act->setToolTip(snip[Attributes::Label]); submenus[object]->addAction(act); } //Include the "general" submenu at the end of snippet menu if(submenus.count(Attributes::General)!=0) { if(snip_menu->isEmpty()) snip_menu->addMenu(submenus[Attributes::General]); else { //Inserting the "general" submenu at the top of snippets actions snip_menu->insertMenu(snip_menu->actions().at(0), submenus[Attributes::General]); snip_menu->insertSeparator(snip_menu->actions().at(1)); } } } bool SnippetsConfigWidget::isSnippetExists(const QString &snip_id) { return(config_params.count(snip_id)!=0); } pgmodeler-0.9.2/libpgmodeler_ui/src/snippetsconfigwidget.h000066400000000000000000000103751360462764600240650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SnippetsConfigWidget \brief Implements the operations to manage sql snippets configuration. */ #ifndef SNIPPETS_CONFIG_WIDGET_H #define SNIPPETS_CONFIG_WIDGET_H #include "ui_snippetsconfigwidget.h" #include "baseconfigwidget.h" #include "syntaxhighlighter.h" #include "baseobject.h" #include "hinttextwidget.h" #include "numberedtexteditor.h" class SnippetsConfigWidget: public BaseConfigWidget, public Ui::SnippetsConfigWidget { private: Q_OBJECT //! \brief Stores all snippets created by the user or loaded from file static map config_params; //! \brief The regular expression the defines a valid id for a snippet static const QRegExp IdFormatRegExp; NumberedTextEditor *snippet_txt; SyntaxHighlighter *snippet_hl; HintTextWidget *parsable_ht, *placeholders_ht; //! \brief Fills the snippet combobox with previously loaded snippet map void fillSnippetsCombo(map &config); //! \brief Validates the specified snippet atributes against the current loaded ones bool isSnippetValid(attribs_map &attribs, const QString &orig_id=QString()); void hideEvent(QHideEvent *); /* Disable methods */ void applyConfiguration(void){} //! \brief Parse the snippet map by using the 'attribs' attributes referenced in the snippet code (for parsable snippets) static QString parseSnippet(attribs_map snippet, attribs_map attribs); //! \brief Create an attribute maps based upon the values filled in the form attribs_map getSnippetAttributes(void); public: SnippetsConfigWidget(QWidget * parent = nullptr); void saveConfiguration(void); void loadConfiguration(void); static map getConfigurationParams(void); //! \brief Returns the snippet attributes related to the identified snippet snip_id static attribs_map getSnippetById(const QString &snip_id); //! \brief Returns only the snippets ids related to the specified object type. static QStringList getSnippetsIdsByObject(ObjectType obj_type); /*! \brief Returns a vector of snippets' attributes filtering by the object type in which they apply. There's a special group for general purpose snippets that can be retrieved using ObjectType::ObjBaseObject type. If there is no snippets related to the type an empty vector is returned. */ static vector getSnippetsByObject(ObjectType obj_type); //! \brief Returns the a list of all available snippets specified attribute static QStringList getAllSnippetsAttribute(const QString &attrib); //! \brief Returns the a vector of all available snippets. static vector getAllSnippets(void); /*! \brief Returns the parsed snipped identified by 'snip_id'. The 'attribs' contains the set of attributes to be replaced on the original snippet code */ static QString getParsedSnippet(const QString &snip_id, attribs_map attribs=attribs_map()); //! \brief Configures a QMenu instances with the available snippets categorizing them in submenus static void configureSnippetsMenu(QMenu *snip_menu, vector types=vector()); //! \brief Returns is the identified snippet exists static bool isSnippetExists(const QString &snip_id); private slots: void resetForm(void); void editSnippet(void); void handleSnippet(void); void removeSnippet(void); void removeAllSnippets(void); void enableEditMode(bool enable); void enableSaveButtons(void); void filterSnippets(int idx); void parseSnippet(void); public slots: void restoreDefaults(void); friend class ConfigurationForm; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/sourcecodewidget.cpp000066400000000000000000000207371360462764600235230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sourcecodewidget.h" #include "taskprogresswidget.h" #include "pgmodeleruins.h" SourceCodeWidget::SourceCodeWidget(QWidget *parent): BaseObjectWidget(parent) { try { Ui_SourceCodeWidget::setupUi(this); configureFormLayout(codigofonte_grid, ObjectType::BaseObject); comment_lbl->setVisible(false); comment_edt->setVisible(false); hl_sqlcode=nullptr; hl_xmlcode=nullptr; sqlcode_txt=PgModelerUiNs::createNumberedTextEditor(sqlcode_wgt); sqlcode_txt->setReadOnly(true); xmlcode_txt=PgModelerUiNs::createNumberedTextEditor(xmlcode_wgt); xmlcode_txt->setReadOnly(true); name_edt->setReadOnly(true); version_cmb->addItems(PgSqlVersions::AllVersions); code_options_ht=new HintTextWidget(code_options_hint, this); code_options_ht->setText( trUtf8("Original: displays only the original object's SQL code.

\ Dependencies: displays the original code including all dependencies needed to properly create the selected object.

\ Children: displays the original code including all object's children SQL code. This option is used only by schemas, tables and views.")); connect(version_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(generateSourceCode(int))); connect(code_options_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(generateSourceCode())); connect(sourcecode_twg, SIGNAL(currentChanged(int)), this, SLOT(setSourceCodeTab(int))); connect(save_sql_tb, SIGNAL(clicked()), this, SLOT(saveSQLCode())); hl_sqlcode=new SyntaxHighlighter(sqlcode_txt); hl_xmlcode=new SyntaxHighlighter(xmlcode_txt); setMinimumSize(640, 540); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SourceCodeWidget::setSourceCodeTab(int) { QString code_icon; bool enabled=false; QPixmap icone; ObjectType obj_type=object->getObjectType(); if(sourcecode_twg->currentIndex()==0) code_icon=QString("codigosql"); else code_icon=QString("codigoxml"); enabled=(sourcecode_twg->currentIndex()==0 && ((obj_type==ObjectType::BaseRelationship && dynamic_cast(object)->getRelationshipType()==BaseRelationship::RelationshipFk) || (obj_type!=ObjectType::BaseRelationship && obj_type!=ObjectType::Textbox))); icone=QPixmap(PgModelerUiNs::getIconPath(code_icon)); icon_lbl->setPixmap(icone); version_cmb->setEnabled(enabled); pgsql_lbl->setEnabled(enabled); version_lbl->setEnabled(enabled); } void SourceCodeWidget::saveSQLCode(void) { QFileDialog file_dlg; file_dlg.setWindowTitle(trUtf8("Save SQL code as...")); file_dlg.setFileMode(QFileDialog::AnyFile); file_dlg.setAcceptMode(QFileDialog::AcceptSave); file_dlg.setModal(true); file_dlg.setNameFilter(trUtf8("SQL code (*.sql);;All files (*.*)")); file_dlg.selectFile(QString("%1-%2.sql").arg(object->getSchemaName()).arg(object->getName())); if(file_dlg.exec()==QFileDialog::Accepted) { QFile out; QByteArray buf; if(!file_dlg.selectedFiles().isEmpty()) { out.setFileName(file_dlg.selectedFiles().at(0)); if(!out.open(QFile::WriteOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(file_dlg.selectedFiles().at(0)), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); buf.append(sqlcode_txt->toPlainText()); out.write(buf.data(), buf.size()); out.close(); } } } void SourceCodeWidget::generateSourceCode(int) { ObjectType obj_type; TaskProgressWidget *task_prog_wgt=nullptr; try { sqlcode_txt->clear(); xmlcode_txt->clear(); obj_type=object->getObjectType(); if(obj_type!=ObjectType::Textbox || (obj_type==ObjectType::BaseRelationship && dynamic_cast(object)->getRelationshipType()==BaseRelationship::RelationshipFk)) { QString aux_def; BaseObject::setPgSQLVersion(version_cmb->currentText()); if(obj_type==ObjectType::Database) { task_prog_wgt=new TaskProgressWidget; task_prog_wgt->setWindowTitle(trUtf8("Generating source code...")); task_prog_wgt->show(); connect(this->model, SIGNAL(s_objectLoaded(int,QString,unsigned)), task_prog_wgt, SLOT(updateProgress(int,QString,unsigned))); sqlcode_txt->setPlainText(object->getCodeDefinition(SchemaParser::SqlDefinition)); } else { if(code_options_cmb->currentIndex()==OriginalSql) sqlcode_txt->setPlainText(object->getCodeDefinition(SchemaParser::SqlDefinition)); else { vector objs=model->getCreationOrder(object, code_options_cmb->currentIndex()==ChildrenSql); for(BaseObject *obj : objs) aux_def+=obj->getCodeDefinition(SchemaParser::SqlDefinition); } if(!aux_def.isEmpty()) { aux_def=trUtf8("-- NOTE: the code below contains the SQL for the selected object\n\ -- as well for its dependencies and children (if applicable).\n\ -- \n\ -- This feature is only a convinience in order to permit you to test\n\ -- the whole object's SQL definition at once.\n\ -- \n\ -- When exporting or generating the SQL for the whole database model\n\ -- all objects will be placed at their original positions.\n\n\n") + aux_def; sqlcode_txt->setPlainText(sqlcode_txt->toPlainText() + aux_def); } } #ifdef DEMO_VERSION #warning "DEMO VERSION: SQL code preview truncated." if(!sqlcode_txt->toPlainText().isEmpty()) { QString code=sqlcode_txt->toPlainText(); code=code.mid(0, code.size()/2); code+=trUtf8("\n\n-- SQL code purposely truncated at this point in demo version!"); sqlcode_txt->setPlainText(code); } #endif } save_sql_tb->setEnabled(!sqlcode_txt->toPlainText().isEmpty()); if(sqlcode_txt->toPlainText().isEmpty()) sqlcode_txt->setPlainText(trUtf8("-- SQL code unavailable for this type of object --")); #ifdef DEMO_VERSION #warning "DEMO VERSION: XML code preview disabled." xmlcode_txt->setPlainText(trUtf8("")); #else xmlcode_txt->setPlainText(object->getCodeDefinition(SchemaParser::XmlDefinition)); #endif setSourceCodeTab(); if(task_prog_wgt) { task_prog_wgt->close(); disconnect(this->model, nullptr, task_prog_wgt, nullptr); delete(task_prog_wgt); } } catch(Exception &e) { if(task_prog_wgt) { task_prog_wgt->close(); disconnect(this->model, nullptr, task_prog_wgt, nullptr); delete(task_prog_wgt); } throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SourceCodeWidget::setAttributes(DatabaseModel *model, BaseObject *object) { if(object) { try { BaseObjectWidget::setAttributes(model, object, nullptr); ObjectType obj_type=object->getObjectType(); this->name_edt->setText(QString("%1 (%2)").arg(object->getSignature()).arg(object->getTypeName())); this->protected_obj_frm->setVisible(false); this->obj_id_lbl->setVisible(false); this->code_options_cmb->setEnabled(obj_type!=ObjectType::Database && obj_type!=ObjectType::Textbox && obj_type!=ObjectType::BaseRelationship && obj_type!=ObjectType::Relationship); #ifdef DEMO_VERSION #warning "DEMO VERSION: SQL code display options disabled." code_options_cmb->setEnabled(false); #endif obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(object->getObjectType()))); if(!hl_sqlcode->isConfigurationLoaded()) hl_sqlcode->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); if(!hl_xmlcode->isConfigurationLoaded()) hl_xmlcode->loadConfiguration(GlobalAttributes::XMLHighlightConfPath); generateSourceCode(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } void SourceCodeWidget::applyConfiguration(void) { emit s_closeRequested(); } pgmodeler-0.9.2/libpgmodeler_ui/src/sourcecodewidget.h000066400000000000000000000035411360462764600231620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SourceCodeWidget \brief Implements the operation to visualize object's source code. */ #ifndef SOURCE_CODE_WIDGET_H #define SOURCE_CODE_WIDGET_H #include "ui_sourcecodewidget.h" #include "baseobjectwidget.h" #include "hinttextwidget.h" #include "numberedtexteditor.h" class SourceCodeWidget: public BaseObjectWidget, public Ui::SourceCodeWidget { private: Q_OBJECT static constexpr int OriginalSql=0, DependenciesSql=1, ChildrenSql=2; NumberedTextEditor *sqlcode_txt, *xmlcode_txt; SyntaxHighlighter *hl_sqlcode, *hl_xmlcode; HintTextWidget *code_options_ht; public: SourceCodeWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, BaseObject *object=nullptr); /* Forcing the widget to indicate that the handled object is not protected even if it IS protected. This will avoid the ok button of the parent dialog to be disabled */ virtual bool isHandledObjectProtected(void){ return(false); } public slots: void applyConfiguration(void); private slots: void generateSourceCode(int=0); void setSourceCodeTab(int=0); void saveSQLCode(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/sqlexecutionhelper.cpp000066400000000000000000000041661360462764600241050ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sqlexecutionhelper.h" SQLExecutionHelper::SQLExecutionHelper(void) : QObject(nullptr) { cancelled = false; result_model = nullptr; } void SQLExecutionHelper::setConnection(Connection conn) { connection = conn; } void SQLExecutionHelper::setCommand(const QString &cmd) { command = cmd; } ResultSetModel *SQLExecutionHelper::getResultSetModel(void) { return(result_model); } bool SQLExecutionHelper::isCancelled(void) { return(cancelled); } QStringList SQLExecutionHelper::getNotices(void) { return(notices); } void SQLExecutionHelper::executeCommand(void) { try { ResultSet res; Catalog catalog; Connection aux_conn = Connection(connection.getConnectionParams()); catalog.setConnection(aux_conn); result_model = nullptr; cancelled = false; if(!connection.isStablished()) { connection.setNoticeEnabled(true); connection.connect(); //The connection will break the execution if it keeps idle for one hour or more connection.setSQLExecutionTimout(3600); } connection.executeDMLCommand(command, res); notices = connection.getNotices(); if(!res.isEmpty()) result_model = new ResultSetModel(res, catalog); emit s_executionFinished(res.getTupleCount()); } catch(Exception &e) { connection.close(); emit s_executionAborted(e); } } void SQLExecutionHelper::cancelCommand(void) { if(connection.isStablished()) { connection.requestCancel(); cancelled = true; } } pgmodeler-0.9.2/libpgmodeler_ui/src/sqlexecutionhelper.h000066400000000000000000000034511360462764600235460ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SQLExecutionHelper \brief Implements a command execution helper that permit the execution of SQL commands in a thread */ #ifndef SQL_EXECUTION_HELPER_H #define SQL_EXECUTION_HELPER_H #include #include #include "connection.h" #include "resultsetmodel.h" class SQLExecutionHelper : public QObject { private: Q_OBJECT Connection connection; QString command; ResultSetModel *result_model; bool cancelled; int affected_rows; QStringList notices; public: SQLExecutionHelper(void); void setConnection(Connection conn); void setCommand(const QString &cmd); //! \brief Returns the result set model created in the execution. This object is not deleted after the execution. ResultSetModel *getResultSetModel(void); bool isCancelled(void); //! \brief Returns the notices generated by the execution QStringList getNotices(void); public slots: void executeCommand(void); void cancelCommand(void); signals: void s_executionFinished(int rows_affected); void s_executionAborted(Exception e); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/sqlexecutionwidget.cpp000066400000000000000000001056521360462764600241130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sqlexecutionwidget.h" #include "taskprogresswidget.h" #include "databaseexplorerwidget.h" #include "snippetsconfigwidget.h" #include "pgmodeleruins.h" #include "plaintextitemdelegate.h" #include "datamanipulationform.h" map SQLExecutionWidget::cmd_history; int SQLExecutionWidget::cmd_history_max_len = 1000; const QString SQLExecutionWidget::ColumnNullValue = QString("␀"); SQLExecutionWidget::SQLExecutionWidget(QWidget * parent) : QWidget(parent) { setupUi(this); sql_cmd_txt=PgModelerUiNs::createNumberedTextEditor(sql_cmd_wgt); cmd_history_txt=PgModelerUiNs::createNumberedTextEditor(cmd_history_parent); cmd_history_txt->setCustomContextMenuEnabled(false); cmd_history_txt->setTabStopWidth(sql_cmd_txt->getTabWidth()); cmd_history_txt->setContextMenuPolicy(Qt::CustomContextMenu); cmd_history_txt->setReadOnly(true); cmd_history_txt->installEventFilter(this); output_tbw->widget(2)->installEventFilter(this); find_history_wgt = new FindReplaceWidget(cmd_history_txt, find_history_parent); QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins(0,0,0,0); layout->addWidget(find_history_wgt); find_history_parent->setLayout(layout); find_history_parent->setVisible(false); connect(find_history_wgt->hide_tb, SIGNAL(clicked(bool)), find_history_parent, SLOT(hide())); sql_cmd_hl=new SyntaxHighlighter(sql_cmd_txt, false); sql_cmd_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); cmd_history_hl=new SyntaxHighlighter(cmd_history_txt, false); cmd_history_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); results_parent->setVisible(false); output_tbw->setTabEnabled(0, false); sql_file_dlg.setDefaultSuffix(QString("sql")); sql_file_dlg.setFileMode(QFileDialog::AnyFile); sql_file_dlg.setNameFilter(trUtf8("SQL file (*.sql);;All files (*.*)")); sql_file_dlg.setModal(true); snippets_tb->setMenu(&snippets_menu); code_compl_wgt=new CodeCompletionWidget(sql_cmd_txt, true); find_replace_wgt=new FindReplaceWidget(sql_cmd_txt, find_wgt_parent); QHBoxLayout *hbox=new QHBoxLayout(find_wgt_parent); hbox->setContentsMargins(0,0,0,0); hbox->addWidget(find_replace_wgt); find_wgt_parent->setVisible(false); connect(find_replace_wgt->hide_tb, SIGNAL(clicked(bool)), find_tb, SLOT(toggle())); run_sql_tb->setToolTip(run_sql_tb->toolTip() + QString(" (%1)").arg(run_sql_tb->shortcut().toString())); stop_tb->setToolTip(stop_tb->toolTip() + QString(" (%1)").arg(stop_tb->shortcut().toString())); export_tb->setToolTip(export_tb->toolTip() + QString(" (%1)").arg(export_tb->shortcut().toString())); file_tb->setToolTip(file_tb->toolTip() + QString(" (%1)").arg(file_tb->shortcut().toString())); output_tb->setToolTip(output_tb->toolTip() + QString(" (%1)").arg(output_tb->shortcut().toString())); find_tb->setToolTip(find_tb->toolTip() + QString(" (%1)").arg(find_tb->shortcut().toString())); filter_tb->setToolTip(filter_tb->toolTip() + QString(" (%1)").arg(filter_tb->shortcut().toString())); results_tbw->setItemDelegate(new PlainTextItemDelegate(this, true)); action_load=new QAction(QIcon(PgModelerUiNs::getIconPath("abrir")), trUtf8("Load"), this); action_save=new QAction(QIcon(PgModelerUiNs::getIconPath("salvar")), trUtf8("Save"), this); action_save_as=new QAction(QIcon(PgModelerUiNs::getIconPath("salvar_como")), trUtf8("Save as"), this); file_menu.addAction(action_load); file_menu.addAction(action_save); file_menu.addAction(action_save_as); file_tb->setMenu(&file_menu); filter_wgt->setVisible(false); connect(columns_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(filterResults())); connect(filter_edt, SIGNAL(textChanged(QString)), this, SLOT(filterResults())); connect(hide_tb, SIGNAL(clicked(bool)), filter_tb, SLOT(click())); connect(filter_tb, &QToolButton::toggled, [&](bool checked){ filter_wgt->setVisible(checked); if(checked) filter_edt->setFocus(); else sql_cmd_txt->setFocus(); }); connect(exact_chk, SIGNAL(toggled(bool)), this, SLOT(filterResults())); connect(exact_chk, &QCheckBox::toggled, [&](bool checked){ regexp_chk->setChecked(false); regexp_chk->setEnabled(!checked); case_sensitive_chk->setChecked(false); case_sensitive_chk->setEnabled(!checked); }); connect(regexp_chk, SIGNAL(toggled(bool)), this, SLOT(filterResults())); connect(case_sensitive_chk, SIGNAL(toggled(bool)), this, SLOT(filterResults())); connect(action_load, SIGNAL(triggered(bool)), this, SLOT(loadCommands())); connect(action_save, SIGNAL(triggered(bool)), this, SLOT(saveCommands())); connect(action_save_as, SIGNAL(triggered(bool)), this, SLOT(saveCommands())); connect(clear_btn, SIGNAL(clicked(void)), this, SLOT(clearAll(void))); connect(sql_cmd_txt, SIGNAL(textChanged(void)), this, SLOT(enableCommandButtons(void))); connect(run_sql_tb, SIGNAL(clicked(void)), this, SLOT(runSQLCommand(void))); connect(find_tb, SIGNAL(toggled(bool)), find_wgt_parent, SLOT(setVisible(bool))); connect(output_tb, SIGNAL(toggled(bool)), this, SLOT(toggleOutputPane(bool))); //Signal handling with C++11 lambdas Slots connect(results_tbw, &QTableView::pressed, [&](){ SQLExecutionWidget::copySelection(results_tbw); }); connect(export_tb, &QToolButton::clicked, [&](){ SQLExecutionWidget::exportResults(results_tbw); }); connect(close_file_tb, &QToolButton::clicked, [&](){ if(clearAll() == QDialog::Accepted) { filename_edt->clear(); filename_wgt->setVisible(false); } }); connect(&snippets_menu, SIGNAL(triggered(QAction*)), this, SLOT(selectSnippet(QAction *))); connect(cmd_history_txt, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHistoryContextMenu())); configureSnippets(); toggleOutputPane(false); filename_wgt->setVisible(false); v_splitter->handle(1)->installEventFilter(this); stop_tb->setVisible(false); sql_exec_hlp.moveToThread(&sql_exec_thread); connect(&sql_exec_thread, SIGNAL(started()), &sql_exec_hlp, SLOT(executeCommand())); connect(&sql_exec_hlp, SIGNAL(s_executionFinished(int)), this, SLOT(finishExecution(int))); connect(&sql_exec_hlp, SIGNAL(s_executionAborted(Exception)), &sql_exec_thread, SLOT(quit())); connect(&sql_exec_hlp, SIGNAL(s_executionAborted(Exception)), this, SLOT(handleExecutionAborted(Exception))); connect(stop_tb, SIGNAL(clicked(bool)), &sql_exec_hlp, SLOT(cancelCommand()), Qt::DirectConnection); } SQLExecutionWidget::~SQLExecutionWidget(void) { if(sql_exec_thread.isRunning()) { sql_exec_hlp.cancelCommand(); sql_exec_thread.quit(); sql_exec_thread.wait(); } destroyResultModel(); } bool SQLExecutionWidget::eventFilter(QObject *object, QEvent *event) { if(event->type() == QEvent::MouseButtonDblClick && object == v_splitter->handle(1)) { output_tb->setChecked(!v_splitter->handle(1)->isEnabled()); return(true); } else if(event->type()== QEvent::MouseButtonPress && dynamic_cast(event)->button()==Qt::MiddleButton && object == cmd_history_txt && cmd_history_txt->textCursor().hasSelection()) { sql_cmd_txt->appendPlainText(cmd_history_txt->textCursor().selectedText()); return(true); } else if(event->type() == QEvent::Show && object == output_tbw->widget(2)) { if(cmd_history_txt->toPlainText().count(QChar('\n')) != cmd_history[sql_cmd_conn.getConnectionId(true,true)].count(QChar('\n'))) { cmd_history_txt->clear(); cmd_history_txt->appendPlainText(cmd_history[sql_cmd_conn.getConnectionId(true,true)]); cmd_history_txt->updateLineNumbers(); } return(true); } return(QWidget::eventFilter(object, event)); } void SQLExecutionWidget::setConnection(Connection conn) { sql_exec_hlp.setConnection(conn); sql_cmd_conn = conn; db_name_lbl->setText(QString("%1@%2:%3") .arg(conn.getConnectionParam(Connection::ParamDbName)) .arg(conn.getConnectionParam(Connection::ParamServerIp).isEmpty() ? conn.getConnectionParam(Connection::ParamServerFqdn) : conn.getConnectionParam(Connection::ParamServerIp)) .arg(conn.getConnectionParam(Connection::ParamPort))); } void SQLExecutionWidget::setSQLCommand(const QString &sql) { sql_cmd_txt->clear(); sql_cmd_txt->setPlainText(sql); } void SQLExecutionWidget::enableCommandButtons(void) { run_sql_tb->setEnabled(!sql_cmd_txt->toPlainText().isEmpty()); find_tb->setEnabled(!sql_cmd_txt->toPlainText().isEmpty()); clear_btn->setEnabled(run_sql_tb->isEnabled()); } void SQLExecutionWidget::showEvent(QShowEvent *) { sql_cmd_txt->setFocus(); } void SQLExecutionWidget::resizeEvent(QResizeEvent *event) { Qt::ToolButtonStyle style=Qt::ToolButtonTextBesideIcon; if(event->size().width() < this->baseSize().width()) style=Qt::ToolButtonIconOnly; if(file_tb->toolButtonStyle()!=style) { file_tb->setToolButtonStyle(style); run_sql_tb->setToolButtonStyle(style); clear_btn->setToolButtonStyle(style); find_tb->setToolButtonStyle(style); snippets_tb->setToolButtonStyle(style); export_tb->setToolButtonStyle(style); output_tb->setToolButtonStyle(style); stop_tb->setToolButtonStyle(style); filter_tb->setToolButtonStyle(style); } } void SQLExecutionWidget::fillResultsTable(Catalog &catalog, ResultSet &res, QTableWidget *results_tbw, bool store_data) { if(!results_tbw) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { int col=0, row=0, col_cnt=res.getColumnCount(); QTableWidgetItem *item=nullptr; vector type_ids; vector::iterator end; vector types; map type_names; unsigned orig_filter=catalog.getFilter(); results_tbw->setRowCount(0); results_tbw->setColumnCount(col_cnt); results_tbw->verticalHeader()->setVisible(true); results_tbw->setSortingEnabled(false); results_tbw->blockSignals(true); results_tbw->setUpdatesEnabled(false); //Configuring the grid columns with the names of retrived table columns for(col=0; col < col_cnt; col++) { type_ids.push_back(res.getColumnTypeId(col)); item=new QTableWidgetItem(res.getColumnName(col)); item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); results_tbw->setHorizontalHeaderItem(col, item); } //Retrieving the data type names for each column catalog.setFilter(Catalog::ListAllObjects); std::sort(type_ids.begin(), type_ids.end()); end=std::unique(type_ids.begin(), type_ids.end()); type_ids.erase(end, type_ids.end()); types=catalog.getObjectsAttributes(ObjectType::Type, QString(), QString(), type_ids); for(auto &tp : types) type_names[tp[Attributes::Oid].toUInt()]=tp[Attributes::Name]; catalog.setFilter(orig_filter); //Assinging the type names as tooltip on header items for(col=0; col < col_cnt; col++) { item=results_tbw->horizontalHeaderItem(col); item->setToolTip(type_names[res.getColumnTypeId(col)]); item->setData(Qt::UserRole, type_names[res.getColumnTypeId(col)]); } if(res.accessTuple(ResultSet::FirstTuple)) { results_tbw->setRowCount(res.getTupleCount()); do { //Fills the current row with the values of current tuple for(col=0; col < col_cnt; col++) { item=new QTableWidgetItem; if(res.isColumnBinaryFormat(col)) { //Binary columns can't be edited by user item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); item->setText(trUtf8("[binary data]")); } else { item->setText(res.getColumnValue(col)); /* When storing column values in the QTableWidget items we need distinguish empty from null values * Since it may affect the generation of SQL like delete when the field value is used somehow (see DataManipulationForm::getDMLCommand) */ if(store_data) item->setData(Qt::UserRole, res.isColumnValueNull(col) ? ColumnNullValue : item->text()); } results_tbw->setItem(row, col, item); } //Configure the vertical header to show the current tuple id results_tbw->setVerticalHeaderItem(row, new QTableWidgetItem(QString::number(row + 1))); row++; } while(res.accessTuple(ResultSet::NextTuple)); } results_tbw->setUpdatesEnabled(true); results_tbw->blockSignals(false); results_tbw->resizeColumnsToContents(); results_tbw->resizeRowsToContents(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SQLExecutionWidget::handleExecutionAborted(Exception e) { QString time_str=QString("[%1]:").arg(QTime::currentTime().toString(QString("hh:mm:ss.zzz"))); switchToExecutionMode(false); msgoutput_lst->clear(); PgModelerUiNs::createOutputListItem(msgoutput_lst, PgModelerUiNs::formatMessage(QString("%1 %2").arg(time_str).arg(e.getErrorMessage())), QPixmap(PgModelerUiNs::getIconPath("msgbox_erro"))); if(e.getErrorCode()==ErrorCode::ConnectionTimeout || e.getErrorCode()==ErrorCode::ConnectionBroken) { PgModelerUiNs::createOutputListItem(msgoutput_lst, QString("%1 %2").arg(time_str).arg(trUtf8("No results retrieved or changes done due to the error above! Run the command again.")), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), false); } msgoutput_lst->setVisible(true); results_parent->setVisible(false); export_tb->setEnabled(false); filter_tb->setEnabled(false); filter_tb->setChecked(false); output_tbw->setTabText(0, trUtf8("Results")); output_tbw->setTabText(1, trUtf8("Messages (%1)").arg(msgoutput_lst->count())); output_tbw->setCurrentIndex(1); output_tbw->setTabEnabled(0, false); addToSQLHistory(sql_cmd_txt->toPlainText(), 0, e.getErrorMessage()); } void SQLExecutionWidget::finishExecution(int rows_affected) { if(sql_exec_hlp.isCancelled()) destroyResultModel(); else { bool empty = false; ResultSetModel *res_model = sql_exec_hlp.getResultSetModel(); end_exec=QDateTime::currentDateTime().toMSecsSinceEpoch(); total_exec = end_exec - start_exec; results_tbw->setSortingEnabled(false); results_tbw->blockSignals(true); results_tbw->setUpdatesEnabled(false); destroyResultModel(); results_tbw->setModel(res_model); results_tbw->resizeColumnsToContents(); results_tbw->setUpdatesEnabled(true); results_tbw->blockSignals(false); filter_edt->blockSignals(true); filter_edt->clear(); filter_edt->blockSignals(false); columns_cmb->blockSignals(true); columns_cmb->clear(); for(int col = 0; res_model && col < res_model->columnCount(QModelIndex()); col++) columns_cmb->addItem(res_model->headerData(col, Qt::Horizontal, Qt::DisplayRole).toString()); columns_cmb->blockSignals(false); addToSQLHistory(sql_cmd_txt->toPlainText(), rows_affected); empty = (!res_model || res_model->rowCount() == 0); output_tbw->setTabEnabled(0, !empty); results_parent->setVisible(!empty); export_tb->setEnabled(!empty); filter_tb->setEnabled(!empty); if(!empty) { output_tbw->setTabText(0, trUtf8("Results (%1)").arg(res_model->rowCount())); output_tbw->setCurrentIndex(0); } else { output_tbw->setTabText(0, trUtf8("Results")); output_tbw->setCurrentIndex(1); } msgoutput_lst->clear(); for(QString notice : sql_exec_hlp.getNotices()) { PgModelerUiNs::createOutputListItem(msgoutput_lst, QString("[%1]: %2").arg(QTime::currentTime().toString(QString("hh:mm:ss.zzz"))).arg(notice.trimmed()), QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")), false); } PgModelerUiNs::createOutputListItem(msgoutput_lst, PgModelerUiNs::formatMessage(trUtf8("[%1]: SQL command successfully executed in %2. %3 %4") .arg(QTime::currentTime().toString(QString("hh:mm:ss.zzz"))) .arg(total_exec >= 1000 ? QString("%1 s").arg(total_exec/1000.0) : QString("%1 ms").arg(total_exec)) .arg(!res_model ? trUtf8("Rows affected") : trUtf8("Rows retrieved")) .arg(rows_affected)), QPixmap(PgModelerUiNs::getIconPath("msgbox_info"))); output_tbw->setTabText(1, trUtf8("Messages (%1)").arg(msgoutput_lst->count())); } switchToExecutionMode(false); sql_exec_thread.quit(); } void SQLExecutionWidget::filterResults(void) { QModelIndexList list; Qt::MatchFlags flags = Qt::MatchStartsWith; int rows_cnt = results_tbw->model()->rowCount(); if(exact_chk->isChecked()) flags = Qt::MatchExactly; else if(regexp_chk->isChecked()) flags = Qt::MatchRegExp; else flags = Qt::MatchContains; if(case_sensitive_chk->isChecked()) flags |= Qt::MatchCaseSensitive; list = results_tbw->model()->match(results_tbw->model()->index(0, columns_cmb->currentIndex()), Qt::DisplayRole, filter_edt->text(), -1, flags); results_tbw->blockSignals(true); results_tbw->setUpdatesEnabled(false); for(int row = 0; row < rows_cnt; row++) results_tbw->hideRow(row); if(!list.isEmpty()) { for(auto &idx : list) results_tbw->showRow(idx.row()); } results_tbw->blockSignals(false); results_tbw->setUpdatesEnabled(true); results_tbw->update(); } void SQLExecutionWidget::addToSQLHistory(const QString &cmd, unsigned rows, const QString &error) { if(!cmd.isEmpty()) { QString fmt_cmd; if(!cmd_history_txt->toPlainText().isEmpty()) fmt_cmd += QString("\n"); fmt_cmd += QString("-- %1 [%2] -- \n") .arg(trUtf8("Executed at")) .arg(QDateTime::currentDateTime().toString(QString("yyyy-MM-dd hh:mm:ss.zzz"))); fmt_cmd += cmd; fmt_cmd += QChar('\n'); if(!error.isEmpty()) { fmt_cmd += QString("-- %1 --\n").arg(trUtf8("Command failed")); fmt_cmd += QString("/*\n%1\n*/\n").arg(error); } else fmt_cmd += QString("-- %1 %2\n").arg(trUtf8("Rows:")).arg(rows); if(!fmt_cmd.trimmed().endsWith(Attributes::DdlEndToken)) fmt_cmd += Attributes::DdlEndToken + QChar('\n'); SQLExecutionWidget::validateSQLHistoryLength(sql_cmd_conn.getConnectionId(true,true), fmt_cmd, cmd_history_txt); } } void SQLExecutionWidget::validateSQLHistoryLength(const QString &conn_id, const QString &fmt_cmd, NumberedTextEditor *cmd_history_txt) { QString cmds; int ln_count = 0; cmds = cmd_history[conn_id]; ln_count = cmds.count(QChar('\n')); ln_count += fmt_cmd.count(QChar('\n')); if(ln_count > cmd_history_max_len) { QStringList buffer = cmds.split(QChar('\n')); cmds = buffer.mid(buffer.size()/2).join(QChar('\n')); cmds = cmds.mid(cmds.indexOf(Attributes::DdlEndToken) + Attributes::DdlEndToken.length()); cmd_history[conn_id] = cmds.trimmed(); if(cmd_history_txt) { cmd_history_txt->clear(); cmd_history_txt->appendPlainText(cmds); } } cmd_history[conn_id].append(fmt_cmd); if(cmd_history_txt) cmd_history_txt->appendPlainText(fmt_cmd); } void SQLExecutionWidget::switchToExecutionMode(bool value) { run_sql_tb->setVisible(!value); stop_tb->setVisible(value); file_tb->setEnabled(!value); find_tb->setEnabled(!value); clear_btn->setEnabled(!value); snippets_tb->setEnabled(!value); export_tb->setEnabled(!value); output_tb->setEnabled(!value); sql_cmd_txt->setEnabled(!value); cmd_history_parent->setEnabled(!value); find_history_parent->setEnabled(!value); filter_tb->setEnabled(!value); if(value) { this->setCursor(Qt::WaitCursor); sql_cmd_txt->setCursor(Qt::WaitCursor); sql_cmd_txt->clearFocus(); } else { this->setCursor(Qt::ArrowCursor); sql_cmd_txt->setCursor(Qt::ArrowCursor); sql_cmd_txt->setFocus(); } } void SQLExecutionWidget::destroyResultModel(void) { if(results_tbw->model()) { ResultSetModel *result_model = dynamic_cast(results_tbw->model()); results_tbw->blockSignals(true); results_tbw->setModel(nullptr); delete(result_model); results_tbw->blockSignals(false); } } void SQLExecutionWidget::runSQLCommand(void) { QString cmd=sql_cmd_txt->textCursor().selectedText(); output_tb->setChecked(true); if(cmd.isEmpty()) cmd=sql_cmd_txt->toPlainText(); else cmd.replace(QChar::ParagraphSeparator, '\n'); msgoutput_lst->clear(); sql_exec_hlp.setCommand(cmd); start_exec=QDateTime::currentDateTime().toMSecsSinceEpoch(); sql_exec_thread.start(); switchToExecutionMode(true); output_tbw->setTabEnabled(0, false); output_tbw->setTabText(0, trUtf8("Results")); output_tbw->setCurrentIndex(1); PgModelerUiNs::createOutputListItem(msgoutput_lst, trUtf8("[%1]: SQL command is running...") .arg(QTime::currentTime().toString(QString("hh:mm:ss.zzz"))), QPixmap(PgModelerUiNs::getIconPath("msgbox_info")), false); } void SQLExecutionWidget::saveCommands(void) { bool browse_file = (sender() == action_save_as || filename_edt->text().isEmpty()); QString filename = filename_edt->text(); if(browse_file) { sql_file_dlg.setWindowTitle(trUtf8("Save SQL commands")); sql_file_dlg.setAcceptMode(QFileDialog::AcceptSave); sql_file_dlg.exec(); if(sql_file_dlg.result()==QDialog::Accepted) filename = sql_file_dlg.selectedFiles().at(0); } else filename = filename_edt->text(); if(!filename.isEmpty()) { QFile file; file.setFileName(filename); if(!file.open(QFile::WriteOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(filename), ErrorCode::FileDirectoryNotAccessed ,__PRETTY_FUNCTION__,__FILE__,__LINE__); file.write(sql_cmd_txt->toPlainText().toUtf8()); file.close(); filename_edt->setText(filename); filename_wgt->setVisible(true); } } void SQLExecutionWidget::loadCommands(void) { sql_file_dlg.setWindowTitle(trUtf8("Load SQL commands")); sql_file_dlg.setAcceptMode(QFileDialog::AcceptOpen); sql_file_dlg.exec(); if(sql_file_dlg.result()==QDialog::Accepted) { QFile file; file.setFileName(sql_file_dlg.selectedFiles().at(0)); if(!file.open(QFile::ReadOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed) .arg(sql_file_dlg.selectedFiles().at(0)), ErrorCode::FileDirectoryNotAccessed ,__PRETTY_FUNCTION__,__FILE__,__LINE__); sql_cmd_txt->clear(); sql_cmd_txt->setPlainText(file.readAll()); file.close(); filename_edt->setText(sql_file_dlg.selectedFiles().at(0)); filename_wgt->setVisible(true); } } void SQLExecutionWidget::exportResults(QTableView *results_tbw) { if(!results_tbw) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); QFileDialog csv_file_dlg; csv_file_dlg.setDefaultSuffix(QString("csv")); csv_file_dlg.setFileMode(QFileDialog::AnyFile); csv_file_dlg.setWindowTitle(trUtf8("Save CSV file")); csv_file_dlg.setNameFilter(trUtf8("Comma-separated values file (*.csv);;All files (*.*)")); csv_file_dlg.setModal(true); csv_file_dlg.setAcceptMode(QFileDialog::AcceptSave); csv_file_dlg.exec(); if(csv_file_dlg.result()==QDialog::Accepted) { QFile file; file.setFileName(csv_file_dlg.selectedFiles().at(0)); if(!file.open(QFile::WriteOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed) .arg(csv_file_dlg.selectedFiles().at(0)), ErrorCode::FileDirectoryNotAccessed ,__PRETTY_FUNCTION__,__FILE__,__LINE__); QApplication::setOverrideCursor(Qt::WaitCursor); results_tbw->setUpdatesEnabled(false); results_tbw->blockSignals(true); results_tbw->selectAll(); file.write(generateCSVBuffer(results_tbw)); file.close(); results_tbw->clearSelection(); results_tbw->blockSignals(false); results_tbw->setUpdatesEnabled(true); QApplication::restoreOverrideCursor(); } } int SQLExecutionWidget::clearAll(void) { Messagebox msg_box; int res = 0; msg_box.show(trUtf8("The SQL input field and the results grid will be cleared! Want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); res = msg_box.result(); if(res==QDialog::Accepted) { sql_cmd_txt->setPlainText(QString()); msgoutput_lst->clear(); msgoutput_lst->setVisible(true); results_parent->setVisible(false); export_tb->setEnabled(false); } return(res); } QByteArray SQLExecutionWidget::generateCSVBuffer(QTableView *results_tbw) { return(generateBuffer(results_tbw, QChar(';'), true, true, true)); } QByteArray SQLExecutionWidget::generateTextBuffer(QTableView *results_tbw) { return(generateBuffer(results_tbw, QChar('\t'), false, false, false)); } QByteArray SQLExecutionWidget::generateBuffer(QTableView *results_tbw, QChar separator, bool incl_col_names, bool use_quotes, bool escape_chars) { if(!results_tbw) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!results_tbw->selectionModel()) return (QByteArray()); QAbstractItemModel *model = results_tbw->model(); QModelIndexList sel_indexes = results_tbw->selectionModel()->selectedIndexes(); QByteArray buf; QStringList line; QModelIndex index; QString str_pattern = use_quotes ? QString("\"%1\"") : QString("%1"), value; int start_row = -1, start_col = -1, row_cnt = 0, col_cnt = 0; start_row = sel_indexes.at(0).row(); start_col = sel_indexes.at(0).column(); row_cnt = (sel_indexes.last().row() - start_row) + 1; col_cnt = (sel_indexes.last().column() - start_col) + 1; int col=0, row=0, max_col=start_col + col_cnt, max_row=start_row + row_cnt; if(incl_col_names) { //Creating the header for(col=start_col; col < max_col; col++) { if(results_tbw->isColumnHidden(col)) continue; value = model->headerData(col, Qt::Horizontal).toString(); if(escape_chars) { value.replace(separator, QString("\\%1").arg(separator)); value.replace(QChar::Tabulation, QString("\\t")); value.replace(QChar::LineFeed, QString("\\n")); if(use_quotes) value.replace('"', QString("\\%1").arg('"')); } line.append(str_pattern.arg(value)); } buf.append(line.join(separator)); buf.append('\n'); line.clear(); } //Creating the content for(row=start_row; row < max_row; row++) { for(col=start_col; col < max_col; col++) { if(results_tbw->isColumnHidden(col)) continue; index = model->index(row, col); value = index.data().toString(); if(escape_chars) { value.replace(separator, QString("\\%1").arg(separator)); value.replace(QChar::Tabulation, QString("\\t")); value.replace(QChar::LineFeed, QString("\\n")); if(use_quotes) value.replace('"', QString("\\%1").arg('"')); } line.append(str_pattern.arg(value)); } buf.append(line.join(separator)); line.clear(); buf.append('\n'); } return(buf); } void SQLExecutionWidget::copySelection(QTableView *results_tbw, bool use_popup, bool csv_is_default) { if(!results_tbw) throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__); QItemSelectionModel *selection = results_tbw->selectionModel(); if(selection && (!use_popup || (use_popup && QApplication::mouseButtons()==Qt::RightButton))) { QMenu copy_menu, copy_mode_menu; QAction *act = nullptr, *act_csv = nullptr, *act_txt = nullptr; if(use_popup) { act = copy_menu.addAction(trUtf8("Copy selection")); act_txt = copy_mode_menu.addAction(trUtf8("Plain format")); act_csv = copy_mode_menu.addAction(trUtf8("CVS format")); act->setMenu(©_mode_menu); act = copy_menu.exec(QCursor::pos()); } if(!use_popup || act) { QByteArray buf; if((use_popup && act == act_csv) || (!use_popup && csv_is_default)) { //Generates the csv buffer and assigns it to application's clipboard buf=generateCSVBuffer(results_tbw); } else if((use_popup && act == act_txt) || (!use_popup && !csv_is_default)) { buf=generateTextBuffer(results_tbw); } qApp->clipboard()->setText(buf); } } } void SQLExecutionWidget::selectSnippet(QAction *act) { QTextCursor cursor=sql_cmd_txt->textCursor(); cursor.movePosition(QTextCursor::End); sql_cmd_txt->appendPlainText(SnippetsConfigWidget::getParsedSnippet(act->text())); sql_cmd_txt->setTextCursor(cursor); } void SQLExecutionWidget::toggleOutputPane(bool visible) { if(!visible) { v_splitter->handle(1)->setCursor(Qt::ArrowCursor); v_splitter->handle(1)->setEnabled(false); } else v_splitter->handle(1)->setCursor(Qt::SplitVCursor); v_splitter->handle(1)->setEnabled(visible); output_wgt->setVisible(visible); if(!visible) /* Force the splitter size to be the same as the sql_cmd_wgt maximum height in order to force the splitter to the bottom, hiding the output pane */ v_splitter->setSizes({sql_cmd_wgt->maximumHeight(), 0}); else //Restore the splitter to the default size v_splitter->setSizes({700, 300}); } void SQLExecutionWidget::configureSnippets(void) { SnippetsConfigWidget::configureSnippetsMenu(&snippets_menu); code_compl_wgt->configureCompletion(nullptr, sql_cmd_hl); } void SQLExecutionWidget::saveSQLHistory(void) { try { SchemaParser schparser; attribs_map attribs; QString commands; QByteArray buffer; QFile file; for(auto hist : cmd_history) { attribs[Attributes::Connection] = hist.first; attribs[Attributes::Commands] = hist.second; schparser.ignoreEmptyAttributes(true); commands += schparser.getCodeDefinition(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + Attributes::Commands + GlobalAttributes::SchemaExt, attribs); } schparser.loadFile(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator + GlobalAttributes::SQLHistoryConf + GlobalAttributes::SchemaExt); attribs.clear(); attribs[Attributes::Commands] = commands; buffer.append(schparser.getCodeDefinition(attribs)); file.setFileName(GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::SQLHistoryConf + GlobalAttributes::ConfigurationExt); if(!file.open(QFile::WriteOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(file.fileName()), ErrorCode::FileDirectoryNotAccessed, __PRETTY_FUNCTION__, __FILE__ ,__LINE__); file.write(buffer); file.close(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SQLExecutionWidget::loadSQLHistory(void) { try { XmlParser xmlparser; attribs_map attribs; xmlparser.setDTDFile(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectDTDDir + GlobalAttributes::DirSeparator + GlobalAttributes::SQLHistoryConf + GlobalAttributes::ObjectDTDExt, GlobalAttributes::SQLHistoryConf); xmlparser.loadXMLFile(GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::SQLHistoryConf + GlobalAttributes::ConfigurationExt); cmd_history.clear(); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementName() == Attributes::Commands) { xmlparser.getElementAttributes(attribs); xmlparser.savePosition(); if(xmlparser.accessElement(XmlParser::ChildElement)) cmd_history[attribs[Attributes::Connection]].append(xmlparser.getElementContent()); xmlparser.restorePosition(); } } while(xmlparser.accessElement(XmlParser::NextElement)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SQLExecutionWidget::destroySQLHistory(void) { Messagebox msg_box; msg_box.show(trUtf8("This action will wipe out all the SQL commands history for all connections! Do you really want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result() == QDialog::Accepted) { QFile::remove(GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::SQLHistoryConf + GlobalAttributes::ConfigurationExt); SQLExecutionWidget::cmd_history.clear(); } } void SQLExecutionWidget::setSQLHistoryMaxLength(int len) { if(len < 1000 || len > 20000) len = 1000; SQLExecutionWidget::cmd_history_max_len = len; } int SQLExecutionWidget::getSQLHistoryMaxLength(void) { return(SQLExecutionWidget::cmd_history_max_len); } void SQLExecutionWidget::enableSQLExecution(bool enable) { try { sql_cmd_txt->setEnabled(enable); snippets_tb->setEnabled(enable); clear_btn->setEnabled(enable && !sql_cmd_txt->toPlainText().isEmpty()); run_sql_tb->setEnabled(enable && !sql_cmd_txt->toPlainText().isEmpty()); find_tb->setEnabled(enable); find_wgt_parent->setEnabled(enable); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SQLExecutionWidget::showHistoryContextMenu(void) { QMenu *ctx_menu=cmd_history_txt->createStandardContextMenu(); QAction *action_clear = new QAction(QPixmap(PgModelerUiNs::getIconPath("limpartexto")), trUtf8("Clear history"), ctx_menu), *action_save = new QAction(QPixmap(PgModelerUiNs::getIconPath("salvar")), trUtf8("Save history"), ctx_menu), *action_reload = new QAction(QPixmap(PgModelerUiNs::getIconPath("atualizar")), trUtf8("Reload history"), ctx_menu), *action_toggle_find = nullptr, *exec_act = nullptr; if(!find_history_parent->isVisible()) action_toggle_find = new QAction(QPixmap(PgModelerUiNs::getIconPath("buscar")), trUtf8("Find in history"), ctx_menu); else action_toggle_find = new QAction(trUtf8("Hide find tool"), ctx_menu); ctx_menu->addSeparator(); ctx_menu->addAction(action_toggle_find); ctx_menu->addAction(action_reload); ctx_menu->addAction(action_save); ctx_menu->addSeparator(); ctx_menu->addAction(action_clear); exec_act = ctx_menu->exec(QCursor::pos()); if(exec_act == action_clear) { Messagebox msg_box; msg_box.show(trUtf8("This action will wipe out all the SQL commands history for the current connection! Do you really want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result() == QDialog::Accepted) { cmd_history_txt->clear(); cmd_history[sql_cmd_conn.getConnectionId(true,true)].clear(); } } else if(exec_act == action_save) SQLExecutionWidget::saveSQLHistory(); else if(exec_act == action_reload) { SQLExecutionWidget::loadSQLHistory(); cmd_history_txt->clear(); cmd_history_txt->appendPlainText(cmd_history[sql_cmd_conn.getConnectionId(true,true)]); cmd_history_hl->rehighlight(); } else if(exec_act == action_toggle_find) find_history_parent->setVisible(!find_history_parent->isVisible()); delete(ctx_menu); } pgmodeler-0.9.2/libpgmodeler_ui/src/sqlexecutionwidget.h000066400000000000000000000130741360462764600235540ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SQLExecutionWidget \brief Implements the operations that permit user to perform basic SQL commands directly on a server */ #ifndef SQL_EXECUTION_WIDGET_H #define SQL_EXECUTION_WIDGET_H #include "ui_sqlexecutionwidget.h" #include "syntaxhighlighter.h" #include "connection.h" #include "databaseimportform.h" #include "findreplacewidget.h" #include "codecompletionwidget.h" #include "numberedtexteditor.h" #include "findreplacewidget.h" #include "resultsetmodel.h" #include "sqlexecutionhelper.h" class SQLExecutionWidget: public QWidget, public Ui::SQLExecutionWidget { private: Q_OBJECT static map cmd_history; static int cmd_history_max_len; qint64 start_exec, end_exec, total_exec; SchemaParser schparser; QThread sql_exec_thread; SQLExecutionHelper sql_exec_hlp; //! \brief Syntax highlighter for sql input field SyntaxHighlighter *sql_cmd_hl, //! \brief Syntax highlighter for command history field *cmd_history_hl; //! \brief Connection used to run commands specified on sql input field Connection sql_cmd_conn; //! \brief Dialog for SQL save/load QFileDialog sql_file_dlg; QMenu snippets_menu, file_menu; QAction *action_save, *action_save_as, *action_load; FindReplaceWidget *find_replace_wgt; CodeCompletionWidget *code_compl_wgt; FindReplaceWidget *find_history_wgt; /*! \brief Enables/Disables the fields for sql input and execution. When enabling a new connection to server will be opened. */ void enableSQLExecution(bool enable); //! \brief Stores the command on the sql command history void addToSQLHistory(const QString &cmd, unsigned rows=0, const QString &error=QString()); static void validateSQLHistoryLength(const QString &conn_id, const QString &fmt_cmd = QString(), NumberedTextEditor *cmd_history_txt = nullptr); void switchToExecutionMode(bool value); void destroyResultModel(void); protected: //! \brief Widget that serves as SQL commands input NumberedTextEditor *sql_cmd_txt, *cmd_history_txt; void showEvent(QShowEvent *); void resizeEvent(QResizeEvent *); bool eventFilter(QObject *object, QEvent *event); public: static const QString ColumnNullValue; SQLExecutionWidget(QWidget * parent = nullptr); ~SQLExecutionWidget(void); //! \brief Configures the connection to query the server void setConnection(Connection conn); //! \brief Insert the provided sql commands in the input field. This method clears the current commands before adding new content void setSQLCommand(const QString &sql); /*! \brief Fills up the results grid based upon the specified result set. The parameter store_data will make each item store the text as its data */ static void fillResultsTable(Catalog &catalog, ResultSet &res, QTableWidget *results_tbw, bool store_data=false); //! \brief Copy to clipboard (in csv format) the current selected items on results grid static void copySelection(QTableView *results_tbw, bool use_popup=true, bool csv_is_default = false); //! \brief Generates a CSV buffer based upon the selection on the results grid static QByteArray generateCSVBuffer(QTableView *results_tbw); //! \brief Generates a Plain text buffer based upon the selection on the results grid (this method does not include the column names) static QByteArray generateTextBuffer(QTableView *results_tbw); //! \brief Generates a custom text buffer. User can specify a separator for columns, include column names and quote values static QByteArray generateBuffer(QTableView *results_tbw, QChar separator, bool incl_col_names, bool use_quotes, bool escape_chars); //! \brief Exports the results to csv file static void exportResults(QTableView *results_tbw); //! \brief Save the history of all connections open in the SQL Execution to the sql-history.conf static void saveSQLHistory(void); //! \brief Load the history from the file sql-history.conf static void loadSQLHistory(void); static void destroySQLHistory(void); static void setSQLHistoryMaxLength(int len); static int getSQLHistoryMaxLength(void); public slots: void configureSnippets(void); //! \brief Show the exception message in the output widget void handleExecutionAborted(Exception e); private slots: //! \brief Enables the command buttons when user fills the sql field void enableCommandButtons(void); //! \brief Runs the current typed sql command void runSQLCommand(void); //! \brief Save the current typed sql command on a file void saveCommands(void); //! \brief Load a sql command from a file void loadCommands(void); //! \brief Clears the input field as well the results grid int clearAll(void); void selectSnippet(QAction *act); void toggleOutputPane(bool visible); void showHistoryContextMenu(void); void finishExecution(int rows_affected = 0); void filterResults(void); friend class SQLToolWidget; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/sqltoolwidget.cpp000066400000000000000000000327311360462764600230620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "sqltoolwidget.h" #include "taskprogresswidget.h" #include "snippetsconfigwidget.h" #include "connectionsconfigwidget.h" #include "pgmodeleruins.h" SQLToolWidget::SQLToolWidget(QWidget * parent) : QWidget(parent) { setupUi(this); h_splitter->setSizes({315, 10000}); h_splitter->handle(1)->installEventFilter(this); v_splitter->setSizes({1000, 400}); sql_exec_corner_btn = new QToolButton; sql_exec_corner_btn->setIcon(QPixmap(PgModelerUiNs::getIconPath("newtab"))); sql_exec_corner_btn->setIconSize(QSize(18, 18)); sql_exec_corner_btn->setStyleSheet("QToolButton { margin-left: 4px; margin-bottom: 4px; padding: 2px; }"); sql_exec_corner_btn->setShortcut(QKeySequence("Ctrl+T")); sql_exec_corner_btn->setToolTip(trUtf8("Add a new execution tab for the current database (%1)").arg(sql_exec_corner_btn->shortcut().toString())); sql_exec_tbw->setCornerWidget(sql_exec_corner_btn, Qt::TopRightCorner); QVBoxLayout *vbox=new QVBoxLayout; sourcecode_txt=new NumberedTextEditor(sourcecode_gb); sourcecode_txt->setReadOnly(true); sourcecode_hl=new SyntaxHighlighter(sourcecode_txt); sourcecode_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); vbox->setContentsMargins(4,4,4,4); vbox->addWidget(sourcecode_txt); sourcecode_gb->setLayout(vbox); connect(connections_cmb, SIGNAL(activated(int)), this, SLOT(connectToServer(void))); connect(refresh_tb, SIGNAL(clicked(void)), this, SLOT(connectToServer(void))); connect(databases_tbw, SIGNAL(tabCloseRequested(int)), this, SLOT(closeDatabaseExplorer(int))); connect(sql_exec_tbw, SIGNAL(tabCloseRequested(int)), this, SLOT(closeSQLExecutionTab(int))); connect(database_cmb, SIGNAL(activated(int)), this, SLOT(browseDatabase())); connect(disconnect_tb, SIGNAL(clicked()), this, SLOT(disconnectFromDatabases())); connect(source_pane_tb, SIGNAL(toggled(bool)), sourcecode_gb, SLOT(setVisible(bool))); connect(sql_exec_corner_btn, SIGNAL(clicked(bool)), this, SLOT(addSQLExecutionTab())); connect(databases_tbw, &QTabWidget::currentChanged, [&](){ DatabaseExplorerWidget *dbexplorer=qobject_cast(databases_tbw->currentWidget()); QMap ::iterator itr=sql_exec_wgts.begin(); sourcecode_txt->clear(); if(dbexplorer && dbexplorer->objects_trw->currentItem()) sourcecode_txt->setPlainText(dbexplorer->objects_trw->currentItem()-> data(DatabaseImportForm::ObjectSource, Qt::UserRole).toString()); while(itr != sql_exec_wgts.end()) { if(itr.key() != dbexplorer) { for(auto &wgt : itr.value()) sql_exec_tbw->removeTab(sql_exec_tbw->indexOf(wgt)); } else { for(auto &wgt : itr.value()) sql_exec_tbw->addTab(wgt, dbexplorer->getConnection().getConnectionParam(Connection::ParamDbName)); } itr++; } disconnect_tb->setEnabled(databases_tbw->count() > 0); }); } SQLToolWidget::~SQLToolWidget(void) { databases_tbw->blockSignals(true); while(databases_tbw->count() > 0) closeDatabaseExplorer(0); } bool SQLToolWidget::eventFilter(QObject *object, QEvent *event) { if(event->type() == QEvent::MouseButtonDblClick && qobject_cast(object) == h_splitter->handle(1)) { if(h_splitter->sizes().at(0) != 0) h_splitter->setSizes({0, 10000}); else h_splitter->setSizes({315, 10000}); return(true); } return(QWidget::eventFilter(object, event)); } void SQLToolWidget::updateTabs(void) { SQLExecutionWidget *sql_exec_wgt=nullptr; for(int i=0; i < sql_exec_tbw->count(); i++) { sql_exec_wgt=dynamic_cast(sql_exec_tbw->widget(i)); sql_exec_wgt->sql_cmd_txt->updateLineNumbersSize(); sql_exec_wgt->sql_cmd_txt->updateLineNumbers(); sql_exec_wgt->sql_cmd_hl->rehighlight(); //Forcing the update of the sql history widget (see SQLExecutionWidget::eventFilter) sql_exec_wgt->output_tbw->widget(2)->hide(); sql_exec_wgt->output_tbw->widget(2)->show(); } } void SQLToolWidget::configureSnippets(void) { SQLExecutionWidget *sql_exec_wgt=nullptr; for(int i=0; i < sql_exec_tbw->count(); i++) { sql_exec_wgt=dynamic_cast(sql_exec_tbw->widget(i)); sql_exec_wgt->configureSnippets(); } } void SQLToolWidget::clearDatabases() { database_cmb->clear(); database_cmb->setEnabled(false); refresh_tb->setEnabled(false); } void SQLToolWidget::connectToServer(void) { try { if(connections_cmb->currentIndex()==connections_cmb->count()-1) { ConnectionsConfigWidget::openConnectionsConfiguration(connections_cmb, true); emit s_connectionsUpdateRequest(); } else { Connection *conn=reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value()); clearDatabases(); if(conn) { import_helper.setConnection(*conn); DatabaseImportForm::listDatabases(import_helper, database_cmb); import_helper.closeConnection(); if(sender()==connections_cmb && conn->isAutoBrowseDB()) { database_cmb->setCurrentText(conn->getConnectionParam(Connection::ParamDbName)); browseDatabase(); } } database_cmb->setEnabled(database_cmb->count() > 1); refresh_tb->setEnabled(database_cmb->isEnabled()); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SQLToolWidget::disconnectFromDatabases(void) { try { Messagebox msg_box; msg_box.show(trUtf8("Warning"), trUtf8("ATTENTION: Disconnect from all databases will close any opened tab in this view! Do you really want to proceed?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { database_cmb->clear(); connections_cmb->setEnabled(true); refresh_tb->setEnabled(false); while(databases_tbw->count() > 0) { databases_tbw->blockSignals(true); closeDatabaseExplorer(0); databases_tbw->blockSignals(false); } connections_cmb->setCurrentIndex(0); disconnect_tb->setEnabled(false); sourcecode_txt->clear(); } } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SQLToolWidget::handleDatabaseDropped(const QString &dbname) { try { //Closing tabs related to the database to be dropped for(int i=0; i < databases_tbw->count(); i++) { if(databases_tbw->tabText(i).remove('&') == dbname) { closeDatabaseExplorer(i); i=-1; } } connectToServer(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } DatabaseExplorerWidget *SQLToolWidget::browseDatabase(void) { try { DatabaseExplorerWidget *db_explorer_wgt=nullptr; //If the selected database is already being browse do not create another explorer instance if(database_cmb->currentIndex() > 0) { Connection conn=(*reinterpret_cast(connections_cmb->itemData(connections_cmb->currentIndex()).value())); QString maintainance_db=conn.getConnectionParam(Connection::ParamDbName); db_explorer_wgt=new DatabaseExplorerWidget; db_explorer_wgt->setObjectName(database_cmb->currentText()); conn.setConnectionParam(Connection::ParamDbName, database_cmb->currentText()); db_explorer_wgt->setConnection(conn, maintainance_db); db_explorer_wgt->listObjects(); databases_tbw->addTab(db_explorer_wgt, database_cmb->currentText()); databases_tbw->setTabToolTip(databases_tbw->count() - 1, db_explorer_wgt->getConnection().getConnectionId(true, true)); databases_tbw->setCurrentWidget(db_explorer_wgt); connect(db_explorer_wgt, SIGNAL(s_databaseDropped(QString)), this, SLOT(handleDatabaseDropped(QString))); connect(db_explorer_wgt, SIGNAL(s_sqlExecutionRequested()), this, SLOT(addSQLExecutionTab())); connect(db_explorer_wgt, SIGNAL(s_snippetShowRequested(QString)), this, SLOT(showSnippet(QString))); connect(db_explorer_wgt, SIGNAL(s_sourceCodeShowRequested(QString)), sourcecode_txt, SLOT(setPlainText(QString))); connect(attributes_tb, SIGNAL(toggled(bool)), db_explorer_wgt->attributes_wgt, SLOT(setVisible(bool))); db_explorer_wgt->attributes_wgt->setVisible(attributes_tb->isChecked()); /* Forcing the signal s_sqlExecutionRequested to be emitted to properly register the new tab on the map of sql panes related to the database explorer */ db_explorer_wgt->runsql_tb->click(); } return(db_explorer_wgt); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } SQLExecutionWidget *SQLToolWidget::addSQLExecutionTab(const QString &sql_cmd) { try { SQLExecutionWidget *sql_exec_wgt = nullptr; DatabaseExplorerWidget *db_explorer_wgt=dynamic_cast(databases_tbw->currentWidget()); Connection conn; if(!db_explorer_wgt) return(nullptr); sql_exec_wgt = new SQLExecutionWidget; conn = db_explorer_wgt->getConnection(); sql_exec_wgt->setConnection(conn); sql_exec_tbw->addTab(sql_exec_wgt, conn.getConnectionParam(Connection::ParamDbName)); sql_exec_tbw->setCurrentWidget(sql_exec_wgt); sql_exec_tbw->currentWidget()->layout()->setContentsMargins(4,4,4,4); sql_exec_wgt->sql_cmd_txt->appendPlainText(sql_cmd); sql_exec_wgts[db_explorer_wgt].push_back(sql_exec_wgt); return(sql_exec_wgt); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void SQLToolWidget::addSQLExecutionTab(const QString &conn_id, const QString &database, const QString &sql_file) { map conns; SQLExecutionWidget *sql_exec_wgt = nullptr; DatabaseExplorerWidget *db_explorer_wgt = nullptr; QFile file; if(!ConnectionsConfigWidget::getConnection(conn_id)) { throw Exception(trUtf8("Failed to load the file `%1' in SQL tool because the connection ID `%2' was not found!") .arg(sql_file).arg(conn_id), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(!QFileInfo(sql_file).exists()) { throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(sql_file), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); } // Connect to the server using the provided connection id connections_cmb->setCurrentText(conn_id); connectToServer(); // Browse the database and retrive the database explorer instace generated database_cmb->setCurrentText(database); db_explorer_wgt = browseDatabase(); /* Now we get the sql execution widget created from the previous operation * in order to load the sql file there */ sql_exec_wgt = dynamic_cast(sql_exec_wgts[db_explorer_wgt].at(0)); file.setFileName(sql_file); file.open(QFile::ReadOnly); sql_exec_wgt->setSQLCommand(file.readAll()); file.close(); } void SQLToolWidget::closeDatabaseExplorer(int idx) { DatabaseExplorerWidget *db_explorer=dynamic_cast(databases_tbw->widget(idx)); /* Display a message box confirming the database explorer tab only if the user * click the close button on the DatabaseExplorerWidget instance */ if(sender() == databases_tbw) { Messagebox msg_box; msg_box.show(trUtf8("Warning"), trUtf8("ATTENTION: Close the database being browsed will close any opened SQL execution pane related to it! Do you really want to proceed?"), Messagebox::AlertIcon, Messagebox::YesNoButtons); if(msg_box.result() != QDialog::Accepted) return; } //Closing sql execution tabs related to the database to be closed for(QWidget *wgt : sql_exec_wgts[db_explorer]) { sql_exec_tbw->removeTab(sql_exec_tbw->indexOf(wgt)); delete(wgt); } sql_exec_wgts.remove(db_explorer); databases_tbw->removeTab(idx); if(db_explorer) delete(db_explorer); } void SQLToolWidget::closeSQLExecutionTab(int idx) { SQLExecutionWidget *sql_exec_wgt=dynamic_cast(sql_exec_tbw->widget(idx)); QMap ::iterator itr=sql_exec_wgts.begin(); int idx1=-1; //Removing the widget from the list it belongs while(itr!=sql_exec_wgts.end()) { idx1=itr.value().indexOf(sql_exec_wgt); if(idx1 >= 0) { itr.value().removeAt(idx1); break; } itr++; } sql_exec_tbw->removeTab(idx); if(sql_exec_wgt) delete(sql_exec_wgt); } void SQLToolWidget::showSnippet(const QString &snip) { SQLExecutionWidget *sql_exec_wgt=nullptr; if(sql_exec_tbw->count()==0) addSQLExecutionTab(); sql_exec_wgt=dynamic_cast(sql_exec_tbw->currentWidget()); if(sql_exec_wgt->sql_cmd_txt->isEnabled()) { QTextCursor cursor=sql_exec_wgt->sql_cmd_txt->textCursor(); cursor.movePosition(QTextCursor::End); sql_exec_wgt->sql_cmd_txt->appendPlainText(snip); sql_exec_wgt->sql_cmd_txt->setTextCursor(cursor); } } bool SQLToolWidget::hasDatabasesBrowsed(void) { return(databases_tbw->count() > 0); } pgmodeler-0.9.2/libpgmodeler_ui/src/sqltoolwidget.h000066400000000000000000000074711360462764600225320ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SQLToolWidget \brief Implements the operations that permit user to perform basic SQL commands directly on a server */ #ifndef SQL_TOOL_WIDGET_H #define SQL_TOOL_WIDGET_H #include "ui_sqltoolwidget.h" #include "syntaxhighlighter.h" #include "connection.h" #include "databaseimportform.h" #include "datamanipulationform.h" #include "findreplacewidget.h" #include "codecompletionwidget.h" #include "numberedtexteditor.h" #include "databaseexplorerwidget.h" #include "sqlexecutionwidget.h" class SQLToolWidget: public QWidget, public Ui::SQLToolWidget { private: Q_OBJECT QToolButton *sql_exec_corner_btn; NumberedTextEditor *sourcecode_txt; SyntaxHighlighter *sourcecode_hl; //! \brief Database import helper used to list objects from current connection DatabaseImportHelper import_helper; /*! \brief Controls the link between a database explorer instance and SQL execution widgets. When a database explorer is closed all the SQL execution panes related to it are closed too. (see addSQLExecutionTab and closeSQLExecutionTab for deitails) */ QMap sql_exec_wgts; bool eventFilter(QObject *object, QEvent *event); public: SQLToolWidget(QWidget * parent = nullptr); ~SQLToolWidget(void); //! \brief Force the update of the sql command input field and the syntax highligter attached to the opened tabs void updateTabs(void); //! \brief Indicates if there is at least one database being browsed through explorer widget bool hasDatabasesBrowsed(void); public slots: void configureSnippets(void); void clearDatabases(void); //! \brief Add a tab to permit the SQL execution for the current database being browsed SQLExecutionWidget *addSQLExecutionTab(const QString &sql_cmd = QString()); protected slots: //! \brief Add a tab by browsing a database in the specified connection, loads the sql file and put its contents on a SQL execution void addSQLExecutionTab(const QString &conn_id, const QString &database, const QString &sql_file); private slots: //! \brief Opens a connection to the selected server void connectToServer(void); //! \brief Disconnect from server and close any opened database explorer or sql execution tab void disconnectFromDatabases(void); //! \brief Removes all DatabaseExplorerWidget instances linked to the dropped database void handleDatabaseDropped(const QString &dbname); //! \brief Open the current database in a database explorer instance DatabaseExplorerWidget *browseDatabase(void); //! \brief Show the selected snippet on the current opened SQL execution tab void showSnippet(const QString &snip); //! \brief Close the database explorer specified by its index. Also, closes any SQL exec. tab related to it void closeDatabaseExplorer(int idx); //! \brief Close the SQL execution tab specified by its index void closeSQLExecutionTab(int idx); signals: /*! \brief This signal is emitted whenever the user changes the connections settings within this widget without use the main configurations dialog */ void s_connectionsUpdateRequest(void); friend class MainWindow; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/swapobjectsidswidget.cpp000066400000000000000000000243151360462764600244100ustar00rootroot00000000000000#include "swapobjectsidswidget.h" #include "pgmodeleruins.h" const QString SwapObjectsIdsWidget::IdLabel = QString("ID: %1"); SwapObjectsIdsWidget::SwapObjectsIdsWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { try { QGridLayout *swap_objs_grid=new QGridLayout(this); vector types=BaseObject::getObjectTypes(true, {ObjectType::Permission, ObjectType::Role, ObjectType::Textbox, ObjectType::Column, ObjectType::Constraint }); setupUi(this); PgModelerUiNs::configureWidgetFont(message_lbl, PgModelerUiNs::MediumFontFactor); selector_idx = 0; src_object_sel=nullptr; dst_object_sel=nullptr; src_object_sel=new ObjectSelectorWidget(types, true, this); src_object_sel->enableObjectCreation(false); dst_object_sel=new ObjectSelectorWidget(types, true, this); dst_object_sel->enableObjectCreation(false); swap_objs_grid->setContentsMargins(4,4,4,4); swap_objs_grid->setSpacing(6); swap_objs_grid->addWidget(create_lbl, 0, 0); swap_objs_grid->addWidget(src_object_sel, 0, 1); swap_objs_grid->addWidget(src_id_lbl, 0, 2); swap_objs_grid->addWidget(src_ico_lbl, 0, 3); swap_objs_grid->addWidget(before_lbl, 1, 0); swap_objs_grid->addWidget(dst_object_sel, 1, 1); swap_objs_grid->addWidget(dst_id_lbl, 1, 2); swap_objs_grid->addWidget(dst_ico_lbl, 1, 3); QHBoxLayout *hlayout=new QHBoxLayout; hlayout->addSpacerItem(new QSpacerItem(10,10, QSizePolicy::Expanding)); hlayout->addWidget(swap_values_tb); hlayout->addWidget(swap_ids_tb); hlayout->addSpacerItem(new QSpacerItem(10,10, QSizePolicy::Expanding)); swap_objs_grid->addLayout(hlayout, 2, 0, 1, 4); swap_objs_grid->addWidget(filter_wgt, swap_objs_grid->count(), 0, 1, 4); swap_objs_grid->addWidget(objects_tbw, swap_objs_grid->count(), 0, 1, 4); swap_objs_grid->addWidget(alert_frm, swap_objs_grid->count(), 0, 1, 4); setModel(nullptr); connect(src_object_sel, SIGNAL(s_objectSelected(void)), this, SLOT(showObjectId(void))); connect(dst_object_sel, SIGNAL(s_objectSelected(void)), this, SLOT(showObjectId(void))); connect(src_object_sel, SIGNAL(s_selectorCleared(void)), this, SLOT(showObjectId(void))); connect(dst_object_sel, SIGNAL(s_selectorCleared(void)), this, SLOT(showObjectId(void))); connect(swap_values_tb, &QToolButton::clicked, [&](){ BaseObject *obj=src_object_sel->getSelectedObject(); src_object_sel->setSelectedObject(dst_object_sel->getSelectedObject()); dst_object_sel->setSelectedObject(obj); }); connect(objects_tbw, &QTableWidget::itemDoubleClicked, [&](QTableWidgetItem *item){ if(QApplication::mouseButtons() == Qt::LeftButton) selectItem(item); }); setMinimumSize(640,480); connect(swap_ids_tb, SIGNAL(clicked(bool)), this, SLOT(swapObjectsIds())); connect(filter_edt, SIGNAL(textChanged(QString)), this, SLOT(filterObjects())); connect(hide_rels_chk, SIGNAL(toggled(bool)), this, SLOT(filterObjects())); connect(hide_sys_objs_chk, SIGNAL(toggled(bool)), this, SLOT(filterObjects())); objects_tbw->installEventFilter(this); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } SwapObjectsIdsWidget::~SwapObjectsIdsWidget() { } void SwapObjectsIdsWidget::setModel(DatabaseModel *model) { this->model=model; src_object_sel->setModel(model); dst_object_sel->setModel(model); src_object_sel->clearSelector(); dst_object_sel->clearSelector(); fillCreationOrderGrid(); } void SwapObjectsIdsWidget::setSelectedObjects(BaseObject *src_object, BaseObject *dst_objct) { src_object_sel->setSelectedObject(src_object); dst_object_sel->setSelectedObject(dst_objct); } void SwapObjectsIdsWidget::fillCreationOrderGrid(void) { objects_tbw->clearContents(); objects_tbw->setRowCount(0); if(!model) return; map creation_order = model->getCreationOrder(SchemaParser::SqlDefinition); vector objects; //Using an stl function to extract all the values (objects) from the map and put them into a list std::for_each(creation_order.begin(), creation_order.end(), [&](const std::pair &itr) { if(itr.second->getObjectType() != ObjectType::Constraint) { objects.push_back(itr.second); } }); ObjectFinderWidget::updateObjectTable(objects_tbw, objects); objects_tbw->resizeColumnsToContents(); if(!filter_edt->text().isEmpty() || hide_rels_chk->isChecked() || hide_sys_objs_chk->isChecked()) filterObjects(); } bool SwapObjectsIdsWidget::eventFilter(QObject *object, QEvent *event) { if(object == objects_tbw && event->type() == QEvent::KeyPress) { QKeyEvent *k_event = dynamic_cast(event); QTableWidgetItem *item = objects_tbw->currentItem(); int row = item->row(); if(k_event->key() == Qt::Key_Space) selectItem(item); else if((k_event->key() == Qt::Key_Down || k_event->key() == Qt::Key_Up) && k_event->modifiers() == Qt::ControlModifier) { QTableWidgetItem *aux_item = nullptr; int key_code = k_event->key(); clearSelectors(); selectItem(item); while(!aux_item) { // If user presses down we get the next item below if(key_code == Qt::Key_Down && row < objects_tbw->rowCount() - 1) aux_item = objects_tbw->item(row + 1, 0); // If user presses up we get the next item above else if(key_code == Qt::Key_Up && row > 1) aux_item = objects_tbw->item(row - 1, 0); // If we reach a hidden row we need to jump to the next one that is not hidden if(aux_item && objects_tbw->isRowHidden(aux_item->row())) { aux_item = nullptr; row += (key_code == Qt::Key_Down ? 1 : -1); } // Breaking if we've reached the top or down limits (avoiding swap ids with null objects) if((key_code == Qt::Key_Down && row >= objects_tbw->rowCount() - 1) || (key_code == Qt::Key_Up && row <= 0)) break; } if(aux_item) { selectItem(aux_item); swapObjectsIds(); clearSelectors(); objects_tbw->setCurrentItem(objects_tbw->item(row , 0)); } } } return(QWidget::eventFilter(object, event)); } void SwapObjectsIdsWidget::showObjectId(void) { QLabel *ico_lbl=nullptr, *id_lbl=nullptr; BaseObject *sel_obj=nullptr; if(sender()==src_object_sel) { ico_lbl=src_ico_lbl; id_lbl=src_id_lbl; sel_obj=src_object_sel->getSelectedObject(); } else { ico_lbl=dst_ico_lbl; id_lbl=dst_id_lbl; sel_obj=dst_object_sel->getSelectedObject(); } id_lbl->clear(); if(sel_obj) { id_lbl->setText(IdLabel.arg(sel_obj->getObjectId())); ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(sel_obj->getObjectType()))); ico_lbl->setToolTip(sel_obj->getTypeName()); id_lbl->setVisible(true); ico_lbl->setVisible(true); } else { id_lbl->setVisible(false); ico_lbl->setVisible(false); } swap_values_tb->setEnabled(src_object_sel->getSelectedObject() && dst_object_sel->getSelectedObject()); swap_ids_tb->setEnabled(src_object_sel->getSelectedObject() && dst_object_sel->getSelectedObject()); } void SwapObjectsIdsWidget::swapObjectsIds(void) { BaseObject *src_obj=src_object_sel->getSelectedObject(), *dst_obj=dst_object_sel->getSelectedObject(); BaseGraphicObject *graph_src_obj=dynamic_cast(src_obj), *graph_dst_obj=dynamic_cast(dst_obj); if(!src_obj && !dst_obj) throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raise an exception if the user try to swap an id of relationship by other object of different kind else if((src_obj->getObjectType()==ObjectType::Relationship || dst_obj->getObjectType()==ObjectType::Relationship) && (src_obj->getObjectType() != dst_obj->getObjectType())) throw Exception(ErrorCode::InvRelationshipIdSwap,__PRETTY_FUNCTION__,__FILE__,__LINE__); try { BaseObject::swapObjectsIds(src_obj, dst_obj, false); //Special id swap for relationship if(src_obj->getObjectType()==ObjectType::Relationship) { vector::iterator itr, itr1; vector *list=model->getObjectList(ObjectType::Relationship); //Find the relationships in the list and swap the memory position too itr=std::find(list->begin(), list->end(), src_obj); itr1=std::find(list->begin(), list->end(), dst_obj); (*itr)=dst_obj; (*itr1)=src_obj; model->validateRelationships(); } else { if(graph_src_obj) graph_src_obj->setModified(true); if(graph_dst_obj) graph_dst_obj->setModified(true); } model->setInvalidated(true); fillCreationOrderGrid(); src_id_lbl->setText(IdLabel.arg(src_object_sel->getSelectedObject()->getObjectId())); dst_id_lbl->setText(IdLabel.arg(dst_object_sel->getSelectedObject()->getObjectId())); emit s_objectsIdsSwapped(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void SwapObjectsIdsWidget::filterObjects(void) { BaseObject *object = nullptr; bool is_rel = false, is_sys_obj = false; QList items=objects_tbw->findItems(filter_edt->text(), Qt::MatchStartsWith | Qt::MatchRecursive); QTableWidgetItem *item = nullptr; for(int row=0; row < objects_tbw->rowCount(); row++) objects_tbw->setRowHidden(row, true); while(!items.isEmpty()) { item = items.front(); object = reinterpret_cast(objects_tbw->item(item->row(), 0)->data(Qt::UserRole).value()); is_rel = (object->getObjectType() == ObjectType::BaseRelationship || object->getObjectType() == ObjectType::Relationship); is_sys_obj = object->isSystemObject(); if((!is_rel && !is_sys_obj) || (!hide_rels_chk->isChecked() && is_rel) || (!hide_sys_objs_chk->isChecked() && is_sys_obj)) objects_tbw->setRowHidden(items.front()->row(), false); items.pop_front(); } } void SwapObjectsIdsWidget::selectItem(QTableWidgetItem *item) { QTableWidgetItem *item_aux = (item->column() == 1 ? item : objects_tbw->item(item->row(), 1)); BaseObject *obj = reinterpret_cast(item_aux->data(Qt::UserRole).value()); if(selector_idx == 0) { src_object_sel->setSelectedObject(obj); selector_idx = 1; } else { dst_object_sel->setSelectedObject(obj); selector_idx = 0; } } void SwapObjectsIdsWidget::clearSelectors(void) { selector_idx = 0; src_object_sel->clearSelector(); dst_object_sel->clearSelector(); } pgmodeler-0.9.2/libpgmodeler_ui/src/swapobjectsidswidget.h000066400000000000000000000036361360462764600240600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ChangeObjectOrderWidget \brief Implements the operations to swap objects ids to cover the cases where model validation cannot reach. */ #ifndef SWAP_OBJECTS_IDS_WIDGET_H #define SWAP_OBJECTS_IDS_WIDGET_H #include #include "ui_swapobjectsidswidget.h" #include "objectselectorwidget.h" class SwapObjectsIdsWidget: public QWidget, public Ui::SwapObjectsIdsWidget { private: Q_OBJECT static const QString IdLabel; unsigned selector_idx = 0; //! \brief Reference database model DatabaseModel *model; //! \brief Source and destination object selectors ObjectSelectorWidget *src_object_sel, *dst_object_sel; void fillCreationOrderGrid(void); bool eventFilter(QObject *object, QEvent *event); public: SwapObjectsIdsWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Widget); ~SwapObjectsIdsWidget(void); void setModel(DatabaseModel *model); void setSelectedObjects(BaseObject *src_object, BaseObject *dst_objct); private slots: void showObjectId(void); void swapObjectsIds(void); void filterObjects(void); void selectItem(QTableWidgetItem *item); void clearSelectors(void); signals: void s_objectsIdsSwapped(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/syntaxhighlighter.cpp000066400000000000000000000443761360462764600237360ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "syntaxhighlighter.h" #include "numberedtexteditor.h" QFont SyntaxHighlighter::default_font=QFont(QString("Source Code Pro"), 10); SyntaxHighlighter::SyntaxHighlighter(QPlainTextEdit *parent, bool single_line_mode, bool use_custom_tab_width) : QSyntaxHighlighter(parent) { if(!parent) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->setDocument(parent->document()); this->single_line_mode=single_line_mode; configureAttributes(); parent->installEventFilter(this); if(use_custom_tab_width) parent->setTabStopWidth(NumberedTextEditor::getTabWidth()); //Adjusting the size of the parent input according to the current font size if(single_line_mode) { QFontMetrics fm=QFontMetrics(default_font); int height=fm.height() + (fm.lineSpacing()/static_cast(1.3)); parent->setMinimumHeight(height); parent->setMaximumHeight(height); parent->setSizePolicy(parent->sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); parent->adjustSize(); } } bool SyntaxHighlighter::eventFilter(QObject *object, QEvent *event) { //Filters the ENTER/RETURN avoiding line breaks if(this->single_line_mode && event->type() == QEvent::KeyPress && (dynamic_cast(event)->key()==Qt::Key_Return || dynamic_cast(event)->key()==Qt::Key_Enter)) { event->ignore(); return(true); } /* If the user is about press Control to paste contents or Right mouse button in order to call the context menu to paste text */ if(event->type()==QEvent::MouseButtonPress || event->type() == QEvent::KeyPress) { QKeyEvent *k_event=dynamic_cast(event); QMouseEvent *m_event=dynamic_cast(event); //Remove the formatting from the clipboard buffer to paste only pure text if(qApp->clipboard() && qApp->clipboard()->mimeData()->hasHtml() && ((m_event && m_event->button()==Qt::RightButton) || (k_event && k_event->modifiers()==Qt::ControlModifier))) qApp->clipboard()->setText(qApp->clipboard()->mimeData()->text()); } return(QSyntaxHighlighter::eventFilter(object, event)); } bool SyntaxHighlighter::hasInitialAndFinalExprs(const QString &group) { return(initial_exprs.count(group) && final_exprs.count(group)); } void SyntaxHighlighter::configureAttributes(void) { conf_loaded=false; } void SyntaxHighlighter::highlightBlock(const QString &txt) { BlockInfo *info=nullptr; BlockInfo *prev_info=dynamic_cast(currentBlock().previous().userData()); if(!currentBlockUserData()) { info=new BlockInfo; setCurrentBlockUserData(info); } else { //Reset the block's info to permit the rehighlighting info=dynamic_cast(currentBlockUserData()); info->resetBlockInfo(); setCurrentBlockState(SimpleBlock); } /* If the previous block info is a open multiline expression the current block will inherit this settings to force the same text formatting */ if(prev_info && currentBlock().previous().userState()==OpenExprBlock && currentBlockState() == OpenExprBlock) { info->group=prev_info->group; info->has_exprs=prev_info->has_exprs; info->is_expr_closed=false; setCurrentBlockState(OpenExprBlock); } if(!txt.isEmpty()) { QString text=txt + QChar('\n'), word, group; unsigned i=0, len, idx=0, i1; int match_idx, match_len, aux_len, start_col; QChar chr_delim, lookahead_chr; len=text.length(); do { //Ignoring the char listed as ingnored on configuration while(i < len && ignored_chars.contains(text[i])) i++; if(i < len) { //Stores the curret text positon idx=i; //If the char is a word separator if(word_separators.contains(text[i])) { while(i < len && word_separators.contains(text[i])) word+=text[i++]; } //If the char is a word delimiter else if(word_delimiters.contains(text[i])) { chr_delim=text[i++]; word+=chr_delim; while(i < len && chr_delim!=text[i]) word+=text[i++]; if(i < len && text[i]==chr_delim) { word+=chr_delim; i++; } } else { BlockInfo *prev_info = dynamic_cast(currentBlock().previous().userData()); while(i < len && !word_separators.contains(text[i]) && !ignored_chars.contains(text[i]) && !word_delimiters.contains(text[i])) { word+=text[i++]; } /* This is an workaround for multi lined groups which use word delimiters in their final expressions. In some cases the highlighter can't undertand that a multi line group was closed and right after another group starts, this way it continues to highlight text as the previous multi lined group. An example of that situation is for multi lined string group: word delimiter: ' (apostrophe) initial-exp: (')(.)*(\n) final-exp: (.)*(')(\n)* String: 'lorem\n ipsum' nextword In the example above, without the workaround, the highlighter would highlight the first line "'lorem\n" as string and continue to hightlight the " ipsum' nextword" in the same way as well, this because the final expression of the group contains the word delimiter '. In order to force the highlight stop in the last ' we include it in the current evaluated word and increment the position in the text so the next word starts without the word delimiter. */ if(word_delimiters.contains(text[i]) && prev_info && !prev_info->group.isEmpty() && prev_info->has_exprs) { for(auto exp : final_exprs[prev_info->group]) { if(exp.pattern().contains(text[i])) { word+=text[i++]; break; } } } } } //If the word is not empty try to identify the group if(!word.isEmpty()) { i1=i; while(i1 < len && ignored_chars.contains(text[i1])) i1++; if(i1 < len) lookahead_chr=text[i1]; else lookahead_chr='\0'; match_idx=-1; match_len=0; group=identifyWordGroup(word, lookahead_chr, match_idx, match_len); if(!group.isEmpty()) { start_col=idx + match_idx; setFormat(start_col, match_len, group); } if(info->has_exprs && !info->is_expr_closed && hasInitialAndFinalExprs(group)) setCurrentBlockState(OpenExprBlock); else setCurrentBlockState(SimpleBlock); aux_len=(match_idx + match_len); if(match_idx >=0 && aux_len != word.length()) i-=word.length() - aux_len; word.clear(); } } while(i < len); } } QString SyntaxHighlighter::identifyWordGroup(const QString &word, const QChar &lookahead_chr, int &match_idx, int &match_len) { QString group; bool match=false; BlockInfo *info=dynamic_cast(currentBlockUserData()), *prev_info=dynamic_cast(currentBlock().previous().userData()); if((info->has_exprs && !info->is_expr_closed && hasInitialAndFinalExprs(info->group)) || (prev_info && !info->has_exprs && prev_info->has_exprs && !prev_info->is_expr_closed)) { if(prev_info && !info->has_exprs) group=prev_info->group; else group=info->group; match=isWordMatchGroup(word, group, true, lookahead_chr, match_idx, match_len); //If the word match one final expression marks the current block info as closed if(match) info->is_expr_closed=true; else { match_idx=0; match_len=word.length(); } info->has_exprs=hasInitialAndFinalExprs(group); info->group=group; return(group); } else { for(auto &itr_group : groups_order) { group=itr_group; if(isWordMatchGroup(word, group, false, lookahead_chr, match_idx, match_len)) { match=true; break; } } if(!match) return(QString()); else { info->group=group; if(!info->has_exprs) info->has_exprs=hasInitialAndFinalExprs(group); info->is_expr_closed=false; return(group); } } } bool SyntaxHighlighter::isWordMatchGroup(const QString &word, const QString &group, bool use_final_expr, const QChar &lookahead_chr, int &match_idx, int &match_len) { vector *vet_expr=nullptr; bool match=false, part_match=partial_match[group]; if(use_final_expr && final_exprs.count(group)) vet_expr=&final_exprs[group]; else vet_expr=&initial_exprs[group]; for(auto &expr : *vet_expr) { if(part_match) { match_idx=word.indexOf(expr); match_len=expr.matchedLength(); match=(match_idx >= 0); } else { if(expr.patternSyntax()==QRegExp::FixedString) match=((expr.pattern().compare(word, expr.caseSensitivity())==0)); else match=expr.exactMatch(word); if(match) { match_idx=0; match_len=word.length(); } } if(match && lookahead_char.count(group) > 0 && lookahead_chr!=lookahead_char.at(group)) match=false; if(match) break; } return(match); } bool SyntaxHighlighter::isConfigurationLoaded(void) { return(conf_loaded); } void SyntaxHighlighter::clearConfiguration(void) { initial_exprs.clear(); final_exprs.clear(); formats.clear(); partial_match.clear(); groups_order.clear(); word_separators.clear(); word_delimiters.clear(); ignored_chars.clear(); lookahead_char.clear(); configureAttributes(); } void SyntaxHighlighter::loadConfiguration(const QString &filename) { if(!filename.isEmpty()) { attribs_map attribs; QString elem, expr_type, group; bool groups_decl=false, chr_sensitive=false, bold=false, italic=false, underline=false, partial_match=false; QTextCharFormat format; QRegExp regexp; QColor bg_color, fg_color; vector::iterator itr, itr_end; try { clearConfiguration(); xmlparser.restartParser(); xmlparser.setDTDFile(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::ObjectDTDDir + GlobalAttributes::DirSeparator + GlobalAttributes::CodeHighlightConf + GlobalAttributes::ObjectDTDExt, GlobalAttributes::CodeHighlightConf); xmlparser.loadXMLFile(filename); if(xmlparser.accessElement(XmlParser::ChildElement)) { do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { elem=xmlparser.getElementName(); if(elem==Attributes::WordSeparators) { xmlparser.getElementAttributes(attribs); word_separators=attribs[Attributes::Value]; } else if(elem==Attributes::WordDelimiters) { xmlparser.getElementAttributes(attribs); word_delimiters=attribs[Attributes::Value]; } else if(elem==Attributes::IgnoredChars) { xmlparser.getElementAttributes(attribs); ignored_chars=attribs[Attributes::Value]; } else if(elem==Attributes::CompletionTrigger) { xmlparser.getElementAttributes(attribs); if(attribs[Attributes::Value].size() >= 1) completion_trigger=attribs[Attributes::Value].at(0); } /* If the element is what defines the order of application of the groups highlight in the (highlight-order). Is in this block that are declared the groups used to highlight the source code. ALL groups in this block must be declared before they are built otherwise an error will be triggered. */ else if(elem==Attributes::HighlightOrder) { //Marks a flag indication that groups are being declared groups_decl=true; xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); elem=xmlparser.getElementName(); } if(elem==Attributes::Group) { xmlparser.getElementAttributes(attribs); group=attribs[Attributes::Name]; /* If the parser is on the group declaration block and not in the build block some validations are made. */ if(groups_decl) { //Raises an error if the group was declared before if(find(groups_order.begin(), groups_order.end(), group)!=groups_order.end()) { throw Exception(Exception::getErrorMessage(ErrorCode::InvRedeclarationGroup).arg(group), ErrorCode::InvRedeclarationGroup,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the group is being declared and build at the declaration statment (not permitted) else if(attribs.size() > 1 || xmlparser.hasElement(XmlParser::ChildElement)) { throw Exception(Exception::getErrorMessage(ErrorCode::InvGroupDeclaration) .arg(group).arg(Attributes::HighlightOrder), ErrorCode::InvRedeclarationGroup,__PRETTY_FUNCTION__,__FILE__,__LINE__); } groups_order.push_back(group); } //Case the parser is on the contruction block and not in declaration of groups else { //Raises an error if the group is being constructed by a second time if(initial_exprs.count(group)!=0) { throw Exception(Exception::getErrorMessage(ErrorCode::DefDuplicatedGroup).arg(group), ErrorCode::DefDuplicatedGroup,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the group is being constructed without being declared else if(find(groups_order.begin(), groups_order.end(), group)==groups_order.end()) { throw Exception(Exception::getErrorMessage(ErrorCode::DefNotDeclaredGroup) .arg(group).arg(Attributes::HighlightOrder), ErrorCode::DefNotDeclaredGroup,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Raises an error if the group does not have children element else if(!xmlparser.hasElement(XmlParser::ChildElement)) { throw Exception(Exception::getErrorMessage(ErrorCode::DefEmptyGroup).arg(group), ErrorCode::DefEmptyGroup,__PRETTY_FUNCTION__,__FILE__,__LINE__); } chr_sensitive=(attribs[Attributes::CaseSensitive]==Attributes::True); italic=(attribs[Attributes::Italic]==Attributes::True); bold=(attribs[Attributes::Bold]==Attributes::True); underline=(attribs[Attributes::Underline]==Attributes::True); partial_match=(attribs[Attributes::PartialMatch]==Attributes::True); fg_color.setNamedColor(attribs[Attributes::ForegroundColor]); //If the attribute isn't defined the bg color will be transparent if(attribs[Attributes::BackgroundColor].isEmpty()) bg_color.setRgb(0,0,0,0); else bg_color.setNamedColor(attribs[Attributes::BackgroundColor]); if(!attribs[Attributes::LookaheadChar].isEmpty()) lookahead_char[group]=attribs[Attributes::LookaheadChar][0]; format.setFontFamily(default_font.family()); format.setFontPointSize(default_font.pointSizeF()); format.setFontItalic(italic); format.setFontUnderline(underline); if(bold) format.setFontWeight(QFont::Bold); else format.setFontWeight(QFont::Normal); format.setForeground(fg_color); format.setBackground(bg_color); formats[group]=format; xmlparser.savePosition(); xmlparser.accessElement(XmlParser::ChildElement); if(chr_sensitive) regexp.setCaseSensitivity(Qt::CaseSensitive); else regexp.setCaseSensitivity(Qt::CaseInsensitive); this->partial_match[group]=partial_match; do { if(xmlparser.getElementType()==XML_ELEMENT_NODE) { xmlparser.getElementAttributes(attribs); expr_type=attribs[Attributes::Type]; regexp.setPattern(attribs[Attributes::Value]); if(attribs[Attributes::RegularExp]==Attributes::True) regexp.setPatternSyntax(QRegExp::RegExp2); else if(attribs[Attributes::Wildcard]==Attributes::True) regexp.setPatternSyntax(QRegExp::Wildcard); else regexp.setPatternSyntax(QRegExp::FixedString); if(expr_type.isEmpty() || expr_type==Attributes::SimpleExp || expr_type==Attributes::InitialExp) initial_exprs[group].push_back(regexp); else final_exprs[group].push_back(regexp); } } while(xmlparser.accessElement(XmlParser::NextElement)); xmlparser.restorePosition(); } } } /* Check if there are some other groups to be declared, if not, continues to reading to the other part of configuration */ if(groups_decl && !xmlparser.hasElement(XmlParser::NextElement)) { groups_decl=false; xmlparser.restorePosition(); } } while(xmlparser.accessElement(XmlParser::NextElement)); } itr=groups_order.begin(); itr_end=groups_order.end(); while(itr!=itr_end) { group=(*itr); itr++; if(initial_exprs[group].size()==0) { //Raises an error if the group was declared but not constructed throw Exception(Exception::getErrorMessage(ErrorCode::InvGroupDeclarationNotDefined).arg(group), ErrorCode::InvGroupDeclarationNotDefined,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } conf_loaded=true; } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } } vector SyntaxHighlighter::getExpressions(const QString &group_name, bool final_expr) { map > *expr_map=(!final_expr ? &initial_exprs : &final_exprs); if(expr_map->count(group_name) > 0) return(expr_map->at(group_name)); else return(vector()); } QChar SyntaxHighlighter::getCompletionTrigger(void) { return(completion_trigger); } void SyntaxHighlighter::setFormat(int start, int count, const QString &group) { QTextCharFormat format=formats[group]; format.setFontFamily(default_font.family()); format.setFontPointSize(default_font.pointSizeF()); QSyntaxHighlighter::setFormat(start, count, format); } void SyntaxHighlighter::setDefaultFont(const QFont &fnt) { SyntaxHighlighter::default_font=fnt; } pgmodeler-0.9.2/libpgmodeler_ui/src/syntaxhighlighter.h000066400000000000000000000141401360462764600233650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class SyntaxHighlighter \brief Implements a syntax hightlighter with user-defined markup patterns (xml configuration). */ #ifndef SYNTAX_HIGHLIGHTER_H #define SYNTAX_HIGHLIGHTER_H #include #include #include #include "exception.h" #include "xmlparser.h" #include "globalattributes.h" #include "attributes.h" #include class SyntaxHighlighter: public QSyntaxHighlighter { private: Q_OBJECT class BlockInfo: public QTextBlockUserData { public: QString group; bool has_exprs; bool is_expr_closed; BlockInfo(void) { resetBlockInfo(); } void resetBlockInfo(void) { group.clear(); has_exprs=false; is_expr_closed=false; } }; //! \brief XML parser used to parse configuration files XmlParser xmlparser; //! \brief Default font configuratoin for all instances os syntax highlighter static QFont default_font; //! \brief Indicates that the current block has no special meaning static constexpr int SimpleBlock=-1, /*! \brief Indicates that the current block has an open (but still to close) expression (e.g. multline comments) When the highlighter finds this const it'll do special operation like highlight next blocks with the same configuration as the current one */ OpenExprBlock=0; /*! \brief Stores the regexp used to identify keywords, identifiers, strings, numbers. Also stores initial regexps used to identify a multiline group */ map > initial_exprs; /*! \brief Stores the regexps that indicates the end of a group. This regexps are used mainly to identify the end of multiline comments */ map > final_exprs; //! \brief Stores the text formatting to each group map formats; //! \brief Stores the groups related to partial matching map partial_match; //! \brief Stores the char used to break the highlight for a group. This char is not highlighted itself. map lookahead_char; //! \brief Stores the order in which the groups must be applied vector groups_order; //! \brief Indicates if the configuration is loaded or not bool conf_loaded, /*! \brief This causes the highlighter to ignores any RETURN/ENTER press on QTextEdit causing the text to be in a single line. */ single_line_mode; //! \brief Stores the chars that indicates word separators QString word_separators, //! \brief Stores the chars that indicates word delimiters word_delimiters, //! \brief Stores the chars ignored by the highlighter during the word reading ignored_chars; //! \brief Stores the char that triggers the code completion QChar completion_trigger; //! \brief Configures the initial attributes of the highlighter void configureAttributes(void); /*! \brief Indentifies the group which the word belongs to. The other parameters indicates, respectively, the lookahead char for the group, the current index (column) on the buffer, the initial match index and the match length. */ QString identifyWordGroup(const QString &palavra, const QChar &lookahead_chr, int &match_idx, int &match_len); /*! \brief This event filter is used to nullify the line breaks when the highlighter is created in single line edit model */ bool eventFilter(QObject *object, QEvent *event); //! \brief Returns if the specified group contains both initial and final expressions bool hasInitialAndFinalExprs(const QString &group); //! \brief Renders the block format using the configuration of the specified group void setFormat(int start, int count, const QString &group); /*! \brief Check if the word matches the specified group by searching the vector of expressions related to it. If the word matches then the match_idx and match_len parameters will be configured with the index and length of chars that the expression could match. Additionally this method returns a boolean indicating the if the match was successful */ bool isWordMatchGroup(const QString &word, const QString &group, bool use_final_expr, const QChar &lookahead_chr, int &match_idx, int &match_len); public: /*! \brief Install the syntax highlighter in a QPlainTextEdit. If single_line_mode is true the highlighter prevents the parent text field to process line breaks. If use_custom_tab_width is true the highlighter will use the same tab size as NumberedTextEdit class */ SyntaxHighlighter(QPlainTextEdit *parent, bool single_line_mode=false, bool use_custom_tab_width=false); //! \brief Loads a highlight configuration from a XML file void loadConfiguration(const QString &filename); //! \brief Returns if the configuration were successfully loaded bool isConfigurationLoaded(void); /*! \brief Returns the regexp vector of the specified group. The 'final_expr' bool parameter indicates that the final expressions must be returned instead of initial expression (default) */ vector getExpressions(const QString &group_name, bool final_expr=false); //! \brief Returns the current configured code completion trigger char QChar getCompletionTrigger(void); //! \brief Sets the default font for all instances of this class static void setDefaultFont(const QFont &fnt); private slots: //! \brief Highlight a line of the text void highlightBlock(const QString &txt); //! \brief Clears the loaded configuration void clearConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/tabledatawidget.cpp000066400000000000000000000411561360462764600233070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tabledatawidget.h" #include "htmlitemdelegate.h" #include "bulkdataeditwidget.h" #include "sqlexecutionwidget.h" const QString TableDataWidget::PlaceholderColumn=QString("$placeholder$"); TableDataWidget::TableDataWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::BaseObject) { Ui_TableDataWidget::setupUi(this); configureFormLayout(tabledata_grid, ObjectType::BaseObject); obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(ObjectType::Table))); comment_lbl->setVisible(false); comment_edt->setVisible(false); data_tbw->setItemDelegate(new PlainTextItemDelegate(this, false)); QFont font=name_edt->font(); font.setItalic(true); name_edt->setReadOnly(true); name_edt->setFont(font); add_row_tb->setToolTip(add_row_tb->toolTip() + QString(" (%1)").arg(add_row_tb->shortcut().toString())); del_rows_tb->setToolTip(del_rows_tb->toolTip() + QString(" (%1)").arg(del_rows_tb->shortcut().toString())); dup_rows_tb->setToolTip(dup_rows_tb->toolTip() + QString(" (%1)").arg(dup_rows_tb->shortcut().toString())); clear_rows_tb->setToolTip(clear_rows_tb->toolTip() + QString(" (%1)").arg(clear_rows_tb->shortcut().toString())); clear_cols_tb->setToolTip(clear_cols_tb->toolTip() + QString(" (%1)").arg(clear_cols_tb->shortcut().toString())); add_col_tb->setMenu(&col_names_menu); data_tbw->removeEventFilter(this); csv_load_parent->setVisible(false); csv_load_wgt = new CsvLoadWidget(this, true); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(csv_load_wgt); layout->setContentsMargins(0,0,0,0); csv_load_parent->setLayout(layout); csv_load_parent->setMinimumSize(csv_load_wgt->minimumSize()); setMinimumSize(640, 480); connect(add_row_tb, SIGNAL(clicked(bool)), this, SLOT(addRow())); connect(dup_rows_tb, SIGNAL(clicked(bool)), this, SLOT(duplicateRows())); connect(del_rows_tb, SIGNAL(clicked(bool)), this, SLOT(deleteRows())); connect(del_cols_tb, SIGNAL(clicked(bool)), this, SLOT(deleteColumns())); connect(clear_rows_tb, SIGNAL(clicked(bool)), this, SLOT(clearRows())); connect(clear_cols_tb, SIGNAL(clicked(bool)), this, SLOT(clearColumns())); connect(data_tbw, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(insertRowOnTabPress(int,int,int,int)), Qt::QueuedConnection); connect(&col_names_menu, SIGNAL(triggered(QAction*)), this, SLOT(addColumn(QAction *))); connect(data_tbw, SIGNAL(itemSelectionChanged()), this, SLOT(enableButtons())); connect(data_tbw->horizontalHeader(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(changeColumnName(int))); connect(csv_load_tb, SIGNAL(toggled(bool)), csv_load_parent, SLOT(setVisible(bool))); connect(csv_load_wgt, &CsvLoadWidget::s_csvFileLoaded, [&](){ populateDataGrid(csv_load_wgt->getCsvBuffer(Table::DataSeparator, Table::DataLineBreak)); }); connect(paste_tb, &QToolButton::clicked, [&](){ csv_load_wgt->loadCsvBuffer(qApp->clipboard()->text(), QString(";"), QString("\""), true); populateDataGrid(csv_load_wgt->getCsvBuffer(Table::DataSeparator, Table::DataLineBreak)); qApp->clipboard()->clear(); paste_tb->setEnabled(false); }); connect(bulkedit_tb, &QToolButton::clicked, [&](){ PgModelerUiNs::bulkDataEdit(data_tbw); }); connect(copy_tb, &QToolButton::clicked, [&](){ SQLExecutionWidget::copySelection(data_tbw, false, true); paste_tb->setEnabled(true); }); connect(data_tbw, &QTableWidget::itemPressed, [&](){ if(QApplication::mouseButtons()==Qt::RightButton) { QMenu item_menu; QAction *act = nullptr; QList btns = { add_row_tb, add_col_tb, dup_rows_tb, nullptr, del_rows_tb, del_cols_tb, nullptr, clear_rows_tb, clear_cols_tb, nullptr, copy_tb, paste_tb }; for(auto &btn : btns) { if(!btn) { item_menu.addSeparator(); continue; } act = item_menu.addAction(btn->icon(), btn->text(), btn, SLOT(click()), btn->shortcut()); act->setEnabled(btn->isEnabled()); act->setMenu(btn->menu()); } item_menu.exec(QCursor::pos()); } }); } void TableDataWidget::insertRowOnTabPress(int curr_row, int curr_col, int prev_row, int prev_col) { if(qApp->mouseButtons()==Qt::NoButton && curr_row==0 && curr_col==0 && prev_row==data_tbw->rowCount()-1 && prev_col==data_tbw->columnCount()-1) { addRow(); } } void TableDataWidget::duplicateRows(void) { QList sel_ranges=data_tbw->selectedRanges(); if(!sel_ranges.isEmpty()) { for(auto &sel_rng : sel_ranges) { for(int row=sel_rng.topRow(); row <= sel_rng.bottomRow(); row++) { addRow(); for(int col=0; col < data_tbw->columnCount(); col++) { data_tbw->item(data_tbw->rowCount() - 1, col) ->setText(data_tbw->item(row, col)->text()); } } } data_tbw->clearSelection(); } } void TableDataWidget::deleteRows(void) { QTableWidgetSelectionRange sel_range; while(!data_tbw->selectedRanges().isEmpty()) { sel_range=data_tbw->selectedRanges().at(0); for(int i = 0; i < sel_range.rowCount(); i++) data_tbw->removeRow(sel_range.topRow()); } } void TableDataWidget::deleteColumns(void) { Messagebox msg_box; msg_box.show(trUtf8("Delete columns is an irreversible action! Do you really want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { QTableWidgetSelectionRange sel_range; while(!data_tbw->selectedRanges().isEmpty()) { sel_range=data_tbw->selectedRanges().at(0); for(int i = 0; i < sel_range.columnCount(); i++) data_tbw->removeColumn(sel_range.leftColumn()); } //Clears the entire table if no columns is left if(data_tbw->columnCount()==0) { clearRows(false); add_row_tb->setEnabled(false); clear_cols_tb->setEnabled(false); } del_cols_tb->setEnabled(false); toggleWarningFrame(); configureColumnNamesMenu(); } } void TableDataWidget::clearRows(bool confirm) { Messagebox msg_box; if(confirm) msg_box.show(trUtf8("Remove all rows is an irreversible action! Do you really want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(!confirm || msg_box.result()==QDialog::Accepted) { data_tbw->clearContents(); data_tbw->setRowCount(0); clear_rows_tb->setEnabled(false); } } void TableDataWidget::clearColumns(void) { Messagebox msg_box; msg_box.show(trUtf8("Remove all columns is an irreversible action! Do you really want to proceed?"), Messagebox::ConfirmIcon, Messagebox::YesNoButtons); if(msg_box.result()==QDialog::Accepted) { clearRows(false); data_tbw->setColumnCount(0); clear_cols_tb->setEnabled(false); warn_frm->setVisible(false); add_row_tb->setEnabled(false); configureColumnNamesMenu(); } } void TableDataWidget::changeColumnName(int col_idx) { QTableWidgetItem *item=data_tbw->horizontalHeaderItem(col_idx); if(item) { QAction * act=nullptr; col_names_menu.blockSignals(true); act=col_names_menu.exec(QCursor::pos()); col_names_menu.blockSignals(false); if(act && act->isEnabled()) { QTableWidgetItem *item=data_tbw->horizontalHeaderItem(col_idx); QString col_name=act->text(); item->setText(col_name); if(act->text()==PlaceholderColumn) { item->setFlags(Qt::NoItemFlags); item->setForeground(QColor(Qt::red)); item->setToolTip(trUtf8("Unknown column")); } else { PhysicalTable *table=dynamic_cast(this->object); Column *column = table->getColumn(col_name); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); item->setForeground(data_tbw->horizontalHeader()->palette().color(QPalette::Foreground)); item->setToolTip(QString("%1 [%2]").arg(col_name).arg(~column->getType())); } for(int row = 0; row < data_tbw->rowCount(); row++) { item=data_tbw->item(row, col_idx); if(col_name==PlaceholderColumn) setItemInvalid(item); else { item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); item->setBackground(item->data(Qt::UserRole).value()); } } toggleWarningFrame(); configureColumnNamesMenu(); data_tbw->horizontalHeader()->update(); data_tbw->update(); } } } void TableDataWidget::enableButtons(void) { QList sel_ranges=data_tbw->selectedRanges(); bool cols_selected, rows_selected; cols_selected = rows_selected = !sel_ranges.isEmpty(); for(auto &sel_rng : sel_ranges) { cols_selected &= (sel_rng.columnCount() == data_tbw->columnCount()); rows_selected &= (sel_rng.rowCount() == data_tbw->rowCount()); } del_rows_tb->setEnabled(cols_selected); add_row_tb->setEnabled(data_tbw->columnCount() > 0); del_cols_tb->setEnabled(rows_selected); dup_rows_tb->setEnabled(cols_selected); bulkedit_tb->setEnabled(!sel_ranges.isEmpty()); copy_tb->setEnabled(!sel_ranges.isEmpty()); } void TableDataWidget::setAttributes(DatabaseModel *model, PhysicalTable *table) { BaseObjectWidget::setAttributes(model, table, nullptr); bool enable=(object != nullptr); protected_obj_frm->setVisible(false); obj_id_lbl->setVisible(false); data_tbw->setEnabled(enable); add_row_tb->setEnabled(enable); if(object) populateDataGrid(); } void TableDataWidget::populateDataGrid(const QString &data) { PhysicalTable *table=dynamic_cast(this->object); QTableWidgetItem *item=nullptr; QString ini_data; int col=0, row=0; QStringList columns, aux_cols, buffer, values; QVector invalid_cols; Column *column=nullptr; clearRows(false); if(!data.isEmpty()) ini_data=data; else ini_data=table->getInitialData(); /* If the initial data buffer is preset the columns there have priority over the current table's columns */ if(!ini_data.isEmpty()) { buffer=ini_data.split(Table::DataLineBreak); //The first line of the buffer always has the column names if(!buffer.isEmpty() && !buffer[0].isEmpty()) columns.append(buffer[0].split(Table::DataSeparator)); } else { for(auto object : *table->getObjectList(ObjectType::Column)) columns.push_back(object->getName()); } data_tbw->setColumnCount(columns.size()); //Creating the header of the grid for(QString col_name : columns) { column = table->getColumn(col_name); item=new QTableWidgetItem(col_name); /* Marking the invalid columns. The ones which aren't present in the table or were already created in a previous iteration */ if(!column || aux_cols.contains(col_name)) { invalid_cols.push_back(col); if(!column) item->setToolTip(trUtf8("Unknown column")); else item->setToolTip(trUtf8("Duplicated column")); } else item->setToolTip(QString("%1 [%2]").arg(col_name).arg(~column->getType())); aux_cols.append(col_name); data_tbw->setHorizontalHeaderItem(col++, item); } buffer.removeAt(0); row=0; //Populating the grid with the data for(QString buf_row : buffer) { addRow(); values = buf_row.split(Table::DataSeparator); col = 0; for(QString val : values) { if(col < columns.size()) data_tbw->item(row, col++)->setText(val); } row++; } //Disabling invalid columns avoiding the user interaction if(!invalid_cols.isEmpty()) { for(int dis_col : invalid_cols) { for(row = 0; row < data_tbw->rowCount(); row++) setItemInvalid(data_tbw->item(row, dis_col)); item=data_tbw->horizontalHeaderItem(dis_col); item->setFlags(Qt::NoItemFlags); item->setForeground(QColor(Qt::red)); } } warn_frm->setVisible(!invalid_cols.isEmpty()); data_tbw->resizeColumnsToContents(); data_tbw->resizeRowsToContents(); add_row_tb->setEnabled(!columns.isEmpty()); clear_cols_tb->setEnabled(!columns.isEmpty()); configureColumnNamesMenu(); } void TableDataWidget::configureColumnNamesMenu(void) { PhysicalTable *table=dynamic_cast(this->object); QStringList col_names; col_names_menu.clear(); for(auto object : *table->getObjectList(ObjectType::Column)) col_names.push_back(object->getName()); for(int col = 0; col < data_tbw->columnCount(); col++) col_names.removeOne(data_tbw->horizontalHeaderItem(col)->text()); if(!col_names.isEmpty()) { col_names.sort(); for(QString col_name : col_names) col_names_menu.addAction(col_name); } col_names_menu.addSeparator(); col_names_menu.addAction(PlaceholderColumn); } void TableDataWidget::toggleWarningFrame(void) { bool has_inv_cols=false; for(int col = 0; col < data_tbw->columnCount() && !has_inv_cols; col++) has_inv_cols = data_tbw->horizontalHeaderItem(col)->flags()==Qt::NoItemFlags; warn_frm->setVisible(has_inv_cols); } void TableDataWidget::setItemInvalid(QTableWidgetItem *item) { if(item) { item->setData(Qt::UserRole, item->background()); item->setBackgroundColor(QColor(QString("#FFC0C0"))); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); } } QString TableDataWidget::generateDataBuffer(void) { QStringList val_list, col_names, buffer; QString value; int col = 0, col_count = data_tbw->horizontalHeader()->count(); for(int col=0; col < col_count; col++) col_names.push_back(data_tbw->horizontalHeaderItem(col)->text()); //The first line of the buffer consists in the column names buffer.push_back(col_names.join(Table::DataSeparator)); for(int row = 0; row < data_tbw->rowCount(); row++) { for(col = 0; col < col_count; col++) { value = data_tbw->item(row, col)->text(); //Checking if the value is a malformed unescaped value, e.g., {value, value}, {value\} if((value.startsWith(PgModelerNs::UnescValueStart) && value.endsWith(QString("\\") + PgModelerNs::UnescValueEnd)) || (value.startsWith(PgModelerNs::UnescValueStart) && !value.endsWith(PgModelerNs::UnescValueEnd)) || (!value.startsWith(PgModelerNs::UnescValueStart) && !value.endsWith(QString("\\") + PgModelerNs::UnescValueEnd) && value.endsWith(PgModelerNs::UnescValueEnd))) throw Exception(Exception::getErrorMessage(ErrorCode::MalformedUnescapedValue) .arg(row + 1).arg(col_names[col]), ErrorCode::MalformedUnescapedValue,__PRETTY_FUNCTION__,__FILE__,__LINE__); val_list.push_back(value); } buffer.push_back(val_list.join(Table::DataSeparator)); val_list.clear(); } if(buffer.size() <= 1) return(QString()); return(buffer.join(Table::DataLineBreak)); } void TableDataWidget::enterEvent(QEvent *) { paste_tb->setEnabled(!qApp->clipboard()->text().isEmpty()); } void TableDataWidget::showEvent(QShowEvent *) { paste_tb->setEnabled(!qApp->clipboard()->text().isEmpty()); } void TableDataWidget::addRow(void) { int row=data_tbw->rowCount(); QTableWidgetItem *item = nullptr; data_tbw->blockSignals(true); data_tbw->insertRow(row); for(int col=0; col < data_tbw->columnCount(); col++) { item=new QTableWidgetItem; if(data_tbw->horizontalHeaderItem(col)->flags()==Qt::NoItemFlags) setItemInvalid(item); else item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); data_tbw->setItem(row, col, item); } data_tbw->clearSelection(); data_tbw->setCurrentCell(row, 0, QItemSelectionModel::ClearAndSelect); if(item && item->flags()!=Qt::NoItemFlags) data_tbw->editItem(data_tbw->item(row, 0)); data_tbw->blockSignals(false); clear_rows_tb->setEnabled(true); } void TableDataWidget::addColumn(QAction *action) { if(action) { QTableWidgetItem *item=nullptr; int col = data_tbw->columnCount(); data_tbw->insertColumn(col); item=new QTableWidgetItem; item->setText(action->text()); data_tbw->setHorizontalHeaderItem(col, item); for(int row=0; row < data_tbw->rowCount(); row++) { item=new QTableWidgetItem; item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); data_tbw->setItem(row, col, item); } add_row_tb->setEnabled(true); clear_cols_tb->setEnabled(true); data_tbw->resizeColumnsToContents(); configureColumnNamesMenu(); } } void TableDataWidget::applyConfiguration(void) { try { PhysicalTable *table = dynamic_cast(this->object); table->setInitialData(generateDataBuffer()); emit s_closeRequested(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/tabledatawidget.h000066400000000000000000000050151360462764600227460ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TableDataWidget \brief Form used to add initial data for tables. */ #ifndef TABLE_DATA_WIDGET_H #define TABLE_DATA_WIDGET_H #include "baseobjectwidget.h" #include "ui_tabledatawidget.h" #include "csvloadwidget.h" class TableDataWidget: public BaseObjectWidget, public Ui::TableDataWidget { private: Q_OBJECT CsvLoadWidget *csv_load_wgt; /*! \brief Stores the remaining column names not used in the grid. This menu is used either to add new columns and fix invalid columns in the grid */ QMenu col_names_menu; //! brief Loads the grid with the initial data of the curret table object void populateDataGrid(const QString &data = QString()); //! brief Configures the col_name_menu with the not used columns names void configureColumnNamesMenu(void); //! brief Toggles the warning frame if some invalid or duplicated columns is detected void toggleWarningFrame(void); //! brief Marks a certain item as invalid cause it to be deactivated in the grid void setItemInvalid(QTableWidgetItem *item); //! brief Generated the CSV-like buffer to be used as initial data in the table object QString generateDataBuffer(void); void showEvent(QShowEvent *); void enterEvent(QEvent *); public: static const QString PlaceholderColumn; TableDataWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, PhysicalTable *table); public slots: void applyConfiguration(void); private slots: void insertRowOnTabPress(int curr_row, int curr_col, int prev_row, int prev_col); void addRow(void); void addColumn(QAction *action); void duplicateRows(void); void deleteRows(void); void deleteColumns(void); void clearRows(bool confirm=true); void clearColumns(void); void changeColumnName(int col_idx); void enableButtons(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/tablespacewidget.cpp000066400000000000000000000035551360462764600234720ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tablespacewidget.h" TablespaceWidget::TablespaceWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Tablespace) { Ui_TablespaceWidget::setupUi(this); configureFormLayout(tablespace_grid, ObjectType::Tablespace); tablespace_grid->addItem(new QSpacerItem(10,0,QSizePolicy::Minimum,QSizePolicy::Expanding), tablespace_grid->count(), 0); setRequiredField(directory_lbl); setRequiredField(directory_edt); configureTabOrder(); setMinimumSize(480, 140); } void TablespaceWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Tablespace *tablespc) { BaseObjectWidget::setAttributes(model, op_list, tablespc); if(tablespc) directory_edt->setText(tablespc->getDirectory()); } void TablespaceWidget::applyConfiguration(void) { try { Tablespace *tablespc=nullptr; startConfiguration(); tablespc=dynamic_cast(this->object); tablespc->setDirectory(directory_edt->text()); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/tablespacewidget.h000066400000000000000000000024031360462764600231260ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TablespaceWidget \brief Implements the operations to create/edit tablespaces via form. */ #ifndef TABLESPACE_WIDGET_H #define TABLESPACE_WIDGET_H #include "baseobjectwidget.h" #include "ui_tablespacewidget.h" class TablespaceWidget: public BaseObjectWidget, public Ui::TablespaceWidget { private: Q_OBJECT public: TablespaceWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Tablespace *tablespc); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/tablewidget.cpp000066400000000000000000001102651360462764600224530ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tablewidget.h" #include "columnwidget.h" #include "constraintwidget.h" #include "rulewidget.h" #include "indexwidget.h" #include "triggerwidget.h" #include "baseform.h" #include "tabledatawidget.h" #include "policywidget.h" #include "generalconfigwidget.h" TableWidget::TableWidget(QWidget *parent, ObjectType tab_type): BaseObjectWidget(parent, tab_type) { QGridLayout *grid=nullptr; QVBoxLayout *vbox=nullptr; ObjectsTableWidget *tab=nullptr; ObjectType types[]={ ObjectType::Column, ObjectType::Constraint, ObjectType::Trigger, ObjectType::Rule, ObjectType::Index, ObjectType::Policy }; map > fields_map; QPushButton *edt_data_tb=nullptr; QStringList part_types; Ui_TableWidget::setupUi(this); edt_data_tb=new QPushButton(this); QPixmap icon=QPixmap(PgModelerUiNs::getIconPath("editdata")); edt_data_tb->setMinimumSize(edt_perms_tb->minimumSize()); edt_data_tb->setText(trUtf8("Edit data")); edt_data_tb->setToolTip(trUtf8("Define initial data for the table")); edt_data_tb->setIcon(icon); edt_data_tb->setIconSize(edt_perms_tb->iconSize()); connect(edt_data_tb, SIGNAL(clicked(bool)), this, SLOT(editData())); misc_btns_lt->insertWidget(1, edt_data_tb); fields_map[generateVersionsInterval(UntilVersion, PgSqlVersions::PgSqlVersion110)].push_back(with_oids_chk); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion91)].push_back(unlogged_chk); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(enable_rls_chk); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion95)].push_back(force_rls_chk); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion100)].push_back(partitioning_type_lbl); warn_frame=generateVersionWarningFrame(fields_map); table_grid->addWidget(warn_frame, table_grid->count()+1, 0, 1, 2); warn_frame->setParent(this); parent_tables = new ObjectsTableWidget(ObjectsTableWidget::NoButtons, true, this); parent_tables->setColumnCount(3); parent_tables->setHeaderLabel(trUtf8("Name"), 0); parent_tables->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); parent_tables->setHeaderLabel(trUtf8("Schema"), 1); parent_tables->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("schema")),1); parent_tables->setHeaderLabel(trUtf8("Type"), 2); parent_tables->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),2); server_sel=nullptr; server_sel=new ObjectSelectorWidget(ObjectType::ForeignServer, true, this); vbox = new QVBoxLayout; vbox->setContentsMargins(0,0,0,0); vbox->addWidget(server_sel); server_wgt->setLayout(vbox); options_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton), true, this); options_tab->setCellsEditable(true); options_tab->setColumnCount(2); options_tab->setHeaderLabel(trUtf8("Option"), 0); options_tab->setHeaderLabel(trUtf8("Value"), 1); vbox = new QVBoxLayout; vbox->setContentsMargins(4,4,4,4); vbox->addWidget(options_tab); attributes_tbw->widget(8)->setLayout(vbox); tag_sel = new ObjectSelectorWidget(ObjectType::Tag, false, this); vbox = new QVBoxLayout(tag_sel_parent); vbox->addWidget(tag_sel); vbox->setContentsMargins(0,0,0,0); grid=new QGridLayout; grid->addWidget(parent_tables, 0,0,1,1); grid->setContentsMargins(4,4,4,4); attributes_tbw->widget(7)->setLayout(grid); //Configuring the table objects that stores the columns, triggers, constraints, rules and indexes for(unsigned i=0; i <= 5; i++) { tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton), true, this); objects_tab_map[types[i]]=tab; grid=new QGridLayout; grid->addWidget(tab, 0,0,1,1); grid->setContentsMargins(4,4,4,4); attributes_tbw->widget(i)->setLayout(grid); connect(tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removeObjects(void))); connect(tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removeObject(int))); connect(tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleObject(void))); connect(tab, SIGNAL(s_rowEdited(int)), this, SLOT(handleObject(void))); connect(tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateObject(int,int))); connect(tab, SIGNAL(s_rowsMoved(int,int)), this, SLOT(swapObjects(int,int))); } objects_tab_map[ObjectType::Column]->setColumnCount(7); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("PK"), 0); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("Name"), 1); objects_tab_map[ObjectType::Column]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),1); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("Type"), 2); objects_tab_map[ObjectType::Column]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),2); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("Default Value"), 3); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("Attribute(s)"), 4); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("Alias"), 5); objects_tab_map[ObjectType::Column]->setHeaderLabel(trUtf8("Comment"), 6); objects_tab_map[ObjectType::Column]->adjustColumnToContents(0); connect(objects_tab_map[ObjectType::Column], &ObjectsTableWidget::s_cellClicked, [&](int row, int col){ if(col == 0 && objects_tab_map[ObjectType::Column]->isCellDisabled(static_cast(row), static_cast(col))) { Messagebox msg_box; PhysicalTable *table = dynamic_cast
(this->object); Constraint *pk = table->getPrimaryKey(); if(pk && pk->isAddedByRelationship()) msg_box.show(trUtf8("It is not possible to mark a column as primary key when the table already has a primary key which was created by a relationship! This action should be done in the section Primary key of the relationship's editing form."), Messagebox::AlertIcon); else msg_box.show(trUtf8("It is not possible to mark a column created by a relationship as primary key! This action should be done in the section Primary key of the relationship's editing form."), Messagebox::AlertIcon); } }); objects_tab_map[ObjectType::Constraint]->setColumnCount(6); objects_tab_map[ObjectType::Constraint]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Constraint]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Constraint]->setHeaderLabel(trUtf8("Type"), 1); objects_tab_map[ObjectType::Constraint]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); objects_tab_map[ObjectType::Constraint]->setHeaderLabel(trUtf8("ON DELETE"), 2); objects_tab_map[ObjectType::Constraint]->setHeaderLabel(trUtf8("ON UPDATE"), 3); objects_tab_map[ObjectType::Constraint]->setHeaderLabel(trUtf8("Alias"), 4); objects_tab_map[ObjectType::Constraint]->setHeaderLabel(trUtf8("Comment"), 5); objects_tab_map[ObjectType::Trigger]->setColumnCount(6); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Trigger]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Refer. Table"), 1); objects_tab_map[ObjectType::Trigger]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("table")),1); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Firing"), 2); objects_tab_map[ObjectType::Trigger]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("trigger")),2); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Events"), 3); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Alias"), 4); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Comment"), 5); objects_tab_map[ObjectType::Rule]->setColumnCount(5); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Rule]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Execution"), 1); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Event"), 2); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Alias"), 3); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Comment"), 4); objects_tab_map[ObjectType::Index]->setColumnCount(4); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Index]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Indexing"), 1); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Alias"), 2); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Comment"), 3); objects_tab_map[ObjectType::Policy]->setColumnCount(8); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Policy]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("Command"), 1); objects_tab_map[ObjectType::Policy]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("keyword")),1); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("Permissive"), 2); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("USING expression"), 3); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("CHECK expression"), 4); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("Roles"), 5); objects_tab_map[ObjectType::Policy]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("role")),5); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("Alias"), 6); objects_tab_map[ObjectType::Policy]->setHeaderLabel(trUtf8("Comment"), 7); partition_keys_tab = new ElementsTableWidget; partition_keys_tab->setEnabled(false); grid = dynamic_cast(attributes_tbw->widget(6)->layout()); grid->addWidget(partition_keys_tab, 1, 0, 1, 2); PartitioningType::getTypes(part_types); part_types.push_front(trUtf8("None")); partitioning_type_cmb->addItems(part_types); connect(partitioning_type_cmb, &QComboBox::currentTextChanged, [&](){ partition_keys_tab->setEnabled(partitioning_type_cmb->currentIndex() != 0); }); setRequiredField(server_lbl); setRequiredField(server_sel); configureFormLayout(table_grid, tab_type); configureTabOrder({ tag_sel }); setMinimumSize(660, 630); } template int TableWidget::openEditingForm(TableObject *object) { BaseForm editing_form(this); WidgetClass *object_wgt=new WidgetClass; int res = 0; object_wgt->setAttributes(this->model, this->op_list, dynamic_cast(this->object), dynamic_cast(object)); editing_form.setMainWidget(object_wgt); GeneralConfigWidget::restoreWidgetGeometry(&editing_form, object_wgt->metaObject()->className()); res = editing_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&editing_form, object_wgt->metaObject()->className()); return(res); } ObjectsTableWidget *TableWidget::getObjectTable(ObjectType obj_type) { if(objects_tab_map.count(obj_type) > 0) return(objects_tab_map[obj_type]); return(nullptr); } ObjectType TableWidget::getObjectType(QObject *sender) { ObjectType obj_type=ObjectType::BaseObject; if(sender) { map::iterator itr, itr_end; itr=objects_tab_map.begin(); itr_end=objects_tab_map.end(); while(itr!=itr_end && obj_type==ObjectType::BaseObject) { if(itr->second==sender) obj_type=itr->first; itr++; } } return(obj_type); } void TableWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Table *table, double pos_x, double pos_y) { if(!table) { table=new Table; if(schema) table->setSchema(schema); /* Sets the 'new_object' flag as true indicating that the alocated table must be treated as a recently created object */ this->new_object=true; } __setAttributes(model, op_list, schema, table, pos_x, pos_y); server_lbl->setVisible(false); server_wgt->setVisible(false); attributes_tbw->removeTab(8); // Removing the options tab } void TableWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, ForeignTable *ftable, double pos_x, double pos_y) { if(!ftable) { ftable = new ForeignTable; if(schema) ftable->setSchema(schema); /* Sets the 'new_object' flag as true indicating that the alocated table must be treated as a recently created object */ this->new_object=true; } __setAttributes(model, op_list, schema, ftable, pos_x, pos_y); warn_frame->setVisible(false); with_oids_chk->setVisible(false); unlogged_chk->setVisible(false); enable_rls_chk->setVisible(false); force_rls_chk->setVisible(false); attributes_tbw->removeTab(3); //Removing the Index tab attributes_tbw->removeTab(3); //Removing the Rule tab attributes_tbw->removeTab(3); //Removing the Policies tab attributes_tbw->removeTab(3); //Removing the Partition keys tab objects_tab_map[ObjectType::Column]->setHeaderVisible(0, false); //Hiding the "PK" checkbox on columns grid server_sel->setModel(this->model); server_sel->setSelectedObject(ftable->getForeignServer()); } void TableWidget::__setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, PhysicalTable *table, double pos_x, double pos_y) { try { unsigned i, count; PhysicalTable *aux_tab=nullptr; vector types=BaseObject::getChildObjectTypes(ObjectType::Table); vector part_keys; BaseObjectWidget::setAttributes(model, op_list, table, schema, pos_x, pos_y); op_list->startOperationChain(); operation_count=op_list->getCurrentSize(); /* Listing all objects (column, constraint, trigger, index, rule) on the respective table objects */ for(auto &type : types) { listObjects(type); objects_tab_map[type]->setButtonConfiguration(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton)); } //Listing the ancestor tables count=table->getAncestorTableCount(); for(i=0; i < count; i++) { aux_tab=table->getAncestorTable(i); parent_tables->addRow(); parent_tables->setCellText(aux_tab->getName(), i, 0); parent_tables->setCellText(aux_tab->getSchema()->getName(), i, 1); parent_tables->setCellText(trUtf8("Parent"), i, 2); } aux_tab=table->getCopyTable(); if(aux_tab) { i = parent_tables->getRowCount(); parent_tables->addRow(); parent_tables->setCellText(aux_tab->getName(), i, 0); parent_tables->setCellText(aux_tab->getSchema()->getName(), i, 1); parent_tables->setCellText(trUtf8("Copy"), i, 2); } aux_tab=table->getPartitionedTable(); if(aux_tab) { i = parent_tables->getRowCount(); parent_tables->addRow(); parent_tables->setCellText(aux_tab->getName(), i, 0); parent_tables->setCellText(aux_tab->getSchema()->getName(), i, 1); parent_tables->setCellText(trUtf8("Partitioned"), i, 2); } i = parent_tables->getRowCount(); for(auto &tab : table->getPartionTables()) { parent_tables->addRow(); parent_tables->setCellText(tab->getName(), i, 0); parent_tables->setCellText(tab->getSchema()->getName(), i, 1); parent_tables->setCellText(trUtf8("Partition"), i, 2); i++; } if(table->getObjectType() == ObjectType::Table) { Table *tab = dynamic_cast
(table); unlogged_chk->setChecked(tab->isUnlogged()); enable_rls_chk->setChecked(tab->isRLSEnabled()); force_rls_chk->setChecked(tab->isRLSForced()); with_oids_chk->setChecked(tab->isWithOIDs()); } else { ForeignTable *ftab = dynamic_cast(table); options_tab->blockSignals(true); for(auto &itr : ftab->getOptions()) { options_tab->addRow(); options_tab->setCellText(itr.first, options_tab->getRowCount() - 1, 0); options_tab->setCellText(itr.second, options_tab->getRowCount() - 1, 1); } options_tab->clearSelection(); options_tab->blockSignals(false); } parent_tables->clearSelection(); gen_alter_cmds_chk->setChecked(table->isGenerateAlterCmds() && !table->isPartition() && !table->isPartitioned()); gen_alter_cmds_chk->setEnabled(!table->isPartition() && !table->isPartitioned()); tag_sel->setModel(this->model); tag_sel->setSelectedObject(table->getTag()); int idx = partitioning_type_cmb->findText(~table->getPartitioningType()); partitioning_type_cmb->setCurrentIndex(idx < 0 ? 0 : idx); partition_keys_tab->setAttributes(model, table); part_keys = table->getPartitionKeys(); partition_keys_tab->setAttributes(this->model, table); partition_keys_tab->setElements(part_keys); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::listObjects(ObjectType obj_type) { ObjectsTableWidget *tab=nullptr; unsigned idx = 0, count = 0; PhysicalTable *table=nullptr; vector checked_cols; try { //Gets the object table related to the object type tab=objects_tab_map[obj_type]; table=dynamic_cast(this->object); /* Since the object grid is cleared we need to register the checked PK columns * so after (re)populating the cols list the check state of that columns * can be restored properly */ if(obj_type == ObjectType::Column) { count = tab->getRowCount(); for(idx = 0; idx < count; idx++) { if(tab->getCellCheckState(idx, 0) == Qt::Checked) checked_cols.push_back(idx); } } tab->blockSignals(true); tab->removeRows(); count = table->getObjectCount(obj_type); for(idx = 0; idx < count; idx++) { tab->addRow(); showObjectData(dynamic_cast(table->getObject(idx, obj_type)), idx); } tab->clearSelection(); tab->blockSignals(false); //Enables the add button on the constraints, triggers and index tab only when there is columns created if(obj_type==ObjectType::Column) { objects_tab_map[ObjectType::Constraint]->setButtonsEnabled(ObjectsTableWidget::AddButton, objects_tab_map[ObjectType::Column]->getRowCount() > 0); objects_tab_map[ObjectType::Trigger]->setButtonsEnabled(ObjectsTableWidget::AddButton, objects_tab_map[ObjectType::Column]->getRowCount() > 0); objects_tab_map[ObjectType::Index]->setButtonsEnabled(ObjectsTableWidget::AddButton, objects_tab_map[ObjectType::Column]->getRowCount() > 0); // Restoring the PK columns check state while(!checked_cols.empty()) { tab->setCellCheckState(checked_cols.back(), 0, Qt::Checked); checked_cols.pop_back(); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::handleObject(void) { ObjectType obj_type=ObjectType::BaseObject; TableObject *object=nullptr; ObjectsTableWidget *obj_table=nullptr; try { obj_type=getObjectType(sender()); //Selects the object table based upon the passed object type obj_table=getObjectTable(obj_type); //Gets the object reference if there is an item select on table if(obj_table->getSelectedRow()>=0) object=reinterpret_cast(obj_table->getRowData(obj_table->getSelectedRow()).value()); if(obj_type==ObjectType::Column) openEditingForm(object); else if(obj_type==ObjectType::Constraint) openEditingForm(object); else if(obj_type==ObjectType::Trigger) openEditingForm(object); else if(obj_type==ObjectType::Index) openEditingForm(object); else if(obj_type==ObjectType::Rule) openEditingForm(object); else openEditingForm(object); listObjects(obj_type); if(obj_type == ObjectType::Constraint) listObjects(ObjectType::Column); } catch(Exception &e) { listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::showObjectData(TableObject *object, int row) { ObjectsTableWidget *tab=nullptr; Column *column=nullptr; Constraint *constr=nullptr; Trigger *trigger=nullptr; Rule *rule=nullptr; Index *index=nullptr; Policy *policy=nullptr; ObjectType obj_type; QString str_aux, str_aux1; QStringList contr_types={ ~ConstraintType(ConstraintType::PrimaryKey), ~ConstraintType(ConstraintType::ForeignKey), ~ConstraintType(ConstraintType::Check), ~ConstraintType(ConstraintType::Unique), QString("NOT NULL") }, constr_codes={ TableObjectView::TextPrimaryKey, TableObjectView::TextForeignKey, TableObjectView::TextCheck, TableObjectView::TextUnique, TableObjectView::TextNotNull}; QFont font; unsigned i; EventType events[]={ EventType::OnInsert, EventType::OnDelete, EventType::OnTruncate, EventType::OnUpdate }; obj_type=object->getObjectType(); tab=objects_tab_map[obj_type]; if(obj_type==ObjectType::Column) tab->setCellText(object->getName(),row,1); else tab->setCellText(object->getName(),row,0); //For each object type there is a use for the columns from 1 to 3 if(obj_type==ObjectType::Column) { PhysicalTable *table = dynamic_cast(this->object); Constraint *pk = table->getPrimaryKey(); column=dynamic_cast(object); //Column 2: Column data type tab->setCellText(*column->getType(),row,2); //Column 3: Column defaul value if(column->getSequence()) str_aux=QString("nextval('%1'::regclass)").arg(column->getSequence()->getName(true).remove('"')); else if(column->getIdentityType() != BaseType::Null) str_aux=QString("GENERATED %1 AS IDENTITY").arg(~column->getIdentityType()); else str_aux=column->getDefaultValue(); if(str_aux.isEmpty()) str_aux=QString("-"); tab->setCellText(str_aux,row,3); //Column 4: Column attributes (constraints which belongs) str_aux=TableObjectView::getConstraintString(column); for(int i=0; i < constr_codes.size(); i++) { if(str_aux.indexOf(constr_codes[i]) >= 0) str_aux1+=contr_types[i] + QString(", "); } if(str_aux1.isEmpty()) str_aux1=QString("-"); else str_aux1.remove(str_aux1.size()-2, 2); tab->setCellText(str_aux1,row,4); if(str_aux.indexOf(TableObjectView::TextPrimaryKey) >= 0) tab->setCellCheckState(row, 0, Qt::Checked); else tab->setCellCheckState(row, 0, Qt::Unchecked); if(column->isAddedByRelationship() || (pk && pk->isAddedByRelationship())) tab->setCellDisabled(row, 0, true); tab->setCellText(column->getAlias(), row, 5); tab->adjustColumnToContents(0); } else if(obj_type==ObjectType::Constraint) { constr=dynamic_cast(object); //Column 1: Constraint type tab->setCellText(~constr->getConstraintType(),row,1); if(constr->getConstraintType()==ConstraintType::ForeignKey) { //Column 2: ON DELETE action tab->setCellText(~constr->getActionType(false),row,2); //Column 3: ON UPDATE action tab->setCellText(~constr->getActionType(true),row,3); } else { tab->setCellText(QString("-"),row,2); tab->setCellText(QString("-"),row,3); } tab->setCellText(constr->getAlias(), row, 4); } else if(obj_type==ObjectType::Trigger) { trigger=dynamic_cast(object); //Column 1: Table referenced by the trigger (constraint trigger) tab->clearCellText(row,1); if(trigger->getReferencedTable()) tab->setCellText(trigger->getReferencedTable()->getName(true),row,1); //Column 2: Trigger firing type tab->setCellText(~trigger->getFiringType(),row,2); //Column 3: Events that fires the trigger for(i=0; i < 4; i++) { if(trigger->isExecuteOnEvent(events[i])) str_aux+=~events[i] + QString(", "); } str_aux.remove(str_aux.size()-2, 2); tab->setCellText(str_aux ,row,3); tab->setCellText(trigger->getAlias(), row, 4); } else if(obj_type==ObjectType::Rule) { rule=dynamic_cast(object); //Column 1: Rule execution type tab->setCellText(~rule->getExecutionType(),row,1); //Column 2: Rule event type tab->setCellText(~rule->getEventType(),row,2); tab->setCellText(rule->getAlias(), row, 3); } else if(obj_type==ObjectType::Index) { index=dynamic_cast(object); //Coluna 1: Indexing type tab->setCellText(~index->getIndexingType(),row,1); tab->setCellText(index->getAlias(), row, 2); } else if(obj_type==ObjectType::Policy) { QStringList rol_names; policy = dynamic_cast(object); //Column 1: Command tab->setCellText(~policy->getPolicyCommand(), row, 1); //Column 2: Permissive tab->setCellText(QString("%1").arg(policy->isPermissive() ? trUtf8("Yes") : trUtf8("No")), row, 2); //Column 3: USING expression tab->setCellText(policy->getUsingExpression(), row, 3); //Column 4: CHECK expression tab->setCellText(policy->getCheckExpression(), row, 4); for(auto role : policy->getRoles()) rol_names.append(role->getName()); //Column 5: Roles tab->setCellText(!rol_names.isEmpty() ? rol_names.join(", ") : QString("PUBLIC"), row, 5); tab->setCellText(policy->getAlias(), row, 6); } //Changes the foreground/background color of the table row if the object is protected or added by relationship if(object->isAddedByRelationship() || object->isProtected()) { font=tab->font(); font.setItalic(true); if(object->isAddedByRelationship()) tab->setRowFont(row, font, RelAddedRowFgColor, RelAddedRowBgColor); else tab->setRowFont(row, font, ProtRowFgColor, ProtRowBgColor); } tab->setCellText(object->getComment(), row, tab->getColumnCount() - 1); tab->setRowData(QVariant::fromValue(object), row); } void TableWidget::removeObjects(void) { PhysicalTable *table=nullptr; unsigned count, op_count=0, i; BaseObject *object=nullptr; ObjectType obj_type=ObjectType::BaseObject; try { table=dynamic_cast(this->object); obj_type=getObjectType(sender()); count=table->getObjectCount(obj_type); op_count=op_list->getCurrentSize(); for(i=0; i < count; i++) { object=table->getObject(0, obj_type); if(!object->isProtected() && !dynamic_cast(object)->isAddedByRelationship()) { op_list->registerObject(object, Operation::ObjectRemoved, 0, this->object); table->removeObject(object); } else throw Exception(Exception::getErrorMessage(ErrorCode::RemProtectedObject) .arg(object->getName()) .arg(object->getTypeName()), ErrorCode::RemProtectedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); } if(obj_type == ObjectType::Constraint) listObjects(ObjectType::Column); } catch(Exception &e) { if(op_count < op_list->getCurrentSize()) { count=op_list->getCurrentSize()-op_count; op_list->ignoreOperationChain(true); for(i=0; i < count; i++) { op_list->undoOperation(); op_list->removeLastOperation(); } op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::removeObject(int row) { PhysicalTable *table=nullptr; BaseObject *object=nullptr; ObjectType obj_type=ObjectType::BaseObject; int op_id=-1; try { table=dynamic_cast(this->object); obj_type=getObjectType(sender()); object=table->getObject(row, obj_type); if(!object->isProtected() && !dynamic_cast(object)->isAddedByRelationship()) { op_id=op_list->registerObject(object, Operation::ObjectRemoved, row, this->object); table->removeObject(object); table->setModified(true); } else throw Exception(Exception::getErrorMessage(ErrorCode::RemProtectedObject) .arg(object->getName()) .arg(object->getTypeName()), ErrorCode::RemProtectedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(obj_type == ObjectType::Constraint) listObjects(ObjectType::Column); } catch(Exception &e) { //If operation was registered if(op_id >= 0) { op_list->ignoreOperationChain(true); op_list->removeLastOperation(); op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::duplicateObject(int sel_row, int new_row) { ObjectType obj_type=ObjectType::BaseObject; BaseObject *object=nullptr, *dup_object=nullptr; ObjectsTableWidget *obj_table=nullptr; PhysicalTable *table = dynamic_cast(this->object); int op_id = -1; try { obj_type=getObjectType(sender()); //Selects the object table based upon the passed object type obj_table=getObjectTable(obj_type); //Gets the object reference if there is an item select on table if(sel_row >= 0) object = reinterpret_cast(obj_table->getRowData(sel_row).value()); PgModelerNs::copyObject(&dup_object, object, obj_type); dup_object->setName(PgModelerNs::generateUniqueName(dup_object, *table->getObjectList(obj_type), false, QString("_cp"))); op_id=op_list->registerObject(dup_object, Operation::ObjectCreated, new_row, this->object); table->addObject(dup_object); table->setModified(true); listObjects(obj_type); } catch(Exception &e) { //If operation was registered if(op_id >= 0) { op_list->ignoreOperationChain(true); op_list->removeLastOperation(); op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::swapObjects(int idx1, int idx2) { ObjectType obj_type=ObjectType::BaseObject; PhysicalTable *table=nullptr; int count; try { obj_type=getObjectType(sender()); table=dynamic_cast(this->object); count=table->getObjectCount(obj_type); if(idx1 >= count) //Special case 1: the object was moved to the first row, its index is swapped with index 0 op_list->updateObjectIndex(table->getObject(idx2, obj_type), 0); else if(idx2 >= count) //Special case 2: the object was moved to the last row, its index is swapped with index count-1 op_list->updateObjectIndex(table->getObject(idx1, obj_type), count-1); else { op_list->updateObjectIndex(table->getObject(idx1, obj_type), idx2); op_list->updateObjectIndex(table->getObject(idx2, obj_type), idx1); } table->swapObjectsIndexes(obj_type, idx1, idx2); } catch(Exception &e) { listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::editData(void) { BaseForm base_form(this); TableDataWidget *tab_data_wgt=new TableDataWidget(this); tab_data_wgt->setAttributes(this->model, dynamic_cast(this->object)); base_form.setMainWidget(tab_data_wgt); base_form.setButtonConfiguration(Messagebox::OkCancelButtons); GeneralConfigWidget::restoreWidgetGeometry(&base_form, tab_data_wgt->metaObject()->className()); base_form.exec(); GeneralConfigWidget::saveWidgetGeometry(&base_form, tab_data_wgt->metaObject()->className()); } void TableWidget::applyConfiguration(void) { try { PhysicalTable *table=nullptr; Table *aux_tab = nullptr; Constraint *pk = nullptr; vector rels; vector pk_cols; vector part_keys; ObjectsTableWidget *col_tab = objects_tab_map[ObjectType::Column]; PartitioningType part_type; if(!this->new_object) op_list->registerObject(this->object, Operation::ObjectModified); else registerNewObject(); table=dynamic_cast(this->object); aux_tab = dynamic_cast
(table); table->setGenerateAlterCmds(gen_alter_cmds_chk->isChecked()); table->setTag(dynamic_cast(tag_sel->getSelectedObject())); // Applying settings specific to table if(aux_tab) { aux_tab->setWithOIDs(with_oids_chk->isChecked()); aux_tab->setRLSEnabled(enable_rls_chk->isChecked()); aux_tab->setRLSForced(force_rls_chk->isChecked()); aux_tab->setUnlogged(unlogged_chk->isChecked()); } // Applying settings specific to foreign table else if(server_sel->isVisible()) { ForeignTable *ftable = dynamic_cast(table); ftable->setForeignServer(dynamic_cast(server_sel->getSelectedObject())); ftable->removeOptions(); for(unsigned row = 0; row < options_tab->getRowCount(); row++) ftable->setOption(options_tab->getCellText(row, 0), options_tab->getCellText(row, 1)); } part_type = partitioning_type_cmb->currentIndex() == 0 ? BaseType::Null : PartitioningType(partitioning_type_cmb->currentText()); table->setPartitioningType(part_type); if(part_type != BaseType::Null) { partition_keys_tab->getElements(part_keys); table->addPartitionKeys(part_keys); if(part_keys.empty()) part_type = BaseType::Null; } BaseObjectWidget::applyConfiguration(); //Retrieving all columns marked as primary key for(unsigned row = 0; row < col_tab->getRowCount(); row++) { if(col_tab->getCellCheckState(row, 0) == Qt::Checked) pk_cols.push_back(reinterpret_cast(col_tab->getRowData(row).value())); } pk = table->getPrimaryKey(); //If there is at least one column marked as pk if(!pk_cols.empty()) { if(!pk) { //Create the primary key if the table does not own one QString pk_name = QString("%1_pk").arg(table->getName()); pk = new Constraint; pk->setName(pk_name); pk->setName(PgModelerNs::generateUniqueName(pk, *table->getObjectList(ObjectType::Constraint))); for(Column *col : pk_cols) pk->addColumn(col, Constraint::SourceCols); table->addConstraint(pk); op_list->registerObject(pk, Operation::ObjectCreated, -1, table); } else if(!pk->isAddedByRelationship()) { vector orig_pk_cols = pk->getColumns(Constraint::SourceCols); //If the table owns a pk we only update the columns op_list->registerObject(pk, Operation::ObjectModified, -1, table); pk->removeColumns(); /* Adding the original primary key columns if they also exists in the * list of columns generated by the selection in the column list */ for(auto col : orig_pk_cols) { if(std::find(pk_cols.begin(), pk_cols.end(), col) != pk_cols.end()) pk->addColumn(col, Constraint::SourceCols); } /* Adding the other columns selected in the grid as pk columns. * Duplicated columns are discarded by the method Constraint::addColumn */ for(Column *col : pk_cols) pk->addColumn(col, Constraint::SourceCols); } } else if(pk_cols.empty() && pk && !pk->isAddedByRelationship()) { //Removing the primary key from the table when no column is checked as pk op_list->registerObject(pk, Operation::ObjectRemoved, -1, table); table->removeObject(pk); } try { table->saveRelObjectsIndexes(); if(model->getRelationship(table, nullptr)) model->validateRelationships(); if(aux_tab) model->updateTableFKRelationships(aux_tab); model->updateViewsReferencingTable(table); } catch(Exception &e) { Messagebox msg_box; if(e.getErrorCode()==ErrorCode::RemInvalidatedObjects) msg_box.show(e); else throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } op_list->finishOperationChain(); finishConfiguration(); if(RelationshipView::getLineConnectinMode()==RelationshipView::ConnectFkToPk) { /* Forcing the update of relationships connected to the table in order to reconfigure the line in case of the relationship is using the CONNECT_FK_TO_PK line mode */ rels=model->getRelationships(table); for(auto &rel : rels) { if(rel->getRelationshipType()==Relationship::Relationship11 || rel->getRelationshipType()==Relationship::Relationship1n || rel->getRelationshipType()==Relationship::RelationshipFk) rel->setModified(true); } } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TableWidget::cancelConfiguration(void) { BaseObjectWidget::cancelChainedOperation(); } pgmodeler-0.9.2/libpgmodeler_ui/src/tablewidget.h000066400000000000000000000066521360462764600221240ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TableWidget \brief Implements the operations to create/edit tables via form. */ #ifndef TABLE_WIDGET_H #define TABLE_WIDGET_H #include "baseobjectwidget.h" #include "ui_tablewidget.h" #include "objectstablewidget.h" #include "tableview.h" #include "elementstablewidget.h" class TableWidget: public BaseObjectWidget, public Ui::TableWidget { private: Q_OBJECT ObjectsTableWidget *parent_tables, *options_tab; ElementsTableWidget *partition_keys_tab; ObjectSelectorWidget *tag_sel, *server_sel; QFrame *warn_frame; //! \brief Stores the objects tables used to handle columns, constraints, indexes, rules and triggers map objects_tab_map; //! \brief Lists (on the correct object table) the table objects according to the specified type void listObjects(ObjectType obj_type); //! \brief Shows the specified object data at the correct object table, at specified row void showObjectData(TableObject *object, int row); //! \brief Returns the object table according with the child type ObjectsTableWidget *getObjectTable(ObjectType obj_type); //! \brief Returns the object type according to the widget (in this case a object table) that called the method ObjectType getObjectType(QObject *sender); /*! \brief Template method that opens the editing form for the specified object. Class and ClassWidget should be compatible, e.g., "Column" can only be edited using ColumnWidget */ template int openEditingForm(TableObject *object); void __setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, PhysicalTable *table, double pos_x, double pos_y); public: TableWidget(QWidget * parent = nullptr, ObjectType tab_type = ObjectType::Table); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Table *table, double pos_x, double pos_y); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, ForeignTable *ftable, double pos_x, double pos_y); private slots: //! \brief Adds or edit a object on the object table that calls the slot void handleObject(void); //! \brief Removes the selected object from the table that calls the slot void removeObject(int row); //! \brief Duplicate the selected object. This method will desambigate names if needed void duplicateObject(int sel_row, int new_row); //! \brief Removes all objects from the table that calls the slot void removeObjects(void); //! \brief Swap the index between two rows of the table that calls the slot void swapObjects(int idx1, int idx2); void editData(void); public slots: void applyConfiguration(void); void cancelConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/tagwidget.cpp000066400000000000000000000066031360462764600221370ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "tagwidget.h" TagWidget::TagWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Tag) { Ui_TagWidget::setupUi(this); configureFormLayout(tag_grid, ObjectType::Tag); QStringList attribs={ Attributes::TableName, Attributes::TableSchemaName, Attributes::TableTitle, Attributes::TableBody, Attributes::TableExtBody }; unsigned color_count=1; int row=0; for(auto &attr : attribs) { if(color_count==1 && attr!=Attributes::TableName && attr!=Attributes::TableSchemaName) color_count=3; color_pickers[attr]=new ColorPickerWidget(color_count, this); colors_grid->addWidget(color_pickers[attr], row, 1); colors_grid->addItem(new QSpacerItem(10,10, QSizePolicy::Expanding, QSizePolicy::Fixed), row, 2); row++; } setMinimumSize(450, 220); } void TagWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Tag *tag) { unsigned color_count=1, i; QStringList attribs={ Attributes::TableName, Attributes::TableSchemaName, Attributes::TableTitle, Attributes::TableBody, Attributes::TableExtBody }; BaseObjectWidget::setAttributes(model, op_list, tag); for(auto &attr : attribs) { if(color_count==1 && attr!=Attributes::TableName && attr!=Attributes::TableSchemaName) color_count=3; for(i=0; i < color_count; i++) { if(tag) color_pickers[attr]->setColor(i, tag->getElementColor(attr, i)); else color_pickers[attr]->setColor(i, BaseObjectView::getElementColor(attr, i)); } } } void TagWidget::applyConfiguration(void) { try { Tag *tag=nullptr; vector tagged_tabs; QStringList attribs={ Attributes::TableTitle, Attributes::TableBody, Attributes::TableExtBody }; startConfiguration(); tag=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); tag->setElementColor(Attributes::TableName, color_pickers[Attributes::TableName]->getColor(0), Tag::FillColor1); tag->setElementColor(Attributes::TableSchemaName, color_pickers[Attributes::TableSchemaName]->getColor(0), Tag::FillColor1); for(auto &attr : attribs) { tag->setElementColors(attr, QString("%1,%2,%3") .arg(color_pickers[attr]->getColor(Tag::FillColor1).name()) .arg(color_pickers[attr]->getColor(Tag::FillColor2).name()) .arg(color_pickers[attr]->getColor(Tag::BorderColor).name())); } model->getObjectReferences(tag, tagged_tabs); while(!tagged_tabs.empty()) { dynamic_cast(tagged_tabs.back())->setModified(true); tagged_tabs.pop_back(); } finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/tagwidget.h000066400000000000000000000027131360462764600216020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TagWidget \brief Implements the operations to create/edit tags via form. */ #ifndef TAG_WIDGET_H #define TAG_WIDGET_H #include "baseobjectwidget.h" #include "colorpickerwidget.h" #include "ui_tagwidget.h" class TagWidget: public BaseObjectWidget, public Ui::TagWidget { private: Q_OBJECT /*! \brief Stores all color picker using the attribute the represents as map key. These attributes are: TABLE_NAME, TABLE_SCHEMA_NAME, TABLE_TITLE, TABLE_BODY, TABLE_EXT_BODY */ map color_pickers; public: TagWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Tag *tag); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/taskprogresswidget.cpp000066400000000000000000000056511360462764600241150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "taskprogresswidget.h" #include "baseobject.h" #include "pgmodeleruins.h" TaskProgressWidget::TaskProgressWidget(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { vector obj_types=BaseObject::getObjectTypes(true); setupUi(this); this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); for(auto &obj_tp : obj_types) addIcon(enum_cast(obj_tp), QIcon(PgModelerUiNs::getIconPath(obj_tp))); } void TaskProgressWidget::addIcon(unsigned id, const QIcon &ico) { icons[id]=ico; } void TaskProgressWidget::show(void) { /* Using a event loop as a workaround to give a little time to task progress to be shown before start the progress update. In tasks too quick, if the event loop above isn't used the task is not shown properly and sometimes stay only on taskbar not poping up to the user. */ QEventLoop eventLoop; PgModelerUiNs::resizeDialog(this); QDialog::show(); QTimer t; //Gives 100ms to the task to be shown and update its contents t.singleShot(100, &eventLoop, SLOT(quit(void))); text_lbl->setText(trUtf8("Waiting task to start...")); eventLoop.exec(QEventLoop::AllEvents); } void TaskProgressWidget::updateProgress(int progress, unsigned icon_id) { updateProgress(progress, QString(), icon_id); } void TaskProgressWidget::updateProgress(int progress, QString text, unsigned icon_id) { if(progress > progress_pb->maximum()) progress=progress_pb->maximum(); progress_pb->setValue(progress); if(!text.isEmpty()) text_lbl->setText(PgModelerUiNs::formatMessage(text)); if(icons.count(icon_id)) icon_lbl->setPixmap(icons[icon_id].pixmap(QSize(32,32))); else icon_lbl->clear(); this->repaint(); /* MacOSX workaround: The event loop below is needed because on this system the task progress is not correctly updated. The event loop causes a little delay (1ms) and it`s sufficient to update the entire widget */ #ifdef Q_OS_MAC QEventLoop eventLoop; QTimer t; //Gives 1ms to the task to be shown and update its contents t.singleShot(1, &eventLoop, SLOT(quit(void))); eventLoop.exec(QEventLoop::AllEvents); #endif } void TaskProgressWidget::close(void) { QDialog::close(); progress_pb->setValue(0); text_lbl->clear(); icon_lbl->clear(); } pgmodeler-0.9.2/libpgmodeler_ui/src/taskprogresswidget.h000066400000000000000000000031271360462764600235560ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TaskProgressWidget \brief Implements a widget that shows the progress of executed operations (e.g. loading a model file, generation source code) */ #ifndef TASK_PROGRESS_WIDGET_H #define TASK_PROGRESS_WIDGET_H #include #include "ui_taskprogresswidget.h" #include using namespace std; class TaskProgressWidget: public QDialog, public Ui::TaskProgressWidget { private: Q_OBJECT //! \brief Stores the icons that are shown as the icons tokens are send via updateProgress() slot map icons; public: TaskProgressWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Widget); void addIcon(unsigned id, const QIcon &ico); public slots: void show(void); void close(void); void updateProgress(int progress, unsigned icon_id); void updateProgress(int progress, QString text, unsigned icon_id); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/textboxwidget.cpp000066400000000000000000000056231360462764600230620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "textboxwidget.h" TextboxWidget::TextboxWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Textbox) { Ui_TextboxWidget::setupUi(this); configureFormLayout(textbox_grid, ObjectType::Textbox); text_txt->removeEventFilter(this); connect(color_select_tb, SIGNAL(clicked(void)), this, SLOT(selectTextColor(void))); setMinimumSize(500, 200); } void TextboxWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Textbox *txtbox, double obj_px, double obj_py) { if(txtbox) { QPalette palette; palette.setColor(QPalette::Button, txtbox->getTextColor()); color_select_tb->setPalette(palette); text_txt->setPlainText(txtbox->getComment()); bold_chk->setChecked(txtbox->getTextAttribute(Textbox::BoldText)); italic_chk->setChecked(txtbox->getTextAttribute(Textbox::ItalicText)); underline_chk->setChecked(txtbox->getTextAttribute(Textbox::UnderlineText)); font_size_sb->setValue(txtbox->getFontSize()); } BaseObjectWidget::setAttributes(model, op_list, txtbox, nullptr, obj_px, obj_py); } void TextboxWidget::selectTextColor(void) { QColorDialog color_dlg; QPalette palette; color_dlg.setWindowTitle(trUtf8("Select text color")); color_dlg.setCurrentColor(color_select_tb->palette().color(QPalette::Button)); color_dlg.exec(); if(color_dlg.result()==QDialog::Accepted) { palette.setColor(QPalette::Button, color_dlg.selectedColor()); color_select_tb->setPalette(palette); } } void TextboxWidget::applyConfiguration(void) { try { Textbox *txtbox=nullptr; startConfiguration(); txtbox=dynamic_cast(this->object); txtbox->setComment(text_txt->toPlainText().toUtf8()); txtbox->setTextAttribute(Textbox::ItalicText, italic_chk->isChecked()); txtbox->setTextAttribute(Textbox::BoldText, bold_chk->isChecked()); txtbox->setTextAttribute(Textbox::UnderlineText, underline_chk->isChecked()); txtbox->setTextColor(color_select_tb->palette().color(QPalette::Button)); txtbox->setFontSize(font_size_sb->value()); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/textboxwidget.h000066400000000000000000000025071360462764600225250ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TextboxWidget \brief Implements the operations to create/edit textboxes via form. */ #ifndef TEXTBOX_WIDGET_H #define TEXTBOX_WIDGET_H #include "ui_textboxwidget.h" #include "baseobjectwidget.h" class TextboxWidget: public BaseObjectWidget, public Ui::TextboxWidget { private: Q_OBJECT public: TextboxWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Textbox *txtbox=nullptr, double obj_px=DNaN, double obj_py=DNaN); private slots: void selectTextColor(void); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/triggerwidget.cpp000066400000000000000000000262071360462764600230310ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "triggerwidget.h" TriggerWidget::TriggerWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Trigger) { try { QStringList list; Ui_TriggerWidget::setupUi(this); cond_expr_hl=new SyntaxHighlighter(cond_expr_txt, false, true); cond_expr_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); columns_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton | ObjectsTableWidget::DuplicateButton), true, this); arguments_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::DuplicateButton, true, this); ref_table_sel=new ObjectSelectorWidget(ObjectType::Table, true, this); function_sel=new ObjectSelectorWidget(ObjectType::Function, true, this); ref_table_sel->setEnabled(false); trigger_grid->addWidget(function_sel, 3, 1, 1, 5); columns_tab->setColumnCount(2); columns_tab->setHeaderLabel(trUtf8("Column"), 0); columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("column")),0); columns_tab->setHeaderLabel(trUtf8("Type"), 1); columns_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); dynamic_cast(arg_cols_tbw->widget(1)->layout())->addWidget(columns_tab, 1,0,1,3); dynamic_cast(arg_cols_tbw->widget(0)->layout())->addWidget(arguments_tab, 1,0,1,3); dynamic_cast(arg_cols_tbw->widget(2)->layout())->addWidget(ref_table_sel, 1, 1, 1, 1); DeferralType::getTypes(list); deferral_type_cmb->addItems(list); FiringType::getTypes(list); firing_mode_cmb->addItems(list); configureFormLayout(trigger_grid, ObjectType::Trigger); connect(deferrable_chk, SIGNAL(toggled(bool)), deferral_type_cmb, SLOT(setEnabled(bool))); connect(columns_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addColumn(int))); connect(columns_tab, SIGNAL(s_rowRemoved(int)), this, SLOT(updateColumnsCombo(void))); connect(columns_tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(updateColumnsCombo(void))); connect(arguments_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleArgument(int))); connect(arguments_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleArgument(int))); connect(arguments_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editArgument(int))); connect(constraint_rb, SIGNAL(toggled(bool)), this, SLOT(setConstraintTrigger(bool))); connect(update_chk, SIGNAL(toggled(bool)), this, SLOT(selectUpdateEvent(void))); connect(insert_chk, SIGNAL(toggled(bool)), this, SLOT(enableTransitionTableNames())); connect(delete_chk, SIGNAL(toggled(bool)), this, SLOT(enableTransitionTableNames())); connect(update_chk, SIGNAL(toggled(bool)), this, SLOT(enableTransitionTableNames())); connect(truncate_chk, SIGNAL(toggled(bool)), this, SLOT(enableTransitionTableNames())); connect(firing_mode_cmb, SIGNAL(currentIndexChanged(int)), this, SLOT(enableTransitionTableNames())); setRequiredField(event_lbl); setRequiredField(firing_mode_lbl); setRequiredField(function_lbl); setRequiredField(function_sel); setMinimumSize(580, 500); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TriggerWidget::selectUpdateEvent(void) { if(!update_chk->isChecked()) columns_tab->removeRows(); /* Disable the columns tab when the trigger belongs to a view. pgModeler does not support triggers reference view columns (yet) */ arg_cols_tbw->widget(1)->setEnabled(update_chk->isChecked() && table->getObjectType()==ObjectType::Table); } void TriggerWidget::setConstraintTrigger(bool value) { exec_per_row_chk->setEnabled(!value); exec_per_row_chk->setChecked(value); ref_table_sel->setEnabled(value); ref_table_lbl->setEnabled(value); deferrable_chk->setEnabled(value); firing_mode_cmb->setEnabled(!value); if(!value) { ref_table_sel->clearSelector(); deferrable_chk->setChecked(false); } else firing_mode_cmb->setCurrentText(~FiringType(FiringType::After)); } void TriggerWidget::enableTransitionTableNames(void) { int num_evnts = 0; QWidget *wgt = nullptr; QCheckBox *chk = nullptr; FiringType firing_type = firing_mode_cmb->currentText(); for(auto &obj : events_wgt->children()) { wgt = qobject_cast(obj); chk = dynamic_cast(wgt); if(chk && chk->isChecked()) num_evnts++; } old_table_edt->setEnabled(firing_type == FiringType::After && num_evnts == 1 && (update_chk->isChecked() || delete_chk->isChecked())); new_table_edt->setEnabled(firing_type == FiringType::After && num_evnts == 1 && (update_chk->isChecked() || insert_chk->isChecked())); } void TriggerWidget::addColumn(int lin_idx) { Column *column=nullptr; try { column=reinterpret_cast(column_cmb->itemData(column_cmb->currentIndex(),Qt::UserRole).value()); column_cmb->removeItem(column_cmb->currentIndex()); addColumn(column, lin_idx); columns_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (column_cmb->count()!=0)); } catch(Exception &e) { columns_tab->removeRow(lin_idx); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TriggerWidget::addColumn(Column *column, int row) { if(column && row >= 0) { columns_tab->setCellText(column->getName(),row,0); columns_tab->setCellText(~column->getType(),row,1); columns_tab->setRowData(QVariant::fromValue(column), row); } } void TriggerWidget::updateColumnsCombo(void) { Column *column=nullptr; unsigned i, col_count=0; try { if(this->table->getObjectType()==ObjectType::Table) { col_count=table->getObjectCount(ObjectType::Column); column_cmb->clear(); for(i=0; i < col_count; i++) { column=dynamic_cast(table->getObject(i, ObjectType::Column)); if(columns_tab->getRowIndex(QVariant::fromValue(column)) < 0) { column_cmb->addItem(column->getName() + QString(" (") + ~column->getType() + QString(")"), QVariant::fromValue(column)); } } columns_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (column_cmb->count()!=0)); } } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TriggerWidget::handleArgument(int lin_idx) { if(!argument_edt->text().isEmpty()) { arguments_tab->setCellText(argument_edt->text(), lin_idx, 0); argument_edt->clear(); } else if(arguments_tab->getCellText(lin_idx, 0).isEmpty()) arguments_tab->removeRow(lin_idx); } void TriggerWidget::editArgument(int lin_idx) { argument_edt->setText(arguments_tab->getCellText(lin_idx, 0)); } void TriggerWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseTable *parent_table, Trigger *trigger) { unsigned count=0, i; Column *column=nullptr; if(!parent_table) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); BaseObjectWidget::setAttributes(model, op_list, trigger, parent_table); ref_table_sel->setModel(model); function_sel->setModel(model); if(trigger) { constraint_rb->setChecked(trigger->isConstraint()); exec_per_row_chk->setChecked(trigger->isExecutePerRow()); cond_expr_txt->setPlainText(trigger->getCondition()); deferrable_chk->setChecked(trigger->isDeferrable()); deferral_type_cmb->setCurrentIndex(deferral_type_cmb->findText(~trigger->getDeferralType())); firing_mode_cmb->setCurrentIndex(firing_mode_cmb->findText(~trigger->getFiringType())); insert_chk->setChecked(trigger->isExecuteOnEvent(EventType::OnInsert)); delete_chk->setChecked(trigger->isExecuteOnEvent(EventType::OnDelete)); update_chk->setChecked(trigger->isExecuteOnEvent(EventType::OnUpdate)); truncate_chk->setChecked(trigger->isExecuteOnEvent(EventType::OnTruncate)); ref_table_sel->setSelectedObject(trigger->getReferencedTable()); function_sel->setSelectedObject(trigger->getFunction()); columns_tab->blockSignals(true); arguments_tab->blockSignals(true); count=trigger->getColumnCount(); for(i=0; i < count; i++) { column=trigger->getColumn(i); columns_tab->addRow(); addColumn(column, i); } count=trigger->getArgumentCount(); for(i=0; i < count; i++) { arguments_tab->addRow(); arguments_tab->setCellText(trigger->getArgument(i), i, 0); } columns_tab->setButtonsEnabled(ObjectsTableWidget::AddButton, (column_cmb->count()!=0)); arguments_tab->blockSignals(false); columns_tab->blockSignals(false); old_table_edt->setText(trigger->getTransitionTableName(Trigger::OldTableName)); new_table_edt->setText(trigger->getTransitionTableName(Trigger::NewTableName)); } updateColumnsCombo(); } void TriggerWidget::applyConfiguration(void) { try { Trigger *trigger=nullptr; unsigned i, count; Column *column=nullptr; startConfiguration(); trigger=dynamic_cast(this->object); trigger->setConstraint(constraint_rb->isChecked()); trigger->setFiringType(FiringType(firing_mode_cmb->currentText())); trigger->setExecutePerRow(exec_per_row_chk->isChecked()); trigger->setDeferrable(deferrable_chk->isChecked()); trigger->setDeferralType(DeferralType(deferral_type_cmb->currentText())); trigger->setCondition(cond_expr_txt->toPlainText()); trigger->setFunction(dynamic_cast(function_sel->getSelectedObject())); trigger->setReferecendTable(dynamic_cast
(ref_table_sel->getSelectedObject())); trigger->setEvent(EventType::OnInsert, insert_chk->isChecked()); trigger->setEvent(EventType::OnUpdate, update_chk->isChecked()); trigger->setEvent(EventType::OnDelete, delete_chk->isChecked()); trigger->setEvent(EventType::OnTruncate, truncate_chk->isChecked()); trigger->setTransitionTableName(Trigger::OldTableName, old_table_edt->isEnabled() ? old_table_edt->text() : QString()); trigger->setTransitionTableName(Trigger::NewTableName, new_table_edt->isEnabled() ? new_table_edt->text() : QString()); trigger->removeArguments(); trigger->removeColumns(); count=arguments_tab->getRowCount(); for(i=0; i < count; i++) trigger->addArgument(arguments_tab->getCellText(i, 0)); count=columns_tab->getRowCount(); for(i=0; i < count; i++) { column=reinterpret_cast(columns_tab->getRowData(i).value()); trigger->addColumn(column); } if(!this->new_object) trigger->validateTrigger(); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/triggerwidget.h000066400000000000000000000037351360462764600224770ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TriggerWidget \brief Implements the operations to create/edit triggers via form. */ #ifndef TRIGGER_WIDGET_H #define TRIGGER_WIDGET_H #include "baseobjectwidget.h" #include "ui_triggerwidget.h" #include "objectstablewidget.h" class TriggerWidget: public BaseObjectWidget, public Ui::TriggerWidget { private: Q_OBJECT //! \brief Conditional expression syntax highlighter SyntaxHighlighter *cond_expr_hl; //! \brief Object tables used to control columns and agruments ObjectsTableWidget *columns_tab, *arguments_tab; //! \brief Selectors for reference table and trigger function ObjectSelectorWidget *ref_table_sel, *function_sel; //! \brief Adds a column to the referenced columns table void addColumn(Column *column, int row); public: TriggerWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, BaseTable *parent_table, Trigger *trigger); private slots: void addColumn(int lin_idx); void selectUpdateEvent(void); void handleArgument(int lin_idx); void editArgument(int lin_idx); void updateColumnsCombo(void); void setConstraintTrigger(bool value); void enableTransitionTableNames(void); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/typewidget.cpp000066400000000000000000000325371360462764600223520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "typewidget.h" TypeWidget::TypeWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::Type) { try { QGridLayout *grid=nullptr; QFrame *frame=nullptr; QStringList list; unsigned i,i1; Ui_TypeWidget::setupUi(this); configureFormLayout(type_grid, ObjectType::Type); like_type=new PgSQLTypeWidget(this, trUtf8("Like Type")); element_type=new PgSQLTypeWidget(this, trUtf8("Element Type")); range_subtype=new PgSQLTypeWidget(this, trUtf8("Subtype")); grid=dynamic_cast(base_attribs_twg->widget(1)->layout()); grid->addWidget(like_type,6,0,1,0); grid->addWidget(element_type,7,0,1,0); grid->addItem(new QSpacerItem(20, 1, QSizePolicy::Minimum, QSizePolicy::Expanding),8,0); grid=dynamic_cast(base_attribs_twg->widget(0)->layout()); for(i=Type::InputFunc; i <= Type::AnalyzeFunc; i++) { functions_sel[i]=nullptr; functions_sel[i]=new ObjectSelectorWidget(ObjectType::Function, true, this); grid->addWidget(functions_sel[i],i,1,1,1); } enumerations_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::DuplicateButton), true, this); grid=dynamic_cast(enumerations_gb->layout()); grid->addWidget(enumerations_tab,1,0,1,2); enumerations_gb->setVisible(false); attributes_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::DuplicateButton, true, this); attributes_tab->setColumnCount(3); attributes_tab->setHeaderLabel(trUtf8("Name"),0); attributes_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); attributes_tab->setHeaderLabel(trUtf8("Type"),1); attributes_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("usertype")),1); attributes_tab->setHeaderLabel(trUtf8("Collation"),2); attributes_tab->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("collation")),2); grid=dynamic_cast(attributes_gb->layout()); attrib_collation_sel=new ObjectSelectorWidget(ObjectType::Collation, true, this); grid->addWidget(attrib_collation_sel, 1,1,1,2); attrib_type_wgt=new PgSQLTypeWidget(this); grid->addWidget(attrib_type_wgt,2,0,1,2); grid->addWidget(attributes_tab,3,0,1,2); attributes_gb->setVisible(false); grid=dynamic_cast(base_attribs_twg->widget(0)->layout()); frame=generateInformationFrame(trUtf8("The functions to be assigned to a type should be written in C language and possess, respectively, the following signatures:
INPUT: any function(cstring, oid, integer) OUTPUT: cstring function(any)
SEND: byta function(any) RECV: any function(internal, oid, integer)
TPMOD_IN: integer function(cstring[]) TPMOD_OUT: cstring function(integer)
ANALYZE: boolean function(internal)
")); grid->addItem(new QSpacerItem(20, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), grid->count()+1,0); grid->addWidget(frame, grid->count()+1, 0, 1, 0); frame->setParent(base_attribs_twg->widget(0)); grid=dynamic_cast(range_attribs_gb->layout()); opclass_sel=new ObjectSelectorWidget(ObjectType::OpClass, true, this); grid->addWidget(opclass_sel,0,1,1,1); for(i1=1, i=Type::CanonicalFunc; i <= Type::SubtypeDiffFunc; i++,i1++) { functions_sel[i]=nullptr; functions_sel[i]=new ObjectSelectorWidget(ObjectType::Function, true, this); grid->addWidget(functions_sel[i],i1,1,1,1); } grid->addWidget(range_subtype,3,0,1,2); frame=generateInformationFrame(trUtf8("The functions to be assigned to a range type should have the following signatures:

Canonical: any function(any)
Subtype Diff: double precision function(subtype, subtype)")); grid->addItem(new QSpacerItem(20, 1, QSizePolicy::Minimum, QSizePolicy::Expanding),4,0); grid->addWidget(frame, 5, 0, 1, 0); range_attribs_gb->setVisible(false); //connect(parent_form->apply_ok_btn,SIGNAL(clicked(bool)), this, SLOT(applyConfiguration(void))); connect(base_type_rb, SIGNAL(toggled(bool)), this, SLOT(selectTypeConfiguration(void))); connect(composite_rb, SIGNAL(toggled(bool)), this, SLOT(selectTypeConfiguration(void))); connect(enumeration_rb, SIGNAL(toggled(bool)), this, SLOT(selectTypeConfiguration(void))); connect(enumerations_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleEnumeration(int))); connect(enumerations_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleEnumeration(int))); connect(attributes_tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleAttribute(int))); connect(attributes_tab, SIGNAL(s_rowUpdated(int)), this, SLOT(handleAttribute(int))); connect(attributes_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editAttribute(int))); StorageType::getTypes(list); storage_cmb->addItems(list); CategoryType::getTypes(list); category_cmb->addItems(list); setRequiredField(range_subtype); setRequiredField(input_lbl); setRequiredField(output_lbl); setRequiredField(functions_sel[Type::InputFunc]); setRequiredField(functions_sel[Type::OutputFunc]); setRequiredField(enumerations_gb); setRequiredField(attributes_gb); configureTabOrder({base_type_rb, enumeration_rb, composite_rb, range_rb, enum_name_edt, attrib_name_edt, attrib_collation_sel, attrib_type_wgt, opclass_sel, functions_sel[Type::CanonicalFunc], functions_sel[Type::SubtypeDiffFunc], base_attribs_twg}); setMinimumSize(620, 750); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TypeWidget::selectTypeConfiguration(void) { base_attribs_twg->setVisible(base_type_rb->isChecked()); enumerations_gb->setVisible(enumeration_rb->isChecked()); attributes_gb->setVisible(composite_rb->isChecked()); range_attribs_gb->setVisible(range_rb->isChecked()); collation_sel->setEnabled(range_rb->isChecked()); collation_lbl->setEnabled(range_rb->isChecked()); if(!range_rb->isChecked()) collation_sel->clearSelector(); } void TypeWidget::handleEnumeration(int row) { if(!enum_name_edt->text().isEmpty()) { enumerations_tab->setCellText(enum_name_edt->text(), row, 0); enum_name_edt->clear(); } else if(enumerations_tab->getCellText(row, 0).isEmpty()) enumerations_tab->removeRow(row); } void TypeWidget::showAttributeData(TypeAttribute attrib, int row) { attributes_tab->setCellText(attrib.getName(), row, 0); attributes_tab->setCellText(*attrib.getType(), row, 1); if(attrib.getCollation()) attributes_tab->setCellText(attrib.getCollation()->getName(true), row, 2); else attributes_tab->clearCellText(row,2); attributes_tab->setRowData(QVariant::fromValue(attrib), row); } void TypeWidget::editAttribute(int row) { TypeAttribute attrib=attributes_tab->getRowData(row).value(); attrib_name_edt->setText(attrib.getName()); attrib_collation_sel->setSelectedObject(attrib.getCollation()); attrib_type_wgt->setAttributes(attrib.getType(), this->model); } void TypeWidget::handleAttribute(int row) { try { TypeAttribute attrib; attrib.setName(attrib_name_edt->text().toUtf8()); attrib.setType(attrib_type_wgt->getPgSQLType()); attrib.setCollation(attrib_collation_sel->getSelectedObject()); showAttributeData(attrib, row); attrib_name_edt->clear(); attrib_collation_sel->clearSelector(); } catch(Exception &e) { if(attributes_tab->getCellText(row,0).isEmpty()) attributes_tab->removeRow(row); throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void TypeWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Type *type) { PgSqlType like_tp, elem_tp; unsigned type_conf, i, count; BaseObjectWidget::setAttributes(model, op_list, type, schema); attrib_collation_sel->setModel(model); attrib_type_wgt->setAttributes(PgSqlType(), model); range_subtype->setAttributes(PgSqlType(), model); opclass_sel->setModel(model); for(i=Type::InputFunc; i <= Type::SubtypeDiffFunc; i++) functions_sel[i]->setModel(model); if(type) { type_conf=type->getConfiguration(); if(type_conf==Type::CompositeType) { composite_rb->setChecked(true); attributes_tab->blockSignals(true); count=type->getAttributeCount(); for(i=0; i < count; i++) { attributes_tab->addRow(); showAttributeData(type->getAttribute(i),i); } attributes_tab->blockSignals(false); attributes_tab->clearSelection(); } else if(type_conf==Type::EnumerationType) { enumeration_rb->setChecked(true); enumerations_tab->blockSignals(true); count=type->getEnumerationCount(); for(i=0; i < count; i++) { enumerations_tab->addRow(); enumerations_tab->setCellText(type->getEnumeration(i), i, 0); } enumerations_tab->blockSignals(false); enumerations_tab->clearSelection(); } else if(type_conf==Type::RangeType) { range_rb->setChecked(true); opclass_sel->setSelectedObject(type->getSubtypeOpClass()); range_subtype->setAttributes(type->getSubtype(), model); functions_sel[Type::CanonicalFunc]->setSelectedObject(type->getFunction(Type::CanonicalFunc)); functions_sel[Type::SubtypeDiffFunc]->setSelectedObject(type->getFunction(Type::SubtypeDiffFunc)); } else { base_type_rb->setChecked(true); like_tp=type->getLikeType(); elem_tp=type->getElement(); internal_len_sb->setValue(type->getInternalLength()); by_value_chk->setChecked(type->isByValue()); preferred_chk->setChecked(type->isPreferred()); collatable_chk->setChecked(type->isCollatable()); delimiter_edt->setText(QString(type->getDelimiter())); default_value_edt->setText(type->getDefaultValue()); category_cmb->setCurrentIndex(category_cmb->findText(~type->getCategory())); storage_cmb->setCurrentIndex(storage_cmb->findText(~type->getStorage())); alignment_cmb->setCurrentIndex(alignment_cmb->findText(~type->getAlignment())); for(i=Type::InputFunc; i <= Type::AnalyzeFunc; i++) functions_sel[i]->setSelectedObject(type->getFunction(i)); } } else selectTypeConfiguration(); like_type->setAttributes(like_tp, model); element_type->setAttributes(elem_tp, model); } void TypeWidget::applyConfiguration(void) { try { Type *type=nullptr; unsigned i, count; startConfiguration(); type=dynamic_cast(this->object); BaseObjectWidget::applyConfiguration(); //Configuring an enumaration type if(enumeration_rb->isChecked()) { type->setConfiguration(Type::EnumerationType); count=enumerations_tab->getRowCount(); for(i=0; i < count; i++) type->addEnumeration(enumerations_tab->getCellText(i,0).toUtf8()); } //Configuration a composite type else if(composite_rb->isChecked()) { type->setConfiguration(Type::CompositeType); count=attributes_tab->getRowCount(); for(i=0; i < count; i++) type->addAttribute(attributes_tab->getRowData(i).value()); } //Configuration a range type else if(range_rb->isChecked()) { type->setConfiguration(Type::RangeType); type->setCollation(collation_sel->getSelectedObject()); type->setSubtype(range_subtype->getPgSQLType()); type->setSubtypeOpClass(dynamic_cast(opclass_sel->getSelectedObject())); type->setFunction(Type::CanonicalFunc, dynamic_cast(functions_sel[Type::CanonicalFunc]->getSelectedObject())); type->setFunction(Type::SubtypeDiffFunc, dynamic_cast(functions_sel[Type::SubtypeDiffFunc]->getSelectedObject())); } //Configuring a base type else { type->setConfiguration(Type::BaseType); type->setLikeType(like_type->getPgSQLType()); type->setElement(element_type->getPgSQLType()); type->setInternalLength(internal_len_sb->value()); type->setByValue(by_value_chk->isChecked()); type->setPreferred(preferred_chk->isChecked()); type->setCollatable(collatable_chk->isChecked()); if(!delimiter_edt->text().isEmpty()) type->setDelimiter(delimiter_edt->text().at(0).toLatin1()); type->setDefaultValue(default_value_edt->text()); type->setCategory(CategoryType(category_cmb->currentText())); type->setAlignment(PgSqlType(alignment_cmb->currentText())); type->setStorage(StorageType(storage_cmb->currentText())); for(i=Type::InputFunc; i <= Type::AnalyzeFunc; i++) type->setFunction(i, dynamic_cast(functions_sel[i]->getSelectedObject())); } finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/typewidget.h000066400000000000000000000053531360462764600220130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class TypeWidget \brief Implements the operations to create/edit user defined data types via form. */ #ifndef TYPE_WIDGET_H #define TYPE_WIDGET_H #include "baseobjectwidget.h" #include "ui_typewidget.h" #include "pgsqltypewidget.h" #include "objectstablewidget.h" /* Declaring the TypeAttribute class as a Qt metatype in order to permit that instances of the class be used as data of QVariant and QMetaType */ #include Q_DECLARE_METATYPE(TypeAttribute) class TypeWidget: public BaseObjectWidget, public Ui::TypeWidget { private: Q_OBJECT //! \brief Type functions selectors widgets ObjectSelectorWidget *functions_sel[9], //! \brief Range type operator class selector widget *opclass_sel; //! \brief Type configuration widgets, used to handle "like type", "element type" and "range subtype" PgSQLTypeWidget *like_type, *element_type, *range_subtype; //! \brief Tables that store enumaration elementas and composite attributes ObjectsTableWidget *enumerations_tab, *attributes_tab; //! \brief Composite type attribute collation selector ObjectSelectorWidget *attrib_collation_sel; //! \brief Composite type attribute datatype configurator PgSQLTypeWidget *attrib_type_wgt; public: TypeWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, Type *type); private slots: //! \brief Handles the form showing the fields according to the selected type configuration (base, composite, enumaration) void selectTypeConfiguration(void); //! \brief Handles the type enumarations void handleEnumeration(int row); //! \brief Create/Updated an attribute based upon values of the form void handleAttribute(int row); //! \brief Exposes on form the values of the currently selected attribute void editAttribute(int row); //! \brief Shows the attribute configured onto the attributes table void showAttributeData(TypeAttribute attrib, int row); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/updatenotifierwidget.cpp000066400000000000000000000130701360462764600244020ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "updatenotifierwidget.h" #include "pgmodeleruins.h" UpdateNotifierWidget::UpdateNotifierWidget(QWidget *parent) : QWidget(parent) { setupUi(this); setWindowFlags(Qt::Widget | Qt::FramelessWindowHint); show_no_upd_msg=false; update_chk_reply=nullptr; old_pos=QPoint(-1,-1); frame->installEventFilter(this); QGraphicsDropShadowEffect * drop_shadow=new QGraphicsDropShadowEffect(this); drop_shadow->setOffset(5,5); drop_shadow->setBlurRadius(30); this->setGraphicsEffect(drop_shadow); connect(&update_chk_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleUpdateChecked(QNetworkReply*))); //C++11 lambda slots connect(get_source_tb, &QToolButton::clicked, this, [&](){ activateLink(GlobalAttributes::PgModelerSourceURL); }); connect(get_binary_tb, &QToolButton::clicked, this, [&](){ activateLink(GlobalAttributes::PgModelerDownloadURL); }); connect(hide_tb, &QToolButton::clicked, this, [&](){ this->close(); emit s_visibilityChanged(false); }); PgModelerUiNs::configureWidgetFont(changelog_txt, PgModelerUiNs::MediumFontFactor); PgModelerUiNs::configureWidgetFont(ver_num_lbl, PgModelerUiNs::BigFontFactor); PgModelerUiNs::configureWidgetFont(title_lbl, PgModelerUiNs::BigFontFactor); this->adjustSize(); } bool UpdateNotifierWidget::eventFilter(QObject *obj, QEvent *event) { if(obj==frame && (event->type()==QEvent::MouseMove || event->type()==QEvent::MouseButtonPress)) { QMouseEvent *m_event=dynamic_cast(event); if(event->type()==QEvent::MouseButtonPress) old_pos=QPoint(-1,-1); else { //Resizing the widget if(m_event->buttons()==Qt::LeftButton) { if(m_event->pos().x() >= this->minimumWidth() - 20 || m_event->pos().y() >= this->minimumHeight()- 20) { int w, h; if(old_pos.x() >= 0) { //Calculates the width and height based upon the delta between the points w=this->width() + (m_event->pos().x() - old_pos.x()); h=this->height() + (m_event->pos().y() - old_pos.y()); this->setGeometry(this->pos().x(), this->pos().y(), w, h); } } old_pos=m_event->pos(); } } } return(QWidget::eventFilter(obj, event)); } void UpdateNotifierWidget::activateLink(const QString &link) { QDesktopServices::openUrl(QUrl(link)); this->close(); emit s_visibilityChanged(false); } void UpdateNotifierWidget::checkForUpdate(void) { QUrl url(GlobalAttributes::PgModelerUpdateCheckURL + GlobalAttributes::PgModelerVersion); QNetworkRequest req(url); req.setRawHeader("User-Agent", "pgModelerUpdateCheck"); show_no_upd_msg=(dynamic_cast(sender())!=nullptr); update_chk_reply=update_chk_manager.get(req); } void UpdateNotifierWidget::handleUpdateChecked(QNetworkReply *reply) { Messagebox msg_box; unsigned http_status=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt(); if(reply->error()!=QNetworkReply::NoError) { msg_box.show(trUtf8("Failed to check updates"), trUtf8("The update notifier failed to check for new versions! Please, verify your internet connectivity and try again! Connection error returned: %1 - %2.").arg(http_status).arg(reply->errorString()), Messagebox::ErrorIcon, Messagebox::OkButton); } else { /* In case of [301 - Move permanently] there is the need to make a new request to reach the final destination */ if(http_status==301 || http_status==302) { QString url=reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString(); if(http_status==302 && !url.startsWith(GlobalAttributes::PgModelerSite)) url.prepend(GlobalAttributes::PgModelerSite); QNetworkRequest req(url); update_chk_reply=update_chk_manager.get(req); } else { //In case of [200 - OK] updates the contents with the retrieved json if(http_status==200) { QJsonDocument json_doc=QJsonDocument::fromJson(reply->readAll()); QJsonObject json_obj=json_doc.object(); QString version=json_obj.value(Attributes::NewVersion).toString(), changelog=json_obj.value(Attributes::Changelog).toString(), date=json_obj.value(Attributes::Date).toString(); bool upd_found=(!version.isEmpty() && version!=Attributes::False); if(upd_found) { ver_num_lbl->setText(version); changelog_txt->setText(changelog); ver_date_lbl->setText(date); } else if(show_no_upd_msg) { msg_box.show(trUtf8("No updates found"), trUtf8("You are running the most recent pgModeler version! No update needed."), Messagebox::InfoIcon, Messagebox::OkButton); } emit s_updateAvailable(upd_found); } else { msg_box.show(trUtf8("Failed to check updates"), trUtf8("The update notifier failed to check for new versions! A HTTP status code was returned: %1").arg(http_status), Messagebox::ErrorIcon, Messagebox::OkButton); } delete(update_chk_reply); update_chk_reply=nullptr; } } } pgmodeler-0.9.2/libpgmodeler_ui/src/updatenotifierwidget.h000066400000000000000000000054231360462764600240520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class UpdateNotifierWidget \brief Implements a basic update notifier shown as a popup widget on main window. ATTENTION: This widget make requests to the url defined in GlobalAttributes::PGMODELER_UPD_CHECK_URL and expects that a JSON data is returned. In order to work correctly the returned JSON must be as follow: 1) When there is a new version: { "new-version":"[version]", "date":"[release_date]", "changelog":"[change_list]" } 2) When there is no new version: {"new-version":"false"} It's recommended to produce this JSON based upon the CHANGELOG.md file since all needed information is there. */ #ifndef UPDATE_NOTIFIER_WIDGET_H #define UPDATE_NOTIFIER_WIDGET_H #include #include #include #include #include #include #include "ui_updatenotifierwidget.h" #include "messagebox.h" #include "globalattributes.h" #include "attributes.h" class UpdateNotifierWidget: public QWidget, public Ui::UpdateNotifierWidget { private: Q_OBJECT //! \brief Object responsible to make request to server QNetworkAccessManager update_chk_manager; //! \brief This pointer stores the reply after the update manager make a call to server QNetworkReply *update_chk_reply; //! \brief Stores the old mouse position to simulate the widget resizing QPoint old_pos; /*! \brief This attribute indicates wether a message informing that no updates are available must be shown. Generally, this attribute is true when the user call the checkForUpdate() from a QAction */ bool show_no_upd_msg; //! \brief This event filter is used to resize the widget when the mouse is over the notifier bool eventFilter(QObject *obj, QEvent *event); void activateLink(const QString &link); public: UpdateNotifierWidget(QWidget * parent = nullptr); public slots: void checkForUpdate(void); private slots: void handleUpdateChecked(QNetworkReply *reply); signals: void s_updateAvailable(bool value); void s_visibilityChanged(bool visible); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/usermappingwidget.cpp000066400000000000000000000063471360462764600237230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "usermappingwidget.h" UserMappingWidget::UserMappingWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::UserMapping) { try { QHBoxLayout *hbox = nullptr; Ui_UserMappingWidget::setupUi(this); server_sel=nullptr; server_sel=new ObjectSelectorWidget(ObjectType::ForeignServer, true, this); hbox = new QHBoxLayout; hbox->setContentsMargins(0,0,0,0); hbox->addWidget(server_sel); server_wgt->setLayout(hbox); options_tab = new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::EditButton | ObjectsTableWidget::UpdateButton), true, this); options_tab->setCellsEditable(true); options_tab->setColumnCount(2); options_tab->setHeaderLabel(trUtf8("Option"), 0); options_tab->setHeaderLabel(trUtf8("Value"), 1); hbox = new QHBoxLayout; hbox->setContentsMargins(4,4,4,4); hbox->addWidget(options_tab); options_gb->setLayout(hbox); configureFormLayout(server_grid, ObjectType::UserMapping); setRequiredField(server_sel); setRequiredField(server_lbl); configureTabOrder({ server_sel, options_tab }); setMinimumSize(550, 280); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void UserMappingWidget::setAttributes(DatabaseModel *model, OperationList *op_list, UserMapping *user_map) { BaseObjectWidget::setAttributes(model, op_list, user_map); server_sel->setModel(model); if(user_map) { server_sel->setSelectedObject(user_map->getForeignServer()); options_tab->blockSignals(true); for(auto &itr : user_map->getOptions()) { options_tab->addRow(); options_tab->setCellText(itr.first, options_tab->getRowCount() - 1, 0); options_tab->setCellText(itr.second, options_tab->getRowCount() - 1, 1); } options_tab->clearSelection(); options_tab->blockSignals(false); } } void UserMappingWidget::applyConfiguration(void) { try { UserMapping *user_map = nullptr; startConfiguration(); user_map = dynamic_cast(this->object); user_map->setForeignServer(dynamic_cast(server_sel->getSelectedObject())); user_map->removeOptions(); for(unsigned row = 0; row < options_tab->getRowCount(); row++) user_map->setOption(options_tab->getCellText(row, 0), options_tab->getCellText(row, 1)); BaseObjectWidget::applyConfiguration(); finishConfiguration(); } catch(Exception &e) { cancelConfiguration(); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } pgmodeler-0.9.2/libpgmodeler_ui/src/usermappingwidget.h000066400000000000000000000025701360462764600233620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class UserMappingWidget \brief Implements the operations to create/edit user mappings via form. */ #ifndef USER_MAPPING_WIDGET_H #define USER_MAPPING_WIDGET_H #include "baseobjectwidget.h" #include "ui_usermappingwidget.h" #include "objectstablewidget.h" class UserMappingWidget: public BaseObjectWidget, public Ui::UserMappingWidget { private: Q_OBJECT ObjectSelectorWidget *server_sel; ObjectsTableWidget *options_tab; public: UserMappingWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, UserMapping *user_map); public slots: void applyConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/validationinfo.cpp000066400000000000000000000042321360462764600231620ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "validationinfo.h" ValidationInfo::ValidationInfo(void) { object=nullptr; val_type=ValidationAborted; } ValidationInfo::ValidationInfo(unsigned val_type, BaseObject *object, vector references) { if(val_type >= SqlValidationError) throw Exception(ErrorCode::AsgInvalidTypeObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if((val_type==NoUniqueName || val_type==BrokenReference) && (!object || references.empty())) throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__); this->val_type=val_type; this->object=object; this->references=references; } ValidationInfo::ValidationInfo(Exception e) { vector err_list; val_type=SqlValidationError; e.getExceptionsList(err_list); while(!err_list.empty()) { errors.push_back(err_list.back().getErrorMessage()); err_list.pop_back(); } errors.removeDuplicates(); } ValidationInfo::ValidationInfo(const QString &msg) { val_type=ValidationAborted; errors.push_back(msg); } unsigned ValidationInfo::getValidationType(void) { return(val_type); } BaseObject *ValidationInfo::getObject(void) { return(object); } vector ValidationInfo::getReferences(void) { return(references); } QStringList ValidationInfo::getErrors(void) { return(errors); } bool ValidationInfo::isValid(void) { return(((val_type==NoUniqueName || val_type==BrokenReference) && object) || (val_type==SqlValidationError && !errors.empty())); } pgmodeler-0.9.2/libpgmodeler_ui/src/validationinfo.h000066400000000000000000000051141360462764600226270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ValidationInfo \brief Stores information of a single object when model is being validated. Instances of this class are emitted during the validation process on ModelValidationHelper class. */ #ifndef VALIDATION_INFO_H #define VALIDATION_INFO_H /* Including QByteArray due to 'QByteArray has no toStdString()' error on Qt 5.4 (Windows only) */ #include "baseobject.h" #include class ValidationInfo { private: //! \brief Validation type (see constants below) unsigned val_type; //! \brief Object which the validation info belongs to BaseObject *object; /*! \brief References to the validated object. This vector isn't filled when the info is about SQL validation */ vector references; QStringList errors; public: static constexpr unsigned NoUniqueName=0, BrokenReference=1, SpObjBrokenReference=2, BrokenRelConfig=3, MissingExtension=4, SqlValidationError=5, ValidationAborted=6; ValidationInfo(void); ValidationInfo(unsigned val_type, BaseObject *object, vector references); ValidationInfo(const QString &msg); ValidationInfo(Exception e); //! \brief Returns the validation type unsigned getValidationType(void); //! \brief Returns the object which the validation info belongs to BaseObject *getObject(void); //! \brief Returns the objects that somehow references the validation info object vector getReferences(void); //! \brief Returns the SQL errors generated during the SQL validation QStringList getErrors(void); /*! \brief Returns if the content of validation info is valid. To be valid the info must have the object not null when it is NO_UNIQUE_NAME or BROKEN_REFERENCE, and when its SQL_VALIDATION_ERR the sql error message must be set */ bool isValid(void); friend class ModelValidationHelper; friend class QVariant; }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/viewwidget.cpp000066400000000000000000000603151360462764600223360ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "viewwidget.h" #include "rulewidget.h" #include "triggerwidget.h" #include "indexwidget.h" #include "baseform.h" #include "referencewidget.h" ViewWidget::ViewWidget(QWidget *parent): BaseObjectWidget(parent, ObjectType::View) { try { ObjectsTableWidget *tab=nullptr; ObjectType types[]={ ObjectType::Trigger, ObjectType::Rule, ObjectType::Index }; QGridLayout *grid=nullptr; QVBoxLayout *vbox=nullptr; map > fields_map; QFrame *frame=nullptr; Ui_ViewWidget::setupUi(this); code_txt=new NumberedTextEditor(this); code_txt->setReadOnly(true); code_hl=new SyntaxHighlighter(code_txt); code_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); vbox=new QVBoxLayout(code_prev_tab); vbox->setContentsMargins(4,4,4,4); vbox->addWidget(code_txt); cte_expression_txt=new NumberedTextEditor(this, true); cte_expression_hl=new SyntaxHighlighter(cte_expression_txt); cte_expression_hl->loadConfiguration(GlobalAttributes::SQLHighlightConfPath); vbox=new QVBoxLayout(cte_tab); vbox->setContentsMargins(4,4,4,4); vbox->addWidget(cte_expression_txt); tag_sel=new ObjectSelectorWidget(ObjectType::Tag, false, this); dynamic_cast(options_gb->layout())->addWidget(tag_sel, 0, 1, 1, 4); references_tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ ObjectsTableWidget::UpdateButton, true, this); references_tab->setColumnCount(5); references_tab->setHeaderLabel(trUtf8("Col./Expr."), 0); references_tab->setHeaderLabel(trUtf8("Table alias"), 1); references_tab->setHeaderLabel(trUtf8("Column alias"), 2); references_tab->setHeaderLabel(trUtf8("Flags: SF FW AW EX VD"), 3); references_tab->setHeaderLabel(trUtf8("Reference alias"), 4); vbox=new QVBoxLayout(tabWidget->widget(0)); vbox->setContentsMargins(4,4,4,4); vbox->addWidget(references_tab); cte_expression_cp=new CodeCompletionWidget(cte_expression_txt, true); //Configuring the table objects that stores the triggers and rules for(unsigned i=0, tab_id=1; i < sizeof(types)/sizeof(ObjectType); i++, tab_id++) { tab=new ObjectsTableWidget(ObjectsTableWidget::AllButtons ^ (ObjectsTableWidget::UpdateButton | ObjectsTableWidget::MoveButtons), true, this); objects_tab_map[types[i]]=tab; grid=new QGridLayout; grid->addWidget(tab, 0,0,1,1); grid->setContentsMargins(4,4,4,4); tabWidget->widget(tab_id)->setLayout(grid); connect(tab, SIGNAL(s_rowsRemoved(void)), this, SLOT(removeObjects(void))); connect(tab, SIGNAL(s_rowRemoved(int)), this, SLOT(removeObject(int))); connect(tab, SIGNAL(s_rowAdded(int)), this, SLOT(handleObject(void))); connect(tab, SIGNAL(s_rowEdited(int)), this, SLOT(handleObject(void))); connect(tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateObject(int,int))); } objects_tab_map[ObjectType::Trigger]->setColumnCount(6); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Trigger]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Refer. Table"), 1); objects_tab_map[ObjectType::Trigger]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("table")),1); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Firing"), 2); objects_tab_map[ObjectType::Trigger]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("trigger")),2); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Events"), 3); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Alias"), 4); objects_tab_map[ObjectType::Trigger]->setHeaderLabel(trUtf8("Comment"), 5); objects_tab_map[ObjectType::Index]->setColumnCount(4); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Index]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Indexing"), 1); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Alias"), 2); objects_tab_map[ObjectType::Index]->setHeaderLabel(trUtf8("Comment"), 3); objects_tab_map[ObjectType::Rule]->setColumnCount(5); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Name"), 0); objects_tab_map[ObjectType::Rule]->setHeaderIcon(QPixmap(PgModelerUiNs::getIconPath("uid")),0); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Execution"), 1); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Event"), 2); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Alias"), 3); objects_tab_map[ObjectType::Rule]->setHeaderLabel(trUtf8("Comment"), 4); tablespace_sel->setEnabled(false); tablespace_lbl->setEnabled(false); configureFormLayout(view_grid, ObjectType::View); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion93)].push_back(recursive_rb); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion93)].push_back(materialized_rb); fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion93)].push_back(with_no_data_chk); frame=generateVersionWarningFrame(fields_map); view_grid->addWidget(frame, view_grid->count()+1, 0, 1,3); frame->setParent(this); connect(references_tab, SIGNAL(s_rowAdded(int)), this, SLOT(addReference(int))); connect(references_tab, SIGNAL(s_rowEdited(int)), this, SLOT(editReference(int))); connect(references_tab, SIGNAL(s_rowDuplicated(int,int)), this, SLOT(duplicateReference(int,int))); connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateCodePreview(void))); connect(materialized_rb, SIGNAL(toggled(bool)), with_no_data_chk, SLOT(setEnabled(bool))); connect(materialized_rb, SIGNAL(toggled(bool)), tablespace_sel, SLOT(setEnabled(bool))); connect(materialized_rb, SIGNAL(toggled(bool)), tablespace_lbl, SLOT(setEnabled(bool))); connect(materialized_rb, SIGNAL(toggled(bool)), this, SLOT(updateCodePreview(void))); connect(recursive_rb, SIGNAL(toggled(bool)), this, SLOT(updateCodePreview(void))); connect(with_no_data_chk, SIGNAL(toggled(bool)), this, SLOT(updateCodePreview(void))); connect(tablespace_sel, SIGNAL(s_objectSelected(void)), this, SLOT(updateCodePreview(void))); connect(tablespace_sel, SIGNAL(s_selectorCleared(void)), this, SLOT(updateCodePreview(void))); connect(schema_sel, SIGNAL(s_objectSelected(void)), this, SLOT(updateCodePreview(void))); connect(schema_sel, SIGNAL(s_selectorCleared(void)), this, SLOT(updateCodePreview(void))); configureTabOrder({ tag_sel, ordinary_rb, recursive_rb, with_no_data_chk, tabWidget }); setMinimumSize(660, 650); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } ObjectsTableWidget *ViewWidget::getObjectTable(ObjectType obj_type) { if(objects_tab_map.count(obj_type) > 0) return(objects_tab_map[obj_type]); return(nullptr); } template int ViewWidget::openEditingForm(TableObject *object) { BaseForm editing_form(this); WidgetClass *object_wgt=new WidgetClass; object_wgt->setAttributes(this->model, this->op_list, dynamic_cast(this->object), dynamic_cast(object)); editing_form.setMainWidget(object_wgt); return(editing_form.exec()); } void ViewWidget::handleObject(void) { ObjectType obj_type=ObjectType::BaseObject; TableObject *object=nullptr; ObjectsTableWidget *obj_table=nullptr; try { obj_type=getObjectType(sender()); obj_table=getObjectTable(obj_type); if(obj_table->getSelectedRow()>=0) object=reinterpret_cast(obj_table->getRowData(obj_table->getSelectedRow()).value()); if(obj_type==ObjectType::Trigger) openEditingForm(object); else if(obj_type==ObjectType::Index) openEditingForm(object); else openEditingForm(object); listObjects(obj_type); } catch(Exception &e) { listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ViewWidget::duplicateObject(int curr_row, int new_row) { ObjectType obj_type=ObjectType::BaseObject; BaseObject *object=nullptr, *dup_object=nullptr; ObjectsTableWidget *obj_table=nullptr; View *view = dynamic_cast(this->object); int op_id = -1; try { obj_type=getObjectType(sender()); //Selects the object table based upon the passed object type obj_table=getObjectTable(obj_type); //Gets the object reference if there is an item select on table if(curr_row >= 0) object = reinterpret_cast(obj_table->getRowData(curr_row).value()); PgModelerNs::copyObject(&dup_object, object, obj_type); dup_object->setName(PgModelerNs::generateUniqueName(dup_object, *view->getObjectList(obj_type), false, QString("_cp"))); op_id=op_list->registerObject(dup_object, Operation::ObjectCreated, new_row, this->object); view->addObject(dup_object); view->setModified(true); listObjects(obj_type); } catch(Exception &e) { //If operation was registered if(op_id >= 0) { op_list->ignoreOperationChain(true); op_list->removeLastOperation(); op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ViewWidget::removeObjects(void) { View *view=nullptr; unsigned count, op_count=0, i; BaseObject *object=nullptr; ObjectType obj_type=getObjectType(sender()); try { view=dynamic_cast(this->object); op_count=op_list->getCurrentSize(); while(view->getObjectCount(obj_type) > 0) { object=view->getObject(0, obj_type); view->removeObject(object); op_list->registerObject(object, Operation::ObjectRemoved, 0, this->object); } } catch(Exception &e) { if(op_count < op_list->getCurrentSize()) { count=op_list->getCurrentSize()-op_count; op_list->ignoreOperationChain(true); for(i=0; i < count; i++) { op_list->undoOperation(); op_list->removeLastOperation(); } op_list->ignoreOperationChain(false); } listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ViewWidget::addReference(int row) { openReferenceForm(Reference(), row, false); } void ViewWidget::duplicateReference(int orig_row, int new_row) { showReferenceData(references_tab->getRowData(orig_row).value(), getReferenceFlag(orig_row), new_row); } void ViewWidget::removeObject(int row) { View *view=nullptr; BaseObject *object=nullptr; ObjectType obj_type=getObjectType(sender()); try { view=dynamic_cast(this->object); object=view->getObject(row, obj_type); view->removeObject(object); op_list->registerObject(object, Operation::ObjectRemoved, row, this->object); } catch(Exception &e) { listObjects(obj_type); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } ObjectType ViewWidget::getObjectType(QObject *sender) { ObjectType obj_type=ObjectType::BaseObject; if(sender) { map::iterator itr, itr_end; itr=objects_tab_map.begin(); itr_end=objects_tab_map.end(); while(itr!=itr_end && obj_type==ObjectType::BaseObject) { if(itr->second==sender) obj_type=itr->first; itr++; } } return(obj_type); } void ViewWidget::showObjectData(TableObject *object, int row) { ObjectsTableWidget *tab=nullptr; Trigger *trigger=nullptr; Rule *rule=nullptr; Index *index=nullptr; ObjectType obj_type; QString str_aux; unsigned i; EventType events[]={ EventType::OnInsert, EventType::OnDelete, EventType::OnTruncate, EventType::OnUpdate }; obj_type=object->getObjectType(); tab=objects_tab_map[obj_type]; //Column 0: Object name tab->setCellText(object->getName(),row,0); if(obj_type==ObjectType::Trigger) { trigger=dynamic_cast(object); //Column 1: Table referenced by the trigger (constraint trigger) tab->clearCellText(row,1); if(trigger->getReferencedTable()) tab->setCellText(trigger->getReferencedTable()->getName(true),row,1); //Column 2: Trigger firing type tab->setCellText(~trigger->getFiringType(),row,2); //Column 3: Events that fires the trigger for(i=0; i < sizeof(events)/sizeof(EventType); i++) { if(trigger->isExecuteOnEvent(events[i])) str_aux+=~events[i] + QString(", "); } str_aux.remove(str_aux.size()-2, 2); tab->setCellText(str_aux ,row,3); tab->setCellText(trigger->getAlias(), row, 4); } else if(obj_type==ObjectType::Rule) { rule=dynamic_cast(object); //Column 1: Rule execution type tab->setCellText(~rule->getExecutionType(),row,1); //Column 2: Rule event type tab->setCellText(~rule->getEventType(),row,2); tab->setCellText(rule->getAlias(), row, 3); } else { index=dynamic_cast(object); //Column 1: Indexing type tab->setCellText(~index->getIndexingType(),row,1); tab->setCellText(index->getAlias(), row, 2); } tab->setCellText(object->getComment(), row, tab->getColumnCount() - 1); tab->setRowData(QVariant::fromValue(object), row); } void ViewWidget::listObjects(ObjectType obj_type) { ObjectsTableWidget *tab=nullptr; unsigned count, i; View *view=nullptr; try { //Gets the object table related to the object type tab=objects_tab_map[obj_type]; view=dynamic_cast(this->object); tab->blockSignals(true); tab->removeRows(); count=view->getObjectCount(obj_type); for(i=0; i < count; i++) { tab->addRow(); showObjectData(dynamic_cast(view->getObject(i, obj_type)), i); } tab->clearSelection(); tab->blockSignals(false); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } int ViewWidget::openReferenceForm(Reference ref, int row, bool update) { BaseForm editing_form(this); ReferenceWidget *ref_wgt=new ReferenceWidget; int result = 0; editing_form.setMainWidget(ref_wgt); editing_form.setButtonConfiguration(Messagebox::OkCancelButtons); disconnect(editing_form.apply_ok_btn, SIGNAL(clicked(bool)), &editing_form, SLOT(accept())); connect(editing_form.apply_ok_btn, SIGNAL(clicked(bool)), ref_wgt, SLOT(applyConfiguration())); connect(ref_wgt, SIGNAL(s_closeRequested()), &editing_form, SLOT(accept())); ref_wgt->setAttributes(ref, getReferenceFlag(row), model); result = editing_form.exec(); disconnect(ref_wgt, nullptr, &editing_form, nullptr); if(result == QDialog::Accepted) showReferenceData(ref_wgt->getReference(), ref_wgt->getReferenceFlags(), row); else if(!update) references_tab->removeRow(row); return(result); } unsigned ViewWidget::getReferenceFlag(int row) { QString flags_str = references_tab->getCellText(row, 3); unsigned ref_flags = 0; if(flags_str[4] == '1') ref_flags = Reference::SqlViewDefinition; else { if(flags_str[0] == '1') ref_flags |= Reference::SqlReferSelect; if(flags_str[1] == '1') ref_flags |= Reference::SqlReferFrom; if(flags_str[2] == '1') ref_flags |= Reference::SqlReferWhere; if(flags_str[3] == '1') ref_flags |= Reference::SqlReferEndExpr; } return(ref_flags); } void ViewWidget::editReference(int ref_idx) { openReferenceForm(references_tab->getRowData(ref_idx).value(), ref_idx, true); } void ViewWidget::showReferenceData(Reference refer, unsigned ref_flags, unsigned row) { PhysicalTable *tab=nullptr; Column *col=nullptr; QString str_aux; bool selec_from = (ref_flags & Reference::SqlReferSelect) == Reference::SqlReferSelect, from_where = (ref_flags & Reference::SqlReferFrom) == Reference::SqlReferFrom, after_where = (ref_flags & Reference::SqlReferWhere) == Reference::SqlReferWhere, end_expr = (ref_flags & Reference::SqlReferEndExpr) == Reference::SqlReferEndExpr, view_def = (ref_flags & Reference::SqlViewDefinition) == Reference::SqlViewDefinition; if(refer.getReferenceType()==Reference::ReferColumn) { tab=refer.getTable(); col=refer.getColumn(); /* If the table is allocated but not the column indicates that the reference is to all table columns this way shows a string in format: [SCHEMA].[TABLE].* */ if(tab && !col) references_tab->setCellText(tab->getName(true) + QString(".*"),row,0); /* If the table and column are allocated indicates that the reference is to a specific column this way shows a string in format: [SCHEMA].[TABLE].[COLUMN] */ else references_tab->setCellText(tab->getName(true) + QString(".") + col->getName(true),row,0); references_tab->setCellText(refer.getAlias(),row,1); if(col) references_tab->setCellText(refer.getColumnAlias(),row,2); } else { references_tab->setCellText(refer.getExpression().simplified(),row,0); references_tab->setCellText(refer.getAlias(),row,1); } //Configures the string that denotes the SQL application for the reference str_aux+=(selec_from ? QString("1") : QString("0")); str_aux+=(from_where ? QString("1") : QString("0")); str_aux+=(after_where ? QString("1") : QString("0")); str_aux+=(end_expr ? QString("1") : QString("0")); str_aux+=(view_def ? QString("1") : QString("0")); references_tab->setCellText(str_aux, row, 3); references_tab->setCellText(refer.getReferenceAlias(), row, 4); refer.setDefinitionExpression(view_def); references_tab->setRowData(QVariant::fromValue(refer), row); } void ViewWidget::updateCodePreview(void) { try { if(tabWidget->currentIndex()==tabWidget->count()-1) { View aux_view; Reference refer; QString str_aux; TableObject *tab_obj=nullptr; map::iterator itr, itr_end; unsigned i, count, i1, expr_type[]={ Reference::SqlReferSelect, Reference::SqlReferFrom, Reference::SqlReferWhere, Reference::SqlReferEndExpr, Reference::SqlViewDefinition}; aux_view.BaseObject::setName(name_edt->text().toUtf8()); aux_view.BaseObject::setSchema(schema_sel->getSelectedObject()); aux_view.setTablespace(tablespace_sel->getSelectedObject()); aux_view.setCommomTableExpression(cte_expression_txt->toPlainText().toUtf8()); aux_view.setMaterialized(materialized_rb->isChecked()); aux_view.setRecursive(recursive_rb->isChecked()); aux_view.setWithNoData(with_no_data_chk->isChecked()); count=references_tab->getRowCount(); for(i=0; i < count; i++) { refer=references_tab->getRowData(i).value(); //Get the SQL application string for the current reference str_aux=references_tab->getCellText(i,3); for(i1=0; i1 < sizeof(expr_type)/sizeof(unsigned); i1++) { if(str_aux[i1]=='1') aux_view.addReference(refer, expr_type[i1]); } } itr=objects_tab_map.begin(); itr_end=objects_tab_map.end(); //Inserts the triggers / rules into the auxiliary view while(itr!=itr_end) { count=itr->second->getRowCount(); //Make a copy of each view objects (rule/trigger) to the auxiliary view for(i=0; i < count; i++) { if(itr->first==ObjectType::Trigger) { tab_obj=new Trigger; (*dynamic_cast(tab_obj))= (*reinterpret_cast(itr->second->getRowData(i).value())); } else { tab_obj=new Rule; (*dynamic_cast(tab_obj))= (*reinterpret_cast(itr->second->getRowData(i).value())); } aux_view.addObject(tab_obj); } itr++; } code_txt->setPlainText(aux_view.getCodeDefinition(SchemaParser::SqlDefinition)); } } catch(Exception &e) { QString str_aux; //In case of error no code is outputed, showing a error message in the code preview widget str_aux=trUtf8("/* Could not generate the SQL code. Make sure all attributes are correctly filled! "); str_aux+=QString("\n\n>> Returned error(s): \n\n%1*/").arg(e.getExceptionsText()); code_txt->setPlainText(str_aux); } } void ViewWidget::setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, View *view, double px, double py) { unsigned i, count, ref_flags = 0; Reference refer; if(!view) { view=new View; if(schema) view->setSchema(schema); /* Sets the 'new_object' flag as true indicating that the alocated table must be treated as a recently created object */ this->new_object=true; } BaseObjectWidget::setAttributes(model,op_list, view, schema, px, py); materialized_rb->setChecked(view->isMaterialized()); recursive_rb->setChecked(view->isRecursive()); with_no_data_chk->setChecked(view->isWithNoData()); cte_expression_cp->configureCompletion(model, cte_expression_hl); op_list->startOperationChain(); operation_count=op_list->getCurrentSize(); tag_sel->setModel(this->model); tag_sel->setSelectedObject(view->getTag()); cte_expression_txt->setPlainText(view->getCommomTableExpression()); count=view->getReferenceCount(); references_tab->blockSignals(true); for(i=0; i < count; i++) { references_tab->addRow(); ref_flags = 0; refer=view->getReference(i); if(view->getReferenceIndex(refer, Reference::SqlViewDefinition) >= 0) ref_flags = Reference::SqlViewDefinition; if(view->getReferenceIndex(refer, Reference::SqlReferSelect) >= 0) ref_flags |= Reference::SqlReferSelect; if(view->getReferenceIndex(refer, Reference::SqlReferFrom) >= 0) ref_flags |= Reference::SqlReferFrom; if(view->getReferenceIndex(refer, Reference::SqlReferWhere) >= 0) ref_flags |= Reference::SqlReferWhere; if(view->getReferenceIndex(refer, Reference::SqlReferEndExpr) >= 0) ref_flags |= Reference::SqlReferEndExpr; showReferenceData(refer, ref_flags, i); } references_tab->blockSignals(false); references_tab->clearSelection(); listObjects(ObjectType::Trigger); listObjects(ObjectType::Rule); listObjects(ObjectType::Index); } void ViewWidget::applyConfiguration(void) { try { View *view=nullptr; ObjectType types[]={ ObjectType::Trigger, ObjectType::Rule, ObjectType::Index }; unsigned expr_type[]={ Reference::SqlReferSelect, Reference::SqlReferFrom, Reference::SqlReferWhere, Reference::SqlReferEndExpr, Reference::SqlViewDefinition}; Reference refer; QString str_aux; if(!this->new_object) op_list->registerObject(this->object, Operation::ObjectModified); else registerNewObject(); BaseObjectWidget::applyConfiguration(); view=dynamic_cast(this->object); view->removeObjects(); view->removeReferences(); view->setMaterialized(materialized_rb->isChecked()); view->setRecursive(recursive_rb->isChecked()); view->setWithNoData(with_no_data_chk->isChecked()); view->setCommomTableExpression(cte_expression_txt->toPlainText().toUtf8()); view->setTag(dynamic_cast(tag_sel->getSelectedObject())); for(unsigned i=0; i < references_tab->getRowCount(); i++) { refer=references_tab->getRowData(i).value(); //Get the SQL application string for the current reference str_aux=references_tab->getCellText(i, 3); for(unsigned i=0; i < sizeof(expr_type)/sizeof(unsigned); i++) { if(str_aux[i]=='1') view->addReference(refer, expr_type[i]); } } //Adds the auxiliary view objects into configured view for(unsigned type_id=0; type_id < sizeof(types)/sizeof(ObjectType); type_id++) { for(unsigned i=0; i < objects_tab_map[types[type_id]]->getRowCount(); i++) view->addObject(reinterpret_cast(objects_tab_map[types[type_id]]->getRowData(i).value())); } op_list->finishOperationChain(); this->model->updateViewRelationships(view); finishConfiguration(); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void ViewWidget::cancelConfiguration(void) { BaseObjectWidget::cancelChainedOperation(); } pgmodeler-0.9.2/libpgmodeler_ui/src/viewwidget.h000066400000000000000000000067511360462764600220070ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class ViewWidget \brief Implements the operations to create/edit views via form. */ #ifndef VIEW_WIDGET_H #define VIEW_WIDGET_H #include #include "baseobjectwidget.h" #include "ui_viewwidget.h" #include "objectstablewidget.h" #include "codecompletionwidget.h" #include "numberedtexteditor.h" /* Declaring the Reference class as a Qt metatype in order to permit that instances of the class be used as data of QVariant and QMetaType */ #include Q_DECLARE_METATYPE(Reference) class ViewWidget: public BaseObjectWidget, public Ui::ViewWidget { private: Q_OBJECT ObjectSelectorWidget *tag_sel; NumberedTextEditor *cte_expression_txt, *code_txt; //! \brief Stores all the view references ObjectsTableWidget *references_tab; map objects_tab_map; SyntaxHighlighter *code_hl, *cte_expression_hl; CodeCompletionWidget *cte_expression_cp; //! \brief Shows the reference at the reference's table void showReferenceData(Reference refer, unsigned ref_flags, unsigned row); //! \brief Returns the object table according with the child type ObjectsTableWidget *getObjectTable(ObjectType obj_type); ObjectType getObjectType(QObject *sender); void showObjectData(TableObject *object, int row); void listObjects(ObjectType obj_type); /*! \brief Template method that opens the editing form for the specified object. Class and ClassWidget should be compatible, e.g., "Column" can only be edited using ColumnWidget */ template int openEditingForm(TableObject *object); int openReferenceForm(Reference ref, int row, bool update); unsigned getReferenceFlag(int row); public: ViewWidget(QWidget * parent = nullptr); void setAttributes(DatabaseModel *model, OperationList *op_list, Schema *schema, View *view, double px, double py); private slots: //! \brief Edits the selected reference void editReference(int ref_idx); //! \brief Updates the sql code field of the view form void updateCodePreview(void); //! \brief Adds or edit a object on the object table that calls the slot void handleObject(void); //! \brief Duplicates a object on the object table that calls the slot void duplicateObject(int curr_row, int new_row); //! \brief Removes the selected object from the table that calls the slot void removeObject(int row); //! \brief Removes all objects from the table that calls the slot void removeObjects(void); //! \brief Opens the reference form when a new row is added in the references grid void addReference(int row); //! \brief Duplicate the current selected reference void duplicateReference(int orig_row, int new_row); public slots: void applyConfiguration(void); void cancelConfiguration(void); }; #endif pgmodeler-0.9.2/libpgmodeler_ui/src/welcomewidget.cpp000066400000000000000000000022331360462764600230120ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "welcomewidget.h" #include "pgmodeleruins.h" WelcomeWidget::WelcomeWidget(QWidget *parent): QWidget(parent) { setupUi(this); QList btns= { new_tb, open_tb, recent_tb, last_session_tb, sample_tb, support_tb }; for(auto &btn : btns) { PgModelerUiNs::createDropShadow(btn, 3, 3, 10); #ifdef Q_OS_LINUX PgModelerUiNs::__configureWidgetFont(btn, 1.30); #else PgModelerUiNs::__configureWidgetFont(btn, 1.50); #endif } } pgmodeler-0.9.2/libpgmodeler_ui/src/welcomewidget.h000066400000000000000000000020121360462764600224520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libpgmodeler_ui \class WelcomeWidget */ #ifndef WELCOME_WIDGET_H #define WELCOME_WIDGET_H #include "ui_welcomewidget.h" class WelcomeWidget: public QWidget, public Ui::WelcomeWidget { private: Q_OBJECT public: WelcomeWidget(QWidget * parent = nullptr); public slots: }; #endif pgmodeler-0.9.2/libpgmodeler_ui/ui/000077500000000000000000000000001360462764600172755ustar00rootroot00000000000000pgmodeler-0.9.2/libpgmodeler_ui/ui/aboutwidget.ui000066400000000000000000000431331360462764600221560ustar00rootroot00000000000000 AboutWidget Qt::NonModal 0 0 550 530 0 0 550 530 16777215 550 About pgModeler :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 0 0 0 0 0 0 0 QFrame::StyledPanel QFrame::Raised 6 6 6 6 0 0 50 50 50 50 :/imagens/imagens/pgmodeler_logo.png true Qt::Horizontal 40 20 0 0 0 0 16777215 16777215 75 true true 0.0.0 0 0 75 true true Qt::LeftToRight build: -1 0 0 0 129 0 0 129 0 128 128 128 50 true false (BUILD_NUM) -1 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Qt::Horizontal 40 20 0 0 75 true PostgreSQL Database Modeler Qt::AlignCenter Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true Qt::Vertical QSizePolicy::Fixed 20 20 0 0 0 0 false QFrame::NoFrame Open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand, let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards. Qt::PlainText Qt::AlignJustify|Qt::AlignTop true 0 Qt::TextSelectableByMouse License 4 4 4 4 QFrame::Sunken QAbstractScrollArea::AdjustToContents false QTextEdit::WidgetWidth true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier';">pgModeler - PostgreSQL Database Modeler<br />Copyright 2006-2019 - Raphael Araújo e Silva<br /><br />This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 3.<br /><br />This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.<br /><br />The complete text of GPLv3 is at LICENSE file on pgModeler's source code root directory. Also, you can get the complete GNU General Public License at &lt;</span><a href="http://www.gnu.org/licenses"><span style=" font-family:'Courier'; text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses</span></a><span style=" font-family:'Courier';">&gt;</span></p></body></html> false Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 0 0 <html><head/><body><p><a href="http://pgmodeler.com.br"><span style=" text-decoration: underline; color:#2980b9;">https://pgmodeler.io</span></a></p></body></html> Qt::RichText 5 true pgModeler is proudly a brazilian software! :/imagens/imagens/brazil_flag.png Qt::AlignHCenter|Qt::AlignTop 0 0 <html><head/><body><p>Copyright 2006-2019 - Raphael Araújo e Silva &lt;<a href="mailto:raphael@pgmodeler.com.br"><span style=" text-decoration: underline; color:#0057ae;">raphael@pgmodeler.io</span></a>&gt;</p></body></html> Qt::AutoText 5 true pgmodeler-0.9.2/libpgmodeler_ui/ui/aggregatewidget.ui000066400000000000000000000061541360462764600227740ustar00rootroot00000000000000 AggregateWidget 0 0 493 369 0 0 2 2 2 2 6 Final Function: Sort Operator: Initial Condition: 0 0 0 200 0 Funtion Inputs Function State Transition Func.: 0 0 16777215 25 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff pgmodeler-0.9.2/libpgmodeler_ui/ui/appearanceconfigwidget.ui000066400000000000000000000323771360462764600243410ustar00rootroot00000000000000 AppearanceConfigWidget 0 0 449 139 Form 2 0 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 Element: Global: Font style Global: Constraints descriptor Global: Object selection Global: Position hint text Global: Position hint box Global: Objects type Global: Lock arc Global: Lock body Table: Schema name Table: Name Table: Columns box Table: Extended attributes box Table: Title box Rule: Name Rule: Descriptor Index: Name Index: Descriptor Trigger: Name Trigger: Descriptor Constraint: Name Constraint: Descriptor Policy: Name Policy: Descriptor View: Schema name View: Name View: References box View: Extended attributes box View: Title box View: Table / columns alias View: Referenced column View: Referenced table View: Reference descriptor Textbox: Body Column: Column name Column: Descriptor Column: Included / Inherited by relationship Column: Protected Column (pk): Name Column (pk): Descriptor Column (fk): Name Column (fk): Descriptor Column (uq): Name Column (uq): Descriptor Column (nn): Name Column (nn): Descriptor Relationship: Descriptor Relationship: Label text Relationship: Label box Relationship: Attribute text Relationship: Attribute descriptor Tag: Name Tag: Body Placeholder: Body Foreign table: Schema name Foreign table: Name Foreign table: Attributes box Foreign table: Extended attributes box Foreign table: Title box 0 0 Font: 0 0 Colors: 0 0 0 1 5.000000000000000 100.000000000000000 0.500000000000000 8.000000000000000 pt 0 0 Underline 0 0 50 false Italic 0 0 50 false Bold element_cmb font_cmb font_size_spb bold_chk italic_chk underline_chk pgmodeler-0.9.2/libpgmodeler_ui/ui/baseform.ui000066400000000000000000000155411360462764600214400ustar00rootroot00000000000000 BaseForm Qt::ApplicationModal 0 0 329 65 200 65 Dialog :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 2 2 2 2 false 0 2 0 0 2 2 2 2 6 0 0 0 30 16777215 30 Qt::PlainText :/imagens/imagens/pgmodeler_name.png 0 0 90 35 16777215 16777215 false &Apply :/icones/icones/confirmar.png:/icones/icones/confirmar.png 22 22 false true 0 0 90 35 16777215 16777215 false &Cancel :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 false false 0 0 QFrame::StyledPanel QFrame::Sunken pgmodeler-0.9.2/libpgmodeler_ui/ui/baseobjectwidget.ui000066400000000000000000000375151360462764600231540ustar00rootroot00000000000000 BaseObjectWidget 0 0 634 588 0 0 0 0 10 88 50 16 0 0 16777215 16777215 Name: 82 88 111 25 0 0 0 0 16777215 16777215 This is the name of the object in the PostgreSQL database. true 8 170 75 16 0 0 0 0 16777215 16777215 Comment: 10 204 91 16 0 0 Tablespace: 10 270 61 16 0 0 Schema: 318 311 141 30 0 0 0 30 16777215 16777215 Qt::StrongFocus Edit object's permissions Edit permissions :/icones/icones/permission.png:/icones/icones/permission.png 22 22 20 10 511 48 0 0 0 48 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 50 false false false true This object is protected thus no change in form will be applied to it. true 465 314 131 24 0 0 Qt::StrongFocus Disables the generated SQL code using comment tokens (--). This will disable the code of all child and referrer objects. Disable SQL code 10 300 61 16 0 0 Collation: 197 311 115 30 0 0 0 30 16777215 16777215 Qt::StrongFocus Append or prepend a set of SQL commands to the object's definition. Custom SQL :/icones/icones/sqlappend.png:/icones/icones/sqlappend.png 22 22 10 240 41 16 0 0 Owner: 200 80 161 31 6 0 0 0 0 0 0 75 true ID: 0 0 32 32 32 32 QFrame::NoFrame QFrame::Plain icone false Qt::AlignCenter 90 160 104 70 0 0 16777215 80 true 80 120 111 25 0 0 0 0 16777215 16777215 This is a more friendly name for the object. When displaying the model in compact view this is the name shown for the object instead of its real name. If this field is empty the real name will be displayed anyway. true 8 120 81 16 0 0 16777215 16777215 Alias: 200 120 31 31 0 0 6 0 0 0 0 0 0 22 22 22 22 name_edt append_sql_tb edt_perms_tb disable_sql_chk pgmodeler-0.9.2/libpgmodeler_ui/ui/bugreportform.ui000066400000000000000000000423411360462764600225350ustar00rootroot00000000000000 BugReportForm Qt::ApplicationModal 0 0 550 500 0 0 550 500 16777215 16777215 Bug Report :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 4 4 4 4 6 0 0 100 100 100 100 :/imagens/imagens/bugreport.png true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 13 75 true Bug report 4 4 2 0 0 0 90 35 16777215 16777215 &Cancel :/icones/icones/msgbox_erro.png:/icones/icones/msgbox_erro.png 22 22 false Qt::Horizontal QSizePolicy::Fixed 6 20 false 0 0 90 35 16777215 16777215 Create :/icones/icones/salvar.png:/icones/icones/salvar.png 22 22 true Qt::Horizontal 91 27 0 0 0 0 Use the form below to generate a complete bug report. Please, try to be as clear as possible when describing the actions that can reproduce the bug. Additionally, it's important to attach a sample database model so that the bug can be quickly discovered and fixed! Qt::PlainText Qt::AlignJustify|Qt::AlignTop true 4 true Qt::TextSelectableByMouse 0 0 0 Report 4 4 4 4 Issue details 4 4 4 4 0 0 0 0 0 0 Output: true Select the report's output folder ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 0 0 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_info.png true 50 false false false false true <html><head/><body><p>If you prefer it's possible to report this issue anytime on pgModeler's project repository at <a href="http://github.com/pgmodeler/pgmodeler/issues"><span style=" text-decoration: underline; color:#0057ae;">GitHub</span></a>. </p></body></html> Qt::AutoText true true Database Model 4 4 4 4 0 0 0 0 0 0 Attach the below database model file to be debugged. true Attach a different database model ... :/icones/icones/adddata.png:/icones/icones/adddata.png 20 20 attach_tb attach_mod_chk true DejaVu Sans Mono 8 true true pgmodeler-0.9.2/libpgmodeler_ui/ui/bulkdataeditwidget.ui000066400000000000000000000020361360462764600234760ustar00rootroot00000000000000 BulkDataEditWidget 0 0 350 40 350 40 Bulk data edit 4 4 4 4 true pgmodeler-0.9.2/libpgmodeler_ui/ui/castwidget.ui000066400000000000000000000115561360462764600220020ustar00rootroot00000000000000 CastWidget 0 0 513 52 0 0 2 2 2 2 6 0 0 0 0 16777215 16777215 I&mplicit false 0 0 0 0 16777215 16777215 Assignment 0 0 Input / Output 0 0 0 0 121 16777215 Conversion Func.: 0 0 0 0 16777215 16777215 Cast Type: 0 0 0 0 16777215 16777215 E&xplicit true Qt::Horizontal 40 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/collationwidget.ui000066400000000000000000000122061360462764600230250ustar00rootroot00000000000000 CollationWidget 0 0 459 74 0 0 2 2 2 2 6 0 0 0 0 Locale: 0 0 0 0 0 0 0 0 Encoding: 5 0 0 0 0 0 0 0 0 50 false false LC_COLLATE: 0 0 0 0 QComboBox::InsertAlphabetically 0 0 0 0 50 false false LC_CTYPE: 5 0 0 0 0 QComboBox::InsertAlphabetically pgmodeler-0.9.2/libpgmodeler_ui/ui/colorpickerwidget.ui000066400000000000000000000034051360462764600233560ustar00rootroot00000000000000 ColorPickerWidget 0 0 196 42 0 0 Form false true 0 0 41 41 0 0 0 0 Generate random color(s) :/icones/icones/random.png:/icones/icones/random.png 22 22 Alt+R pgmodeler-0.9.2/libpgmodeler_ui/ui/columnwidget.ui000066400000000000000000000112661360462764600223430ustar00rootroot00000000000000 ColumnWidget 0 0 585 250 2 2 2 2 6 Default Value: 4 4 4 4 0 30 Edit the underlying sequence's attributes Edit sequence :/icones/icones/sequence.png:/icones/icones/sequence.png Identity: E&xpression: true Se&quence: 16777215 16777215 QFrame::Sunken 1 0 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true Qt::Horizontal 40 20 false 0 0 &NOT NULL expression_rb def_value_txt sequence_rb pgmodeler-0.9.2/libpgmodeler_ui/ui/configurationform.ui000066400000000000000000000336471360462764600234040ustar00rootroot00000000000000 ConfigurationForm Qt::ApplicationModal 0 0 813 660 0 0 800 660 pgModeler Configuration :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 2 2 2 2 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 2 0 0 160 0 16777215 16777215 QFrame::StyledPanel Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff false 16 QAbstractItemView::NoEditTriggers false QAbstractItemView::NoDragDrop Qt::IgnoreAction false QAbstractItemView::SelectItems 32 32 Qt::ElideLeft QListView::Snap QListView::TopToBottom false QListView::Adjust QListView::SinglePass 5 0 45 QListView::ListMode 0 true 1 false false -1 General AlignLeading|AlignVCenter :/icones/icones/config.png:/icones/icones/config.png ItemIsSelectable|ItemIsEnabled Relationships :/icones/icones/relationshiptv.png:/icones/icones/relationshiptv.png ItemIsSelectable|ItemIsUserCheckable|ItemIsEnabled Appearance AlignLeading|AlignVCenter :/icones/icones/aparencia.png:/icones/icones/aparencia.png ItemIsSelectable|ItemIsEnabled Connections AlignLeading|AlignVCenter :/icones/icones/conexaobd.png:/icones/icones/conexaobd.png ItemIsSelectable|ItemIsEnabled Snippets :/icones/icones/codesnippet.png:/icones/icones/codesnippet.png ItemIsSelectable|ItemIsUserCheckable|ItemIsEnabled Plug-ins AlignLeading|AlignVCenter :/icones/icones/plugins.png:/icones/icones/plugins.png ItemIsSelectable|ItemIsEnabled 0 0 0 0 16777215 16777215 Qt::LeftToRight -1 QLayout::SetDefaultConstraint 2 Qt::Horizontal QSizePolicy::Expanding 200 27 0 0 90 35 16777215 16777215 Defaults :/icones/icones/padroes.png:/icones/icones/padroes.png 22 22 false false 0 0 90 35 16777215 16777215 &Apply :/icones/icones/confirmar.png:/icones/icones/confirmar.png 22 22 true 0 0 90 35 16777215 16777215 &Cancel :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 false 0 0 :/imagens/imagens/pgmodeler_name.png pgmodeler-0.9.2/libpgmodeler_ui/ui/connectionsconfigwidget.ui000066400000000000000000001062231360462764600245540ustar00rootroot00000000000000 ConnectionsConfigWidget 0 0 562 446 Edit database connections 2 0 0 0 560 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 Connections: 6 0 0 QComboBox::InsertAtBottom QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 true Create new connection :/icones/icones/novo.png:/icones/icones/novo.png 22 22 true Cancel edition :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 true Duplicate the selected connection :/icones/icones/duplicate.png:/icones/icones/duplicate.png 22 22 false Edit selected connection :/icones/icones/editar.png:/icones/icones/editar.png 22 22 false Delete selected connection :/icones/icones/excluir.png:/icones/icones/excluir.png 22 22 0 General 4 4 4 4 0 0 Timeout: Qt::Horizontal 40 20 false 0 0 0 30 16777215 16777215 Test :/icones/icones/conexaobd.png:/icones/icones/conexaobd.png 22 22 false 0 0 0 30 16777215 16777215 Add :/icones/icones/adicionar.png:/icones/icones/adicionar.png 22 22 false 0 0 0 30 16777215 16777215 Update :/icones/icones/padroes.png:/icones/icones/padroes.png 22 22 0 0 Password: 0 0 true 1 65535 5432 0 0 Default for: 0 0 true 0 0 User: 0 0 Host/Port: 0 0 Connection Alias: QLineEdit::Password true 0 0 Connection DB: 0 0 Other params: Specify additional connection parameters in the form [param]=[value]. These parameters are described in the <strong>libpq</strong> chapter at PostgreSQL docs. true 0 0 22 22 22 22 2 0 0 second(s) 0 0 true Diff Export Import Validation 0 0 22 22 22 22 Qt::Horizontal 40 20 0 0 true Automatically browses the named database when using this connection to manage databases on <strong>Manage</strong> view. Auto browse 0 0 22 22 22 22 Qt::Vertical 20 40 Qt::Vertical QSizePolicy::Fixed 20 10 Security 4 4 4 4 false ~/.postgresql/postgresql.crt true 200 0 Disable Allow Require AC verification Full verification Qt::Horizontal 40 20 false ~/.postgresql/root.crt true true true 0 0 Force GSSAPI 0 0 SSL Mode: false 0 0 Client Key: false ~/.postgresql/root.crl true true 0 0 Kerberos Server: false 0 0 Root Certificate: false 0 0 Revoked Certs.: false ~/.postgresql/postgresql.key true false 0 0 Client Certificate: Qt::Vertical 20 40 connections_cmb new_tb cancel_tb duplicate_tb edit_tb remove_tb conn_attribs_tbw alias_edt conn_db_edt auto_browse_chk host_edt port_sbp user_edt passwd_edt timeout_sbp other_params_edt diff_chk export_chk import_chk validation_chk test_tb add_tb update_tb ssl_mode_cmb client_cert_edt client_key_edt root_cert_edt crl_edt krb_server_edt gssapi_auth_chk pgmodeler-0.9.2/libpgmodeler_ui/ui/constraintwidget.ui000066400000000000000000000407551360462764600232370ustar00rootroot00000000000000 ConstraintWidget 0 0 574 649 0 0 2 2 2 2 6 0 0 80 0 75 16777215 Match: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 0 120 0 0 0 100 0 Constraint Type: 100 0 This attribute cannot be changed once the object is created. 0 0 100 0 Expression: false 0 0 10 100 100 0 0 100 0 Deferrable: 0 0 false 0 0 0 0 16777215 16777215 Deferral: false 0 0 120 0 0 0 120 0 0 0 100 0 ON DELETE: 0 0 0 0 16777215 16777215 ON UPDATE: 0 0 120 0 No inherit: 0 0 Exclude Elements 0 0 0 0 0 Columns 4 4 4 4 6 0 0 Column: 0 0 180 0 Qt::Horizontal QSizePolicy::Preferred 40 20 0 0 Referenced Columns 4 4 4 4 Qt::Horizontal QSizePolicy::Preferred 40 20 0 0 0 0 16777215 16777215 0 0 0 0 Column: 0 0 Table: 0 0 Indexing: false 0 0 Fill Factor: 0 0 0 50 16777215 16777215 QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded constr_type_cmb match_cmb no_inherit_chk expression_txt fill_factor_sb deferrable_chk deferral_cmb on_delete_cmb on_update_cmb columns_tbw column_cmb ref_column_cmb pgmodeler-0.9.2/libpgmodeler_ui/ui/conversionwidget.ui000066400000000000000000000122741360462764600232330ustar00rootroot00000000000000 ConversionWidget 0 0 439 82 0 0 2 2 2 2 6 0 0 0 0 16777215 16777215 Source Encoding: true 0 0 0 25 0 0 0 0 16777215 16777215 Target Encoding: 5 true 0 0 0 25 0 0 0 0 16777215 16777215 Conversion Func.: Qt::Horizontal 273 20 0 0 0 0 16777215 16777215 Default Conversion: 0 0 pgmodeler-0.9.2/libpgmodeler_ui/ui/csvloadwidget.ui000066400000000000000000000252641360462764600225040ustar00rootroot00000000000000 CsvLoadWidget 0 0 710 100 Form 0 0 0 0 0 0 0 100 Load CSV 4 4 4 4 CSV File: true true 0 0 Select output file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 Separator: Qt::Horizontal QSizePolicy::Fixed 5 20 0 Use the first row as column names in the CSV file. By unchecking this option the first row is used as data. Columns in the first row true 0 0 22 22 22 22 Qt::Horizontal 32 20 false 0 0 0 30 16777215 16777215 Load :/icones/icones/loadcsv.png:/icones/icones/loadcsv.png 22 22 false false 4 0 0 110 0 Semicolon (;) Comma (,) Space Tabulation Other 0 0 25 16777215 0 0 ; 2 Qt::AlignCenter 0 Text delimiter: true true 0 0 25 16777215 0 0 " 2 Qt::AlignCenter Qt::Horizontal QSizePolicy::Fixed 5 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/customsqlwidget.ui000066400000000000000000000332361360462764600231010ustar00rootroot00000000000000 CustomSQLWidget 0 0 666 389 0 0 0 0 Add custom SQL code 0 0 0 0 SQL code 4 4 4 4 Qt::Horizontal 40 20 0 27 false Puts an SELECT command template at current cursor position. &SELECT :/icones/icones/objselect.png:/icones/icones/objselect.png 20 20 QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon 0 27 false Puts an INSERT command template at current cursor position. &INSERT :/icones/icones/adicionar.png:/icones/icones/adicionar.png 20 20 QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon 0 27 false Puts an UPDATE command template at current cursor position. &UPDATE :/icones/icones/atualizar.png:/icones/icones/atualizar.png 20 20 QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon 0 27 false Puts an DELETE command template at current cursor position. &DELETE :/icones/icones/excluir.png:/icones/icones/excluir.png 20 20 QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon false &Clear :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 20 20 Qt::ToolButtonTextBesideIcon Qt::Horizontal 40 20 0 Append SQL 4 4 4 4 Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command. Append at end of model definition. Prepend SQL 4 4 4 4 Append the SQL code at the very end of model definition. Unchecking this will cause the SQL to be appended at the end of CREATE DATABASE command. Prepend at beginning of model definition. 0 0 0 0 QFrame::NoFrame QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 50 false false false true <html><head/><body><p>Use custom commands with extreme caution because you can change the semantics of the entire model when running SQL validation or export processes. Additionally, depending on the amount of commands, those processes can have their performance sensibly degradated.</p></body></html> true select_tb insert_tb update_tb delete_tb clear_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/databaseexplorerwidget.ui000066400000000000000000000504211360462764600243670ustar00rootroot00000000000000 DatabaseExplorerWidget 0 0 285 697 0 0 Form 4 4 4 4 4 true 8 Toggle the display of filter widget as well the system/extension objects. Data &Grid :/icones/icones/filter.png:/icones/icones/filter.png 22 22 Alt+G QToolButton::InstantPopup Qt::ToolButtonIconOnly true true 8 Sort items alphabetically. When unchecked, items are sorted by OID. Sort alphabetically :/icones/icones/sortasc.png:/icones/icones/sortasc.png 22 22 true true Qt::ToolButtonIconOnly true true 8 Open the grid to visualize or edit data Data &Grid :/icones/icones/result.png:/icones/icones/result.png 22 22 Alt+G Qt::ToolButtonIconOnly true true Add a new SQL execution tab for the current database ... :/icones/icones/runsqldb.png:/icones/icones/runsqldb.png 22 22 Ctrl+F6 true true Update the objects tree ... :/icones/icones/refreshdb.png:/icones/icones/refreshdb.png 22 22 true true Drop this database ... :/icones/icones/excluir.png:/icones/icones/excluir.png 22 22 true Qt::Horizontal 40 20 Qt::Vertical false true 0 0 QFrame::Sunken Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustIgnored QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows 20 20 Qt::ElideRight 20 true true false true true true 2 true 1 2 0 0 0 65 0 0 0 5 Qt::Horizontal 40 20 true 0 0 Expands all items ... :/icones/icones/adicionar.png:/icones/icones/adicionar.png 22 22 false true 0 0 Collapses all items ... :/icones/icones/remover.png:/icones/icones/remover.png 22 22 false Qt::Horizontal 40 20 true 0 0 Filters the currently loaded items in the tree by using a pattern and matching their names. If <strong>By OID</strong> is checked the pattern is interpreted as an integer value that represents the object id (OID). <br><br/><strong>HINT:</strong> if you need to search the entire database use the full refresh (<strong>Ctrl+F5</strong>) prior the filtering. Filter: true true By OID 0 0 22 22 22 22 0 100 0 0 0 0 QFrame::StyledPanel 1 QAbstractScrollArea::AdjustIgnored 16 QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed false false false true QAbstractItemView::ContiguousSelection QAbstractItemView::SelectItems true Qt::SolidLine true true false 100 25 true false 26 false Attribute Value Show raw attributes raw_attrib_names_chk properties_tbw pgmodeler-0.9.2/libpgmodeler_ui/ui/databaseimportform.ui000066400000000000000000001273761360462764600235370ustar00rootroot00000000000000 DatabaseImportForm Qt::ApplicationModal 0 0 690 530 0 0 690 530 16777215 16777215 Import database :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 4 4 4 4 true 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 0 Settings 4 4 4 4 Qt::Horizontal false 0 0 Options 4 4 4 4 0 0 Connection: 0 0 Resolve some of the object's dependencies by querying the catalog when a needed object does not exists on the loaded set. In some cases it's necessary to combine this option with others below. This option does not applies to database level objects like role, tablespace and language as well for data types, extensions. Automatically resolve dependencies true 0 0 22 22 22 22 Qt::Vertical 20 40 0 0 All catalog queries as well the created objects' source code are printed to standard output (stdout). Debug mode 0 0 22 22 22 22 Create all imported objects in the current working model instead of create a new one. Import objects to the working model false 0 0 22 22 22 22 0 0 Enables the import of system built-in objects. It's recommend to select only those objects that are directly referenced by the ones to be imported. WARNING: Try to import a huge set of system objects can bloat the resultant model or even crash pgModeler due to memory/cpu overuse. Import system objects 0 0 22 22 22 22 0 0 Enables the import of objects created by extensions. Generally there is no need to check this option but if there are objects in the database that directly references this category of objects this mode must be enabled. Import extension objects 0 0 22 22 22 22 0 0 pgModeler ignores import errors and will try to create as many as possible objects. By checking this option the import operation will not be aborted but an incomplete model will be constructed. This option generates a log file on pgModeler's temp directory. Ignore import errors 0 0 22 22 22 22 0 0 QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 Random colors will be assigned to imported relationships facilitating the identification of links between tables mainly in large models. Random colors for relationships true 0 0 22 22 22 22 true 0 0 Database 4 4 4 4 false 0 0 QComboBox::InsertAlphabetically QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 true 0 0 0 0 true 300 0 QFrame::Sunken QAbstractItemView::NoEditTriggers true QAbstractItemView::NoSelection QAbstractItemView::SelectRows 20 20 Qt::ElideRight true true false true true true 2 false 50 false 1 2 true 0 0 Filter: true true true Filter object by it's OID By OID Qt::Horizontal 90 20 true 0 0 0 0 Select all objects ... :/icones/icones/seltodos.png:/icones/icones/seltodos.png 22 22 false true 0 0 0 0 Clear object selection ... :/icones/icones/clearobjsel.png:/icones/icones/clearobjsel.png 22 22 false true 0 0 0 0 Expands all items ... :/icones/icones/adicionar.png:/icones/icones/adicionar.png 22 22 false true 0 0 0 0 Collapses all items ... :/icones/icones/remover.png:/icones/icones/remover.png 22 22 false Qt::Horizontal 77 20 Output 4 4 4 4 4 4 4 4 0 0 22 22 22 22 true Qt::AlignCenter 0 0 Progress label... false Cancel :/icones/icones/msgbox_erro.png:/icones/icones/msgbox_erro.png 22 22 Qt::ToolButtonTextBesideIcon 0 0 0 Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustToContents QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed true QAbstractItemView::SingleSelection 20 20 20 true false 25 0 0 0 0 :/imagens/imagens/pgmodeler_name.png Qt::Horizontal 246 20 false 0 0 90 32 16777215 16777215 &Import :/icones/icones/import.png:/icones/icones/import.png 22 22 true 0 0 90 32 16777215 16777215 &Close :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 false connections_cmb resolve_deps_chk import_sys_objs_chk import_ext_objs_chk ignore_errors_chk debug_mode_chk database_cmb filter_edt by_oid_chk cancel_btn import_btn close_btn pgmodeler-0.9.2/libpgmodeler_ui/ui/databasewidget.ui000066400000000000000000000273621360462764600226160ustar00rootroot00000000000000 DatabaseWidget 0 0 453 223 0 0 0 0 0 0 0 Attributes 4 4 4 4 0 0 96 0 Template DB: 0 25 true 0 0 Model Author: 0 25 true 0 0 96 0 Encoding: 0 25 0 0 85 0 50 false false LC_COLLATE: 0 25 true QComboBox::InsertAlphabetically 0 0 96 0 50 false false Connections: 0 25 -1 65535 -1 0 0 70 0 50 false false LC_CTYPE: 0 25 true QComboBox::InsertAlphabetically 0 0 96 0 50 false false Options: Allow connections true Is template Qt::Horizontal 40 20 Qt::Vertical QSizePolicy::Preferred 20 40 Default Objects 4 4 4 4 Tablespace: Schema: Collation: Owner: Qt::Vertical QSizePolicy::Preferred 20 40 pgmodeler-0.9.2/libpgmodeler_ui/ui/datamanipulationform.ui000066400000000000000000001774301360462764600240660ustar00rootroot00000000000000 DataManipulationForm 0 0 897 650 700 650 1250 900 Data Manipulation :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png false 0 2 2 2 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 Qt::Horizontal 40 20 0 0 Schema: 0 0 20 QComboBox::InsertAtBottom 16 16 0 0 Table: 0 0 20 QComboBox::InsertAtBottom QComboBox::AdjustToContentsOnFirstShow 16 16 0 0 Hide views true 0 20 20 22 22 :/icones/icones/database.png true 0 0 5 0 0 Qt::Horizontal false true 0 0 QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked true QAbstractItemView::ExtendedSelection QAbstractItemView::SelectItems QAbstractItemView::ScrollPerItem QAbstractItemView::ScrollPerPixel false 0 0 true 30 false true false false 26 25 false 0 Filter 4 4 4 4 Qt::Vertical false Expression 4 4 4 4 0 0 0 0 Order && Limit 4 4 4 4 0 0 Qt::Horizontal 40 20 false 0 0 0 0 Add Item :/icones/icones/adicionar.png:/icones/icones/adicionar.png 20 20 Ins false 0 0 0 0 Remove Item :/icones/icones/remover.png:/icones/icones/remover.png 20 20 Del false 0 0 0 0 Clear the order by columns list :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 20 20 Del false 0 0 0 0 Move selected item up :/icones/icones/movercima.png:/icones/icones/movercima.png 20 20 Del false 0 0 0 0 Move selected item down :/icones/icones/moverbaixo.png:/icones/icones/moverbaixo.png 20 20 Del Qt::Horizontal 40 20 0 0 0 1000000 50 1000 0 0 Column: 0 0 results (Use <strong>0</strong> for no limit) Limit in: 0 0 QComboBox::InsertAlphabetically 0 0 ASC true 0 0 DESC Columns 4 4 4 4 Qt::Horizontal 58 20 0 0 Select all 0 0 Clear all Qt::Horizontal 58 20 0 0 0 30 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_info.png true 0 0 50 false false false true <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> true 0 0 2 2 2 2 0 0 false -1 0 0 0 0 0 30 QFrame::StyledPanel QFrame::Raised 2 2 2 2 50 false false false false true true 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 0 0 0 0 0 3 0 3 4 false 0 0 0 0 Add empty rows Add :/icones/icones/addrow.png:/icones/icones/addrow.png 25 25 Ins Qt::ToolButtonIconOnly true false 0 0 0 0 Clears the items selected on the grid Clear :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 25 25 Ctrl+R QToolButton::InstantPopup Qt::ToolButtonIconOnly true Qt::Horizontal false 0 0 0 0 Change the values of all selected cells at once Edit :/icones/icones/bulkedit.png:/icones/icones/bulkedit.png 25 25 Ctrl+E Qt::ToolButtonIconOnly true false 0 0 0 0 Browse referenced tables Browse :/icones/icones/browsetable.png:/icones/icones/browsetable.png 25 25 QToolButton::InstantPopup Qt::ToolButtonIconOnly true true 0 0 0 0 Add new rows from a CSV file Load CSV :/icones/icones/loadcsv.png:/icones/icones/loadcsv.png 25 25 Ctrl+L true Qt::ToolButtonIconOnly true false 0 0 0 0 Copy items on the grid Copy :/icones/icones/copiar.png:/icones/icones/copiar.png 25 25 QToolButton::InstantPopup Qt::ToolButtonIconOnly true false 0 0 0 0 Duplicate the selected rows Duplicate :/icones/icones/duprow.png:/icones/icones/duprow.png 25 25 Ctrl+D Qt::ToolButtonIconOnly true Qt::Horizontal false 0 0 0 0 Filter the result set Filter :/icones/icones/filter.png:/icones/icones/filter.png 25 25 Ctrl+F true Qt::ToolButtonIconOnly true false 0 0 0 0 Mark the selected rows to be deleted Delete :/icones/icones/delrow.png:/icones/icones/delrow.png 25 25 Del Qt::ToolButtonIconOnly true Qt::Horizontal Qt::Vertical 20 40 true 0 0 0 0 Open a new data manipulation window New :/icones/icones/novoobjeto.png:/icones/icones/novoobjeto.png 25 25 Ctrl+N Qt::ToolButtonIconOnly true Qt::Horizontal false 0 0 0 0 Paste items on the grid Paste :/icones/icones/colar.png:/icones/icones/colar.png 25 25 QToolButton::InstantPopup Qt::ToolButtonIconOnly true false 0 0 0 0 Save changes Save :/icones/icones/salvar.png:/icones/icones/salvar.png 25 25 Ctrl+S Qt::ToolButtonIconOnly true false 0 0 0 0 Undo modifications Undo :/icones/icones/desfazer.png:/icones/icones/desfazer.png 25 25 Ctrl+Z Qt::ToolButtonIconOnly true false 0 0 0 0 Export results to CSV file Export :/icones/icones/exportdata.png:/icones/icones/exportdata.png 25 25 Ctrl+X Qt::ToolButtonIconOnly true false 0 0 0 0 Refresh listing Refresh :/icones/icones/atualizar.png:/icones/icones/atualizar.png 25 25 F5 Qt::ToolButtonIconOnly true false 0 0 0 0 Truncate the browsed table Truncate :/icones/icones/truncate.png:/icones/icones/truncate.png 25 25 QToolButton::InstantPopup Qt::ToolButtonIconOnly true 2 2 2 2 6 0 0 127 0 Qt::PlainText :/imagens/imagens/pgmodeler_name.png 0 0 90 32 16777215 16777215 false &Close :/icones/icones/fechar1.png:/icones/icones/fechar1.png 20 20 false false false Qt::Horizontal 40 20 close_btn pgmodeler-0.9.2/libpgmodeler_ui/ui/domainwidget.ui000066400000000000000000000102431360462764600223070ustar00rootroot00000000000000 DomainWidget 0 0 487 140 4 4 4 4 0 Attributes 4 4 4 4 Default Value: true Not null Check constraints 4 4 4 4 Name: true Expression: 0 0 0 50 16777215 16777215 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded pgmodeler-0.9.2/libpgmodeler_ui/ui/donatewidget.ui000066400000000000000000000161101360462764600223110ustar00rootroot00000000000000 DonateWidget 0 0 400 245 0 0 16777215 600 Form 0 0 0 0 QFrame::StyledPanel QFrame::Raised 6 6 6 6 75 true Donate to pgModeler Qt::AlignCenter 0 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true 0 0 0 0 false QFrame::NoFrame <html><head/><body><p>pgModeler is brought to you thanks to a <span style=" font-style:italic;">great effort to create and distribute a quality product</span>. This project is reaching out levels of maturity never imagined. All this is the result of a joint work between its author and the <span style=" font-weight:600;">Open Source community</span>. <br/><br/>This software has a long way to go yet and with your help we'll keep maintaining the good job and bringing new improvements on each release. If you did like pgModeler and thinks it deserves a contribution please make a donation!</p></body></html> Qt::RichText Qt::AlignJustify|Qt::AlignTop true 0 Qt::NoTextInteraction Qt::Horizontal 118 20 0 0 0 30 I want to help! :/icones/icones/donate.png:/icones/icones/donate.png 22 22 false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon Qt::Horizontal 118 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/elementwidget.ui000066400000000000000000000211201360462764600224650ustar00rootroot00000000000000 ElementWidget 0 0 540 215 540 215 Element properties 4 4 4 4 6 0 0 0 0 16777215 16777215 Operator Class: false 0 0 0 50 16777215 16777215 QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded 0 0 Sorting: true 0 0 Ascending true 0 0 Descending 0 0 Nulls first 0 0 0 0 16777215 16777215 Column: true false 0 0 Operator: 0 0 0 0 16777215 16777215 Expression: false false 0 0 Collation: 0 0 0 0 0 0 0 0 180 0 16777215 16777215 Qt::Horizontal 95 20 column_rb expression_rb elem_expr_txt sorting_chk ascending_rb descending_rb nulls_first_chk pgmodeler-0.9.2/libpgmodeler_ui/ui/eventtriggerwidget.ui000066400000000000000000000054001360462764600235440ustar00rootroot00000000000000 EventTriggerWidget 0 0 537 316 0 0 0 0 Event: Qt::Horizontal 383 20 Function: 0 0 Filter 4 4 4 4 Tag: true pgmodeler-0.9.2/libpgmodeler_ui/ui/extensionwidget.ui000066400000000000000000000057521360462764600230650ustar00rootroot00000000000000 ExtensionWidget 0 0 349 70 0 0 0 0 6 0 0 Version: 0 0 100 0 true 0 0 Old Version: 0 0 100 0 true 0 0 This attribute cannot be changed once the object is created. Handles data type pgmodeler-0.9.2/libpgmodeler_ui/ui/findreplacewidget.ui000066400000000000000000000230541360462764600233200ustar00rootroot00000000000000 FindReplaceWidget 0 0 704 68 0 0 Form 0 0 0 0 0 0 Find: true false 8 Find previous :/icones/icones/anterior.png:/icones/icones/anterior.png 22 22 Shift+F3 Qt::ToolButtonIconOnly false 8 Find next :/icones/icones/proximo.png:/icones/icones/proximo.png 22 22 F3 Qt::ToolButtonIconOnly 0 0 Case sensitive 0 0 Regular expression 0 0 Whole words Qt::Horizontal 98 20 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true 0 0 Replace: true 0 0 0 0 0 0 false Replace one occurrence Replace 20 20 Qt::ToolButtonTextBesideIcon false Replace all occurrences Replace All 20 20 Qt::ToolButtonTextBesideIcon false Replace the selection and find the next one Replace && Find 20 20 Qt::ToolButtonTextBesideIcon Qt::Horizontal 40 20 previous_tb next_tb case_sensitive_chk regexp_chk replace_tb replace_all_tb replace_find_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/foreigndatawrapperwidget.ui000066400000000000000000000077441360462764600247400ustar00rootroot00000000000000 ForeignDataWrapperWidget 0 0 337 221 0 0 0 0 0 0 0 0 22 22 22 22 0 0 0 0 Validator: 0 0 0 0 Handler: 0 0 22 22 22 22 0 0 0 20 0 0 0 20 Options pgmodeler-0.9.2/libpgmodeler_ui/ui/foreignserverwidget.ui000066400000000000000000000060471360462764600237270ustar00rootroot00000000000000 ForeignServerWidget 0 0 462 210 0 0 0 0 0 0 0 0 0 0 Version: 0 0 0 0 FDW: 0 0 0 0 Type: Options 0 0 0 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/functionwidget.ui000066400000000000000000000510471360462764600226740ustar00rootroot00000000000000 FunctionWidget 0 0 611 383 0 0 465 216 2 2 2 2 6 0 0 0 273 0 Attributes 4 4 4 4 6 100 16777215 16777215 16777215 Security: -1 0 0 0 0 16777215 16777215 Function Type: 0 0 0 1 16777215 1 QFrame::StyledPanel QFrame::Sunken 0 0 1000000000 16777215 16777215 Rows Returned: 5 0 0 16777215 16777215 50 false Language: 0 0 0 1 16777215 1 QFrame::StyledPanel QFrame::Sunken 0 0 16777215 16777215 Return Method: 0 0 16777215 16777215 Behavior: 0 0 0 0 Si&mple true true 0 0 Set true 0 0 Tab&le true 0 0 Return Table 0 0 0 0 16777215 16777215 Execution Cost: 5 0 0 Windown Func. 0 0 1 10000 Qt::Horizontal QSizePolicy::Expanding 40 20 Leakproof Parameters Definition 4 4 4 4 6 0 0 QFrame::NoFrame QFrame::Raised 2 2 2 2 6 Dynamic Library: Qt::Horizontal 450 20 true 16777215 16777215 Symbol: true 0 0 true true 16777215 16777215 Library: true 0 0 true Qt::Vertical 20 40 0 0 QFrame::NoFrame QFrame::Raised 2 2 2 2 6 Source code: Qt::Horizontal 485 20 func_config_twg language_cmb func_type_cmb rows_ret_spb security_cmb exec_cost_spb behavior_cmb window_func_chk leakproof_chk simple_rb set_rb table_rb symbol_edt library_edt pgmodeler-0.9.2/libpgmodeler_ui/ui/generalconfigwidget.ui000066400000000000000000002536121360462764600236540ustar00rootroot00000000000000 GeneralConfigWidget 0 0 795 712 0 0 Form 2 0 0 0 0 200 0 General && Design 4 4 4 4 Qt::Vertical 20 40 Design 4 4 4 4 10 0 0 210 0 Attributes per page: 0 0 60 0 These spinners define the minimum amount of attributes visible per page in each section of tables and views when the pagination is enabled on them. The first one controls the amount of columns per page. The second defines the amount of extended attributes (constraints, indexes, trigger, rules, policies) displayed per page. 5 100 5 10 Qt::Horizontal QSizePolicy::Fixed 10 20 0 0 60 0 Defines the minimum amount of attributes visible per page on tables and view when the pagination is enabled on these objects. 5 100 5 5 Qt::Horizontal 40 20 0 0 22 22 22 22 0 0 210 0 Minimum object opacity (%): 0 0 60 0 Defines the minimum opacity percentage applied to the objects when using the fade out feature. A zero opacity causes the object to be completely hidden not being possible to interact with it in the canvas area. 0 70 5 10 Qt::Horizontal 40 20 0 0 22 22 22 22 0 0 210 0 Defines the period when the opened models will be saved automatically. The temporary models saving period will be defined as the half of the value defined here. If the autosave is disabled the temporary models saving will occur in a period of 5 minutes. Autosave interval (minutes): 0 0 60 0 5 30 5 Qt::Horizontal 40 20 0 0 22 22 22 22 0 0 210 0 Operation history size: 0 0 60 0 Defines the maximum amount of elements held in the operation history. Once reached the maximum number the history is automatically cleaned. 500 1000 Qt::Horizontal 40 20 0 0 22 22 22 22 0 0 210 0 Canvas grid size: 0 0 60 0 Defines the vertical and horizontal grid size. This value affects the spacing of objects when using the feature that aligns the objects on the grid. 10 100 1 20 Qt::Horizontal 40 20 0 0 22 22 22 22 0 0 Graphical objects (table, views and textboxes) will be created in a single step without the need to click on canvas Simplify the creation of graphical objects false 0 0 22 22 22 22 0 0 When enabled this option creates a placeholder object at the previous table's position when starting to move it. This will cause graphical updates on relationship lines to be performed only when the drag & drop action is done improving the performance. Disabling placeholders will cause those updates to be executed every time the table's position changes a single pixel (classical behavior). Use placeholders when moving tables 0 0 22 22 22 22 0 0 After loading the model the last zoom and position on canvas will be restored Save and restore last position and zoom 0 0 22 22 22 22 0 0 By default the range selection is triggered with Shift + left click. By checking this option range selection will be activated only with a single click and move. Trigger range selection with a single click false 0 0 22 22 22 22 0 0 Hide the portion of table which represents triggers, indexes and rules. Hide table extended attributes 0 0 22 22 22 22 0 0 Hide the object which represents the tag assigned to the table Hide table tags 0 0 22 22 22 22 0 0 Hide the object that represents the relationship name Hide relationship name 0 0 22 22 22 22 Triggers a dialog asking the user to validate the model before a save, export or diff operation. Validate before save, export or diff false 0 0 22 22 22 22 0 0 Start move the canvas when the cursor is on the canvas edges Move canvas by keeping the mouse on corners false 0 0 22 22 22 22 0 0 Replaces any straight line in relationship by curved ones in order to improve the model's visualization. Use curved lines for relationships 0 0 22 22 22 22 0 0 Toggles the code completion in all fields that accepts the input of SQL commands. Enable SQL code completion 0 0 22 22 22 22 0 0 Disable the antialiasing for lines and texts improving performance when handling huge models. Disable render smoothness 0 0 22 22 22 22 0 0 Forces the escaping of line breaks and tabulations in objects' comments during SQL code generation. This option produces a more compact SQL code since all comments will be presented in one line. Despite changing the presentation this option doesn't affect the final semantics of multilined comments. Escape objects' comments in SQL code 0 0 22 22 22 22 General 4 4 4 4 Save/restore dialogs sizes Qt::Horizontal QSizePolicy::Expanding 25 20 false 0 0 0 30 16777215 16777215 Qt::StrongFocus Reset the dialogs sizes and positions to their default values. Reset sizes :/icones/icones/atualizar.png:/icones/icones/atualizar.png 22 22 Qt::ToolButtonTextBesideIcon Qt::Horizontal QSizePolicy::Fixed 100 20 0 0 22 22 22 22 Souce code editor args: true false 0 0 0 0 SQL history max. length: Souce code editor: Overrides the default user interface language defined by the system. Requires restarting the program. <strong>NOTE:</strong> UI translations are third party collaborations thus any typo or mistake should be reported directly to their respective maintainers. 0 0 0 0 16777215 16777215 Open in file manager :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 0 0 16777215 16777215 Browse the source code editor application :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 60 0 1000 20000 500 1000 0 0 0 0 16777215 16777215 lines Qt::Horizontal QSizePolicy::Expanding 25 20 0 0 0 30 16777215 16777215 Qt::StrongFocus Clear the entire SQL comand history. Clear history :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 22 22 Qt::ToolButtonTextBesideIcon Qt::Horizontal QSizePolicy::Fixed 100 20 Configurations directory: User interface language: false true false true Check if there is a new version on server Check updates at startup false Reduces the verbosity of the export, import and diff process causing only key info messages and errors to be displayed. This option causes less rendering operations to be performed when displaying progress messages and, as a consequence, it makes these processes run faster. Low verbosity for the export, import and diff processes 0 0 22 22 22 22 Qt::Horizontal 40 20 Printing && Code 4 4 4 4 Code style 4 4 4 4 0 0 Size: 0 0 Font: 0 0 Colors: 0 0 Options: Display line numbers true 0 0 Highlight lines at cursor's position true 0 0 1 5.000000000000000 100.000000000000000 0.500000000000000 8.000000000000000 0 0 pt Qt::Horizontal QSizePolicy::Fixed 30 20 Custom tab width: true true 1 100 1 Qt::Horizontal 40 20 Printing 4 4 4 4 Options: 0 0 Print grid true 0 0 Print page numbers true 0 0 Paper: 0 0 16777215 16777215 0 A0 (841 x 1189 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) B0 (1030 x 1456 mm) B1 (728 x 1030 mm) B10 (32 x 45 mm) B2 (515 x 728 mm) B3 (364 x 515 mm) B4 (257 x 364 mm) B5 (182 x 257 mm) B6 (128 x 182 mm) B7 (91 x 128 mm) B8 (64 x 91 mm) B9 (45 x 64 mm) C5E (163 x 229 mm) Comm10E (105 x 241 mm) DLE (110 x 220 mm) Executive (191 x 254 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Legal (216 x 356 mm) Letter (216 x 279 mm) Tabloid (279 x 432 mm) Custom 0 0 Orientation: 0 0 Landscape true 0 0 Portrait Unity: Custom Size: 0 0 Width: 1.000000000000000 999999.989999999990687 0 0 52 0 Height: 1.000000000000000 999999.989999999990687 0 0 Page Margins: 39 0 Left: 0 0 50 23 Left margin 5000.000000000000000 Top: 0 0 50 23 Top margin 5000.000000000000000 39 0 Right: 0 0 50 23 Bottom margin 5000.000000000000000 0 0 50 23 Right margin 5000.000000000000000 Bottom: 0 0 0 Milimeters Pixels Inches Centimeter Qt::Vertical 20 40 grid_size_spb oplist_size_spb autosave_interv_spb print_grid_chk print_pg_num_chk paper_cmb landscape_rb portrait_rb unity_cmb width_spb height_spb left_marg top_marg right_marg bottom_marg font_cmb font_size_spb pgmodeler-0.9.2/libpgmodeler_ui/ui/genericsqlwidget.ui000066400000000000000000000157631360462764600232100ustar00rootroot00000000000000 GenericSQLWidget 0 0 651 418 2 2 2 2 0 SQL code References 4 4 4 4 Object: 0 0 32 32 32 32 QFrame::NoFrame QFrame::Plain false Qt::AlignCenter Ref. name: The name of the reference to an object. All occurences of the reference enclosed by <strong>{}</strong> are replaced by the referenced object's name or signature in the generic SQL object's code. 0 0 22 22 22 22 Use the referenced object's signature instead of its name. For some objects like functions, casts, operators and some others the signature will include parameters types and some other information. Use signature 0 0 22 22 22 22 The referenced object's name or signature will be automatically quoted when special characters are found. Additionally, for schema qualified objects, the name of the parent schema is prepended to the referenced object's name or signature. This will avoid common SQL syntax errors or loss of semantics. Format name 0 0 22 22 22 22 Preview pgmodeler-0.9.2/libpgmodeler_ui/ui/hinttextwidget.ui000066400000000000000000000064071360462764600227160ustar00rootroot00000000000000 HintTextWidget 0 0 100 20 0 0 100 20 300 16777215 0 0 0 0 Form false 0 0 0 0 0 0 false 0 0 0 0 0 0 Qt::StrongFocus QFrame::NoFrame Qt::AutoText Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 0 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse pgmodeler-0.9.2/libpgmodeler_ui/ui/indexwidget.ui000066400000000000000000000255311360462764600221550ustar00rootroot00000000000000 IndexWidget 0 0 521 200 0 0 2 2 2 2 6 0 Attributes 4 4 4 4 6 0 0 0 0 16777215 16777215 50 false false Indexing: 0 0 127 0 127 16777215 Qt::Horizontal QSizePolicy::Fixed 40 20 Fill Factor: false 0 0 110 0 16777215 16777215 10 100 90 0 0 0 0 16777215 16777215 Options: 6 0 0 0 0 16777215 16777215 Concurrent 0 0 0 0 16777215 16777215 Unique 0 0 0 0 16777215 16777215 Fast update 0 0 Buffering 0 0 0 0 16777215 16777215 Predicate: 0 0 0 50 16777215 16777215 QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded Elements tabWidget indexing_cmb fill_factor_chk fill_factor_sb concurrent_chk unique_chk fast_update_chk predicate_txt pgmodeler-0.9.2/libpgmodeler_ui/ui/languagewidget.ui000066400000000000000000000063201360462764600226240ustar00rootroot00000000000000 LanguageWidget 0 0 337 120 0 0 2 2 2 2 6 0 0 0 0 0 0 Trusted: 0 0 0 0 Validator Func.: 0 0 0 0 Handler Func.: 0 0 0 0 Inline Func.: pgmodeler-0.9.2/libpgmodeler_ui/ui/layerswidget.ui000066400000000000000000000162571360462764600223520ustar00rootroot00000000000000 LayersWidget 0 0 448 165 Form true 0 0 0 0 0 165 QFrame::StyledPanel QFrame::Raised 4 4 4 4 false 0 0 0 0 Remove all layers Delete all :/icones/icones/clearlayers.png:/icones/icones/clearlayers.png 22 22 Shift+Del Qt::ToolButtonTextBesideIcon false true 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true Qt::Horizontal QSizePolicy::Expanding 20 20 true 0 0 0 0 Add a new layer Add :/icones/icones/addlayer.png:/icones/icones/addlayer.png 22 22 Ins Qt::ToolButtonTextBesideIcon false false 0 0 0 0 Remove the selected layer Delete :/icones/icones/dellayer.png:/icones/icones/dellayer.png 22 22 Shift+Del Qt::ToolButtonTextBesideIcon false pgmodeler-0.9.2/libpgmodeler_ui/ui/mainwindow.ui000066400000000000000000001502761360462764600220230ustar00rootroot00000000000000 MainWindow Qt::NonModal 0 0 1068 708 1000 500 true Qt::NoFocus pgModeler - PostgreSQL Database Modeler :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png Qt::LeftToRight false Qt::ToolButtonTextOnly false true true true 0 0 0 0 0 0 0 0 0 0 0 6 0 true Qt::Horizontal 5 false 0 0 640 480 false 0 0 0 0 0 true Qt::Vertical 5 false 6 Qt::Vertical 0 398 0 0 true false QTabWidget::North QTabWidget::Triangular -1 false true 0 0 true 0 0 0 0 0 Qt::Horizontal 5 false 0 0 0 0 0 0 true 0 0 0 0 0 true Qt::Vertical 5 false 0 0 270 0 0 0 270 0 true 0 0 true 0 0 0 0 0 6 3 3 0 0 Toogle the model validation widgets &Validation :/icones/icones/validation.png:/icones/icones/validation.png 22 22 Alt+V true Qt::ToolButtonTextBesideIcon false 0 0 Toggle the object finder Find objects :/icones/icones/buscar.png:/icones/icones/buscar.png 22 22 Ctrl+F true Qt::ToolButtonTextBesideIcon false 0 0 Toggle the object finder Layers :/icones/icones/layers.png:/icones/icones/layers.png 22 22 true Qt::ToolButtonTextBesideIcon false Qt::Horizontal 40 20 0 3 3 0 0 Toggle the model objects widget O&bjects :/icones/icones/tablespace.png:/icones/icones/tablespace.png 22 22 Alt+B true Qt::ToolButtonTextBesideIcon false Qt::Horizontal QSizePolicy::Fixed 6 20 0 0 Toggle the operation history widget &Operations :/icones/icones/funcao.png:/icones/icones/funcao.png 22 22 Alt+O true Qt::ToolButtonTextBesideIcon false 0 0 0 0 0 0 3 Saving temp. models 16777215 16 24 Qt::Horizontal 40 20 20 0 16777215 16777215 true 0 0 1068 29 true false &File &Edit He&lp &Show false Pl&ugins 0 0 50 false General false Qt::LeftToolBarArea 32 32 Qt::ToolButtonTextUnderIcon false LeftToolBarArea false true 0 0 0 0 16777215 16777215 Controls Qt::LeftToRight false Qt::TopToolBarArea 22 22 Qt::ToolButtonIconOnly TopToolBarArea false :/icones/icones/novo.png:/icones/icones/novo.png &New New model Ctrl+N false :/icones/icones/salvar.png:/icones/icones/salvar.png &Save Save model Ctrl+S false :/icones/icones/zoom_mais.png:/icones/icones/zoom_mais.png &Zoom in Zoom in Ctrl+= QAction::TextHeuristicRole QAction::NormalPriority false :/icones/icones/zoom_menos.png:/icones/icones/zoom_menos.png Zoo&m out Zoom - Zoom out Ctrl+- :/icones/icones/abrir.png:/icones/icones/abrir.png &Load Ctrl+O false :/icones/icones/salvar_como.png:/icones/icones/salvar_como.png Sa&ve as :/icones/icones/sair.png:/icones/icones/sair.png E&xit Exit pgModeler Ctrl+Q QAction::QuitRole true :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png &About pgModeler F4 QAction::TextHeuristicRole false :/icones/icones/imprimir.png:/icones/icones/imprimir.png &Print Print model Ctrl+P false :/icones/icones/desfazer.png:/icones/icones/desfazer.png &Undo Undo operation Ctrl+Z false :/icones/icones/refazer.png:/icones/icones/refazer.png &Redo Redo operation Ctrl+Y false :/icones/icones/exportar.png:/icones/icones/exportar.png &Export Export the current opened model in different modes Ctrl+Shift+E true true false :/icones/icones/grade.png:/icones/icones/grade.png &Show grid Show grid Ctrl+G false :/icones/icones/fechar.png:/icones/icones/fechar.png &Close Close current model Ctrl+W false :/icones/icones/zoom_normal.png:/icones/icones/zoom_normal.png &Normal zoom Ctrl+0 true false false :/icones/icones/aligntogrid.png:/icones/icones/aligntogrid.png &Align to grid Align objects position to grid Ctrl+H true true false :/icones/icones/exibirlimpag.png:/icones/icones/exibirlimpag.png Show &delimiters Show the page delimiters Ctrl+L :/icones/icones/config.png:/icones/icones/config.png &Settings Edit pgModeler settings F12 false Save all true false :/icones/icones/visaogeral.png:/icones/icones/visaogeral.png &Overview Show the model overview F10 :/icones/icones/help.png:/icones/icones/help.png &Support Access the support page F1 :/icones/icones/novoobjeto.png:/icones/icones/novoobjeto.png New New object :/icones/icones/plugins.png:/icones/icones/plugins.png Plugins Access the list of loaded plugins :/icones/icones/loadrecent.png:/icones/icones/loadrecent.png &Recent Models Load recently opened model true :/icones/icones/import.png:/icones/icones/import.png &Import Import existing database to new model (reverse engineering) Ctrl+Shift+I :/icones/icones/last_session.png:/icones/icones/last_session.png Rest&ore Session :/icones/icones/fixobject.png:/icones/icones/fixobject.png &Fix a model true :/icones/icones/atualizar.png:/icones/icones/atualizar.png New version found! Update for the current version is available on project's site :/icones/icones/atualizar.png:/icones/icones/atualizar.png &Check for update :/icones/icones/mainmenu.png:/icones/icones/mainmenu.png action_main_menu Main menu Show expanded Expands the main menu bar in classical mode Ctrl+Shift+S Hide main menu Hides the main menu bar and put the action on a separated action Ctrl+Shift+H true :/icones/icones/diff.png:/icones/icones/diff.png &Diff Determine the changes between model/database and another database Ctrl+Shift+D true true :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png Welcome Welcome screen Shift+W true false :/icones/icones/design.png:/icones/icones/design.png Design Design database models Shift+D true :/icones/icones/managedb.png:/icones/icones/managedb.png Manage Manage existent databases Shift+M :/icones/icones/bugreport.png:/icones/icones/bugreport.png &Bug report Report a bug true :/icones/icones/donate.png:/icones/icones/donate.png Donate Help pgModeler by donating! false :/icones/icones/objmetadata.png:/icones/icones/objmetadata.png Objects me&tadata Objects metadata false :/icones/icones/arrangetables.png:/icones/icones/arrangetables.png Arrange objects Rearrange objects over the canvas true false :/icones/icones/compactview.png:/icones/icones/compactview.png Compact view Toggle the compact view on the model(s) :/icones/icones/moreactions.png:/icones/icones/moreactions.png More Addition action over the model models_tbw pgmodeler-0.9.2/libpgmodeler_ui/ui/messagebox.ui000066400000000000000000000440271360462764600220000ustar00rootroot00000000000000 Messagebox Qt::ApplicationModal 0 0 500 244 0 0 500 175 Dialog :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 2 2 2 2 4 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 424 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 0 40 40 40 40 Qt::AlignCenter true 0 0 0 90 16777215 16777215 false false msg Qt::RichText true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true 4 true Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse Qt::Vertical 20 84 Qt::Horizontal QSizePolicy::Fixed 5 20 4 4 4 0 0 1 1 16 QAbstractItemView::NoEditTriggers true QAbstractItemView::NoSelection QAbstractItemView::SelectItems 20 20 15 false false false 100 21 Exceptions 2 2 2 2 DejaVu Sans Mono QTextEdit::NoWrap false 0 0 0 0 4 4 Qt::Horizontal 415 24 0 0 Show raw text errors or information. :/icones/icones/codigofonte.png:/icones/icones/codigofonte.png 22 22 true 0 0 Show/hide exceptions stack. ... :/icones/icones/refazer.png:/icones/icones/refazer.png 22 22 true 0 0 :/imagens/imagens/pgmodeler_name.png 0 0 0 0 0 0 90 32 &Yes 22 22 true false 0 0 90 32 &No 22 22 0 0 90 32 Cancel 22 22 Qt::Horizontal 40 20 show_raw_info_tb show_errors_tb yes_ok_btn no_btn cancel_btn raw_info_txt exceptions_trw pgmodeler-0.9.2/libpgmodeler_ui/ui/metadatahandlingform.ui000066400000000000000000001425011360462764600240100ustar00rootroot00000000000000 MetadataHandlingForm 0 0 727 609 Handle metadata :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 2 2 2 2 0 0 :/imagens/imagens/pgmodeler_name.png QLayout::SetDefaultConstraint 2 Qt::Horizontal QSizePolicy::Expanding 200 27 false 0 0 90 35 16777215 16777215 &Apply :/icones/icones/confirmar.png:/icones/icones/confirmar.png 22 22 true 0 0 90 35 16777215 16777215 &Cancel :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 false QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 0 Settings 4 4 4 4 Extract from: 0 0 0 48 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 0 0 50 false false false false true Loading a metadata file to the current model is an irreversible operation so be sure to specify a backup file before proceed. true 0 0 Options 4 4 4 10 0 0 Handles the objects' aliases in the metadata file. Only for graphical objects and table's children objects. Objects' aliases true 0 0 22 22 22 22 0 0 Handles the objects' positioning in the metadata file. Objects' positioning true 0 0 22 22 22 22 Qt::Vertical 20 40 0 0 Handles the objects' custom colors in the metadata file. Currently available only for relationships and schemas. Custom object's colors true 0 0 22 22 22 22 0 0 Handles the objects' protection status in the metadata file. Objects' protection status true 0 0 22 22 22 22 0 0 Handles the objects' SQL disabled status in the metadata file. Objects' SQL disabled status true 0 0 22 22 22 22 0 0 Handles the following database model attributes in the metadata file: author, zoom factor, last position and default objects. Database model metadata true 0 0 22 22 22 22 0 0 Handles the objects' fade out status in the metadata file. Objects' fade out status true 0 0 22 22 22 22 0 0 Save tags to the output file when extracting metadata. When loading the file, the tags are recreated and duplicated ones are ignored. Tag objects true 0 0 22 22 22 22 0 0 Save textboxes to the output file when extracting metadata. When loading the file, the textboxes are recreated and duplicated ones are ignored. Textbox objects true 0 0 22 22 22 22 0 0 Handles the objects' custom SQL commands in the metadata file. Custom SQL commands true 0 0 22 22 22 22 0 0 Handles the tables' and views' collapsing mode in the metadata file. Tables and views collpsing mode true 0 0 22 22 22 22 0 0 Save generic SQL objects to the output file when extracting metadata. When loading the file, the objects are recreated and duplicated ones are ignored. Generic SQL objects true 0 0 22 22 22 22 0 0 6 0 10 0 0 Qt::Horizontal 252 20 Select all Clear all Qt::Horizontal 40 20 Backup file: true true Select file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 Operation: 0 0 Extracts the objects' metadata from the loaded models and apply to the current focused model. A backup file can be specified to where the focused model's current metadata will be saved. &Extract and restore true 0 0 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 10 20 0 0 Extracts the objects metadata from one of the loaded models saving the info to a backup file. Extract &only false 0 0 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 10 20 0 0 Reads the objects' metadata from a previously saved backup file and apply to the current model. &Restore a backup file 0 0 22 22 22 22 Qt::Horizontal 40 20 Apply to: true false Output 4 4 4 4 0 0 16777215 65 0 0 0 0 6 0 0 20 20 20 20 true 0 0 0 Progress label... 0 0 Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustToContents QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed true QAbstractItemView::SingleSelection 18 18 20 true false pgmodeler-0.9.2/libpgmodeler_ui/ui/modeldatabasediffform.ui000066400000000000000000003143251360462764600241460ustar00rootroot00000000000000 ModelDatabaseDiffForm Qt::ApplicationModal 0 0 680 621 0 0 680 570 16777215 16777215 Diff tool :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 4 4 4 4 6 true 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 0 Settings 4 4 4 4 Qt::Horizontal 5 false 0 0 0 0 Presets false false 4 4 4 4 6 0 0 QComboBox::InsertAtBottom QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 true Add new preset :/icones/icones/novo.png:/icones/icones/novo.png 22 22 Ins true Edit preset name :/icones/icones/editar.png:/icones/icones/editar.png 22 22 Ctrl+E true Save preset :/icones/icones/salvar.png:/icones/icones/salvar.png 22 22 Ctrl+S true Cancel operation on the preset :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 Esc true Delete the selected preset :/icones/icones/excluir.png:/icones/icones/excluir.png 22 22 Del true Restore the default presets :/icones/icones/atualizar.png:/icones/icones/atualizar.png 22 22 Ctrl+R 0 0 0 0 Input false false 4 4 4 4 0 0 0 Current model: true 0 0 75 false true (model) Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 0 0 Database: false 50 30 20 0 0 0 false Connection: false 0 0 QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 false 0 0 Database: -1 false 0 0 QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 0 0 0 0 Compare to 4 4 4 4 Connection: 0 0 QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 false 0 0 Database: -1 false 0 0 QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 0 0 Diff mode 4 4 4 4 Override the PostgreSQL version when generating the diff code. The default is to use the same version as the input database (detected automatically). Use PostgreSQL: false 0 0 22 22 22 22 Qt::Horizontal 40 20 0 0 125 0 Compares the model and the input database storing the diff in a SQL file for later usage. Store in S&QL file true 0 0 22 22 22 22 Qt::Horizontal 40 20 true 0 0 20 0 0 0 true 0 0 0 0 File: true 0 0 Select output file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 true false false true true 0 0 125 0 Compares the model and the input database generating a diff and applying it directly to the latter. <strong>WARNING:</strong> this mode causes irreversible changes on the database and in case of failure the original structure is not restored, so make sure to have a backup before proceed. Appl&y on server false 0 0 22 22 22 22 Qt::Horizontal 40 20 Qt::Vertical 0 0 QTabWidget::South 0 Diff 4 4 4 4 Database cluster level objects like roles and tablespaces will not be dropped. Keep cluster objects true 0 0 22 22 22 22 Permissions already set on database objects will be kept. The ones configured on the model will be applied to the database. Keep object's permissions true 0 0 22 22 22 22 Avoid the generation of DROP commands for objects that exists in database but not in the model. This is useful when diff a partial model against the complete database. Do not drop missing objects false 0 0 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 12 21 false 0 0 Force the generation of DROP commands for columns and constraints that exist in database but not in the model. This is useful when diff a partial model against the complete database and the user needs to drop columns and constraint but preserve the rest of the objects. Drop missing columns and constraints false 0 0 22 22 22 22 No command to rename the destination database will be generated even the model's name differ from database name. Preserve database name true 0 0 22 22 22 22 true For DROP command, the objects that depends on an object to be dropped will be deleted as well. For TRUNCATE command, tables that are linked to a table to be truncated will be truncate too. <strong>NOTE:</strong> this option can affect more objects than listed in the output or diff preview. Drop or truncate in cascade mode true 0 0 22 22 22 22 0 0 Clears the data of all tables which will have columns modified. This is useful to avoid errors related to type casting. <strong>WARNING:</strong> DO NOT use this option on production servers and always make a backup before use it. Truncate tables before alter columns 0 0 22 22 22 22 0 0 Serial columns are converted to integer and having the default value changed to <strong>nextval(sequence)</strong> function call. By default, a new sequence is created for each serial column but checking this option sequences matching the name on column's default value will be reused and will not be dropped. Reuse sequences on serial columns true 0 0 22 22 22 22 false 0 0 Recreate only unmodifiable objects false 0 0 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 15 20 true Instead of use an ALTER command to modify certain kind of objects a DROP and CREATE will be used in order to do a full modification. This option does not affects the database object. Force recreation of objects true false 0 0 22 22 22 22 Qt::Vertical 20 40 Import && Export 4 4 4 4 Import 4 4 4 4 0 0 Import system (built-in) objects. Use this if the import step is returning errors related to missing objects. Import system objects 0 0 22 22 22 22 0 0 Import objects created by extensions. Use this if the import step is returning errors even importing built in ones. Import extension objects 0 0 22 22 22 22 0 0 Ignores as many as possible errors on import step. This option generates an incomplete diff. Ignore import errors 0 0 22 22 22 22 Export 4 4 4 4 0 0 Ignores errors generated by duplicated objects when exporting the diff to database. Ignore duplicity errors 0 0 22 22 22 22 0 0 22 22 22 22 true 0 0 This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes false true Qt::Vertical 20 57 Output 4 4 4 4 0 0 Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustToContents QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed true QAbstractItemView::SingleSelection 20 20 20 false false false true 100 25 true 0 0 Changes: 0 0 0 0 0 0 0 0 0 0 20 20 20 20 true false 0 0 0 30 Cancel :/icones/icones/msgbox_erro.png:/icones/icones/msgbox_erro.png 22 22 Qt::ToolButtonTextBesideIcon 0 0 0 0 20 20 20 20 true 0 0 Progress label... 0 0 Step label... 0 0 0 48 QFrame::NoFrame QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 50 false false false false true <html><head/><body><p>Objects marked with an <span style=" font-weight:600;">ALTER</span> may not be effectively changed unless that the differences detected are in attributes that can be modified through ALTER commands otherwise no operationwill be performed or, if the force recreation is checked, the object will be dropped and created again.</p></body></html> true 0 0 0 0 0 0 0 0 0 0 50 30 Objects to be created 0 :/icones/icones/criado.png:/icones/icones/criado.png 22 22 true true Qt::ToolButtonTextBesideIcon 0 0 50 30 Objects to be dropped 0 :/icones/icones/removido.png:/icones/icones/removido.png 22 22 true true Qt::ToolButtonTextBesideIcon 0 0 50 30 Possible objects to be changed 0 :/icones/icones/modificado.png:/icones/icones/modificado.png 22 22 true true Qt::ToolButtonTextBesideIcon 0 0 50 30 Ignored objects (system ones or with sql disabled) 0 :/icones/icones/ignore.png:/icones/icones/ignore.png 22 22 true true Qt::ToolButtonTextBesideIcon Qt::Horizontal 40 20 Diff Preview 4 4 4 4 Qt::Horizontal 40 20 0 0 0 30 16777215 16777215 &Apply diff :/icones/icones/diff.png:/icones/icones/diff.png 22 22 false 0 0 Qt::Horizontal 40 20 0 0 0 30 16777215 16777215 Loads the generated diff code in the destination server for manual applying. Open in SQL Tool :/icones/icones/codigosql.png:/icones/icones/codigosql.png 22 22 false false 0 0 0 :/imagens/imagens/pgmodeler_name.png Qt::Horizontal 246 20 0 0 90 35 16777215 16777215 &Generate :/icones/icones/diff.png:/icones/icones/diff.png 22 22 true Qt::Horizontal QSizePolicy::Fixed 6 20 0 0 90 35 16777215 16777215 &Close :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 false file_edt select_file_tb cancel_btn generate_btn close_btn pgmodeler-0.9.2/libpgmodeler_ui/ui/modelexportform.ui000066400000000000000000002165101360462764600230670ustar00rootroot00000000000000 ModelExportForm Qt::ApplicationModal 0 0 720 649 0 0 660 550 16777215 16777215 Export model :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 4 4 4 4 true 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 0 Settings 4 4 4 4 0 0 Database server false 4 4 4 4 0 0 4 4 0 4 Qt::Vertical QSizePolicy::Preferred 20 13 true 0 0 30 60 30 60 :/imagens/imagens/model2sgdb.png true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Qt::Vertical QSizePolicy::Preferred 20 18 true 0 0 0 0 Connection: true 0 0 QComboBox::InsertAlphabetically QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 true 0 0 pgModeler ignores errors generated by duplicated objects and creates only that ones which does not exists in the database. This option may be used when an object was created after a previous model export. Ignore object duplicity 0 0 22 22 22 22 true 0 0 PostgreSQL version in which the SQL code should be generated. It is recommended to select this option only when the version of the DBMS, somehow, is not identifiable or if you need to generate a specific version of SQL code for test purposes. PostgreSQL: false false 0 0 22 22 22 22 false 0 0 0 0 16777215 16777215 QComboBox::InsertAtBottom Qt::Horizontal 40 20 0 0 22 22 22 22 true 0 0 This advanced option causes pgModeler to ignore extra errors by their numeric codes. These errors must be informed in the input below and separeted by space. For the complete list of error codes check the PostgreSQL docs, section <strong> Appendix A. PostgreSQL Error Codes</strong>. <strong>WARNING:</strong> use this option with extreme care since it can interfere in final export result. Ignore error codes false true true 0 0 If <strong>DB</strong> is checked pgModeler will destroy the database if already exists on the server. When <strong>Objects</strong> is checked pgModeler will execute the DROP command attached to SQL-enabled objects. <strong>WARNING:</strong> this option leads to data loss so make sure to have a backup before exporting. Drop: false DB true false Ob&jects 0 0 22 22 22 22 pgModeler will destroy the database if already exists on the server. Make sure to have a backup before use this option because all data will be lost. Qt::Horizontal 40 20 true 0 0 true false SQL file 4 4 4 4 0 0 false false true 0 0 4 4 0 4 true 0 0 0 0 File: true false true false true 0 0 Select target file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 0 0 false PostgreSQL: true 0 0 16777215 16777215 PostgreSQL version in which the SQL code should be generated QComboBox::InsertAtBottom Qt::Horizontal 158 20 true 0 0 30 60 30 60 :/imagens/imagens/model2sql.png true 0 0 Graphics file 4 4 4 4 true 0 0 0 0 4 4 0 4 Qt::Vertical QSizePolicy::Preferred 20 18 true 0 0 30 60 30 60 :/imagens/imagens/model2png.png true Qt::Vertical QSizePolicy::Preferred 20 28 true 0 0 0 0 Type: I&mage (PNG) true 0 0 &Vectorial (SVG) true 0 0 0 0 File: true false true false true 0 0 Select target file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 true 0 0 0 0 false Zoom: true 0 0 true 0 0 Show grid true 0 0 Show delimiters true 0 0 Exporting the model page by page will generate files with a <strong>_p[n]</strong> suffix where <strong>n</strong> is the page id. Check if the current user has write permission on output folder. Page by page 0 0 22 22 22 22 Qt::Horizontal 40 20 0 0 false false 0 0 Data dictionary 4 4 4 4 true 0 0 0 0 4 4 0 4 0 0 22 22 22 22 <strong>Standalone:</strong> pgModeler will generate a single HTML file containing the data dictionaries of all tables in the database model. <strong>Splitted:</strong> the data dictionaries are generated in separated files inside the selected directory. In this mode the files are named <em>schema.table.html</em>. Qt::Horizontal 40 20 0 0 Splitted 0 0 22 22 22 22 pgModeler will generate an index to help navigate through the data dictionary. If splitted mode is set then a separated file named <em>index.html</em> will be saved into the destination folder. true 0 0 0 0 Mode: true 0 0 30 60 30 60 :/imagens/imagens/model2datadict.png true true 0 0 0 0 Output: true false true false true 0 0 Select target file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 true 0 0 Include index true Standalone true Qt::Horizontal QSizePolicy::Fixed 5 20 0 0 false false Qt::Vertical 20 40 Output 4 4 4 4 0 0 16777215 65 0 0 0 0 6 0 0 20 20 20 20 true 0 false Cancel :/icones/icones/msgbox_erro.png:/icones/icones/msgbox_erro.png 20 20 Qt::ToolButtonTextBesideIcon 0 0 Progress label... 0 0 Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustToContents QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed true QAbstractItemView::SingleSelection 20 20 20 true false 25 0 0 :/imagens/imagens/pgmodeler_name.png Qt::Horizontal 246 20 0 0 90 32 16777215 16777215 &Export :/icones/icones/exportar.png:/icones/icones/exportar.png 20 20 true 0 0 90 32 16777215 16777215 &Close :/icones/icones/fechar1.png:/icones/icones/fechar1.png 20 20 false connections_cmb pgsqlvers_chk pgsqlvers1_cmb ignore_dup_chk drop_chk file_edt select_file_tb pgsqlvers_cmb image_edt select_img_tb show_grid_chk show_delim_chk page_by_page_chk cancel_btn export_btn close_btn pgmodeler-0.9.2/libpgmodeler_ui/ui/modelfixform.ui000066400000000000000000000552051360462764600223360ustar00rootroot00000000000000 ModelFixForm Qt::ApplicationModal 0 0 605 499 0 0 500 390 16777215 16777215 Model file fix :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 2 2 2 2 true 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 Input file: 1 100 0 0 Load fixed model when finish true 0 0 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 0 0 0 128 128 128 128 128 128 255 255 255 Monospace Qt::ScrollBarAsNeeded false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Monospace'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:9pt;">Waiting process to start...</span></p></body></html> false Qt::TextSelectableByMouse true true Select output file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 0 48 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 50 false false false false true <html><head/><body><p>[pgmodeler-cli not found error]</p></body></html> true 0 0 0 48 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 0 0 50 false false false false true In some cases the fix process will fail to restore all objects within the model demanding manual fixes by changing the file on a text editor. <strong>NOTE:</strong> relationships may lost their graphical configuration like custom points and line color. true 0 0 pgmodeler-cli: 0 true true Browse for pgmodeler-cli tool ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 170 0 0 170 0 0 128 128 128 false The specified file is not the pgModeler command line tool (pgmodeler-cli). 0 0 Output file: Fix tries: true true Select input file ... :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 :/imagens/imagens/pgmodeler_name.png Qt::Horizontal 186 27 false 0 0 90 32 16777215 16777215 &Fix :/icones/icones/fixobject.png:/icones/icones/fixobject.png 20 20 true 0 0 90 32 16777215 16777215 &Close :/icones/icones/fechar1.png:/icones/icones/fechar1.png 20 20 false pgmodeler-0.9.2/libpgmodeler_ui/ui/modelnavigationwidget.ui000066400000000000000000000114041360462764600242200ustar00rootroot00000000000000 ModelNavigationWidget false 0 0 328 29 0 0 Form 4 0 0 0 0 false 0 0 0 0 Previous model :/icones/icones/anterior.png:/icones/icones/anterior.png 22 22 Ctrl+Left true false 0 0 0 0 Next model :/icones/icones/proximo.png:/icones/icones/proximo.png 22 22 Ctrl+Right true 0 0 200 0 16777215 16777215 0 0 16777215 16777215 Close model ... :/icones/icones/fechar.png:/icones/icones/fechar.png 22 22 Alt+C true pgmodeler-0.9.2/libpgmodeler_ui/ui/modelobjectswidget.ui000066400000000000000000000721531360462764600235220ustar00rootroot00000000000000 ModelObjectsWidget true 0 0 489 580 0 0 260 300 524287 524287 Model Objects :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png false 2 2 2 4 0 0 0 0 0 Qt::Vertical true 0 0 0 true 0 0 0 0 0 true 0 170 255 0 170 255 0 170 255 QFrame::Sunken Qt::ScrollBarAlwaysOff true QAbstractItemView::NoEditTriggers true true QAbstractItemView::SingleSelection QAbstractItemView::SelectItems 20 20 20 false true true false true false true false 1 50 50 false 1 0 0 0 0 0 true QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows 20 20 Qt::SolidLine true true 96 true true false false 20 false false false ID AlignLeading|AlignVCenter :/icones/icones/uid.png:/icones/icones/uid.png Object AlignLeading|AlignVCenter :/icones/icones/table.png:/icones/icones/table.png Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Parent Object AlignLeading|AlignVCenter :/icones/icones/schema.png:/icones/icones/schema.png Parent Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png 0 16777215 16777215 Visible object types false false 4 4 4 4 0 0 16777215 16777215 QAbstractItemView::NoEditTriggers true -1 true Qt::Horizontal 58 20 0 0 Select All 0 0 Clear All Qt::Horizontal 58 20 9 0 2 2 2 0 9 false Model objects Qt::Horizontal 156 5 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true 0 0 0 0 0 0 true 0 0 Filter: true true By ID Qt::Horizontal QSizePolicy::Expanding 118 20 0 0 0 0 Select :/icones/icones/confirmar.png:/icones/icones/confirmar.png 22 22 Return 0 0 0 0 Cancel :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 Esc 0 0 0 0 Tree view ... :/icones/icones/visaoarvore.png:/icones/icones/visaoarvore.png 22 22 true true 0 0 0 0 List view ... :/icones/icones/visaolista.png:/icones/icones/visaolista.png 22 22 true 0 0 0 0 Objects view configuration ... :/icones/icones/filter.png:/icones/icones/filter.png 22 22 true false 0 0 0 0 Expands all items ... :/icones/icones/adicionar.png:/icones/icones/adicionar.png 22 22 false 0 0 0 0 Collapses all items ... :/icones/icones/remover.png:/icones/icones/remover.png 22 22 false objectstree_tw visibleobjects_lst select_all_tb clear_all_tb select_tb cancel_tb tree_view_tb list_view_tb options_tb expand_all_tb collapse_all_tb objectslist_tbw hide_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/modeloverviewwidget.ui000066400000000000000000000111611360462764600237270ustar00rootroot00000000000000 ModelOverviewWidget Qt::NonModal 0 0 569 250 0 0 0 0 16777215 16777215 true Qt::ActionsContextMenu Model overview :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 1.000000000000000 false border: 1px solid #707070; 0 0 0 0 0 0 0 0 0 16777215 16777215 true false QFrame::NoFrame QFrame::Plain 1 0 0 0 60 60 16777215 16777215 ArrowCursor Qt::NoContextMenu border-color:rgba(2, 61, 134,70); background-color: rgba(2, 61, 134,70); QFrame::StyledPanel 2 0 0 0 141 61 QFrame::NoFrame Qt::AlignCenter label window_frm pgmodeler-0.9.2/libpgmodeler_ui/ui/modelrestorationform.ui000066400000000000000000000302511360462764600241130ustar00rootroot00000000000000 ModelRestorationForm Qt::ApplicationModal 0 0 500 300 0 0 500 300 16777215 16777215 Model restoration :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 2 2 2 2 false 0 0 90 30 16777215 16777215 &Restore :/icones/icones/restaurarobjeto.png:/icones/icones/restaurarobjeto.png 22 22 true 0 0 :/imagens/imagens/pgmodeler_name.png true 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 0 48 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 50 false false false true pgModeler was not closed properly in a previous execution and some models were still being edited. Click <strong>Restore</strong> to reopen the models or <strong>Cancel</strong> to abort the restoration. true 2 0 0 pgModeler will try to recover the selected models but will not destroy them in case of loading failure. This option serves as a last resort in order to try to recover the database model. Temporary models will last until the application is closed so the user must try to manually recover the files before exit pgModeler. Keep temporary models in case of restoration failure true 0 0 22 22 22 22 QAbstractItemView::NoEditTriggers true QAbstractItemView::MultiSelection QAbstractItemView::SelectRows true false Database AlignLeading|AlignVCenter :/icones/icones/database.png:/icones/icones/database.png File AlignLeading|AlignVCenter :/icones/icones/codigofonte.png:/icones/icones/codigofonte.png Modified AlignLeading|AlignVCenter :/icones/icones/validade.png:/icones/icones/validade.png Size AlignLeading|AlignVCenter 0 0 90 30 16777215 16777215 &Cancel :/icones/icones/msgbox_erro.png:/icones/icones/msgbox_erro.png 22 22 false Qt::Horizontal 186 27 pgmodeler-0.9.2/libpgmodeler_ui/ui/modelvalidationwidget.ui000066400000000000000000000556041360462764600242250ustar00rootroot00000000000000 ModelValidationWidget 0 0 990 282 0 0 0 230 500 0 Form 4 4 4 4 0 0 0 30 Va&lidate :/icones/icones/validation.png:/icones/icones/validation.png 20 20 Qt::ToolButtonTextBesideIcon true 0 0 0 30 Try to apply a fix on the selected validation info. Options :/icones/icones/config.png:/icones/icones/config.png 20 20 true Qt::ToolButtonTextBesideIcon false 0 30 Clear validation results Clear :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 20 20 Qt::ToolButtonTextBesideIcon 0 0 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 20 20 0 0 Enables the validation of SQL code in DBMS. This process requires the use of a pre-configured connection. SQL validation will occur only in the last step (when all objects were validated) or when there are no warnings. SQL Validation: true true 0 0 0 0 200 16777215 Connection to be used in the SQL validation QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 0 0 22 22 22 22 Qt::Horizontal 40 20 true 0 0 120 0 PostgreSQL version QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 0 0 pgModeler will generate unique and temporary names for database, role and tablespace objects. This option avoids object duplication errors when running the SQL validation. Use unique temporary names for cluster level objects false 0 30 Cancel the SQL validation in progress. Cancel :/icones/icones/msgbox_erro.png:/icones/icones/msgbox_erro.png 20 20 Esc Qt::ToolButtonTextBesideIcon QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows 20 20 20 true false Qt::Horizontal 405 17 0 0 0 0 0 0 3 10 0 0 22 22 22 22 Warnings: does not prevents model to be saved. Qt::AutoText :/icones/icones/msgbox_alerta.png true 0 0 0 0 0 0 0 0 50 false 3 10 0 0 22 22 22 22 Errors: model will not be saved while there are validation errors. :/icones/icones/msgbox_erro.png true 0 0 0 0 0 0 0 20 20 20 20 true 0 0 5 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true false 0 0 0 30 Try to resolve the reported issues. Apply fixes :/icones/icones/fixobject.png:/icones/icones/fixobject.png 20 20 Ctrl+S Qt::ToolButtonTextBesideIcon Qt::NoArrow 0 30 Change the creation order for two objects by swapping their ids Swap ids :/icones/icones/swapobjs.png:/icones/icones/swapobjs.png 20 20 Qt::ToolButtonTextBesideIcon validate_btn fix_btn clear_btn options_btn cancel_btn sql_validation_chk connections_cmb version_cmb output_trw hide_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/newobjectoverlaywidget.ui000066400000000000000000002213441360462764600244300ustar00rootroot00000000000000 NewObjectOverlayWidget 0 0 422 934 0 0 8 75 true true Form 1.000000000000000 false 0 0 0 0 0 0 0 QFrame::StyledPanel QFrame::Sunken 4 4 4 4 4 Database objects 4 4 4 4 0 0 0 0 0 0 6 0 0 95 50 50 false Qt::NoFocus Generic SQL :/icones/icones/genericsql.png:/icones/icones/genericsql.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Extension :/icones/icones/extension.png:/icones/icones/extension.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Data Wrapper :/icones/icones/foreigndatawrapper.png:/icones/icones/foreigndatawrapper.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Permissions :/icones/icones/permission.png:/icones/icones/permission.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Role :/icones/icones/role.png:/icones/icones/role.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Server :/icones/icones/foreignserver.png:/icones/icones/foreignserver.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Schema :/icones/icones/schema.png:/icones/icones/schema.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Event Trigger :/icones/icones/eventtrigger.png:/icones/icones/eventtrigger.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Language :/icones/icones/language.png:/icones/icones/language.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Cast :/icones/icones/cast.png:/icones/icones/cast.png 32 32 A QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Tablespace :/icones/icones/tablespace.png:/icones/icones/tablespace.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Tag :/icones/icones/tag.png:/icones/icones/tag.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Textbox :/icones/icones/textbox.png:/icones/icones/textbox.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus User mapping :/icones/icones/usermapping.png:/icones/icones/usermapping.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon Schema objects 4 4 4 4 0 0 0 0 0 0 6 0 0 95 50 50 false Qt::NoFocus Conversion :/icones/icones/conversion.png:/icones/icones/conversion.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Collation :/icones/icones/collation.png:/icones/icones/collation.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Domain :/icones/icones/domain.png:/icones/icones/domain.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Aggregate :/icones/icones/aggregate.png:/icones/icones/aggregate.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::StrongFocus Type :/icones/icones/usertype.png:/icones/icones/usertype.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Table :/icones/icones/table.png:/icones/icones/table.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Sequence :/icones/icones/sequence.png:/icones/icones/sequence.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus View :/icones/icones/view.png:/icones/icones/view.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Op. Family :/icones/icones/opfamily.png:/icones/icones/opfamily.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Op. Class :/icones/icones/opclass.png:/icones/icones/opclass.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Operator :/icones/icones/operator.png:/icones/icones/operator.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Foreign Table :/icones/icones/foreigntable.png:/icones/icones/foreigntable.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Function :/icones/icones/function.png:/icones/icones/function.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon Table objects 4 4 4 4 0 0 0 0 0 0 6 0 0 95 50 50 false Qt::NoFocus Constraint :/icones/icones/constraint.png:/icones/icones/constraint.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Column :/icones/icones/column.png:/icones/icones/column.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Permissions :/icones/icones/permission.png:/icones/icones/permission.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Index :/icones/icones/index.png:/icones/icones/index.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Rule :/icones/icones/rule.png:/icones/icones/rule.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Trigger :/icones/icones/trigger.png:/icones/icones/trigger.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Policy :/icones/icones/policy.png:/icones/icones/policy.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon Relationships 4 4 4 4 0 0 0 0 0 0 6 0 0 95 50 50 false Qt::NoFocus Many-to-many :/icones/icones/relationshipnn.png:/icones/icones/relationshipnn.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus One-to-many :/icones/icones/relationship1n.png:/icones/icones/relationship1n.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus One-to-one :/icones/icones/relationship11.png:/icones/icones/relationship11.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Inheritance :/icones/icones/relationshipgen.png:/icones/icones/relationshipgen.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Copy :/icones/icones/relationshipdep.png:/icones/icones/relationshipdep.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon 0 0 95 50 50 false Qt::NoFocus Partitioning :/icones/icones/relationshippart.png:/icones/icones/relationshippart.png 32 32 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon Qt::Horizontal 40 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/objectdepsrefswidget.ui000066400000000000000000000343261360462764600240520ustar00rootroot00000000000000 ObjectDepsRefsWidget 0 0 702 359 Object's dependencies & references :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 0 0 0 0 6 0 22 22 Dependencies 4 4 4 4 6 true QAbstractItemView::NoEditTriggers true QAbstractItemView::NoSelection QAbstractItemView::SelectRows Qt::SolidLine true true 96 30 true true false false 26 false 25 false false ID AlignLeading|AlignVCenter :/icones/icones/uid.png:/icones/icones/uid.png Object AlignLeading|AlignVCenter :/icones/icones/table.png:/icones/icones/table.png Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Parent Object AlignLeading|AlignVCenter :/icones/icones/schema.png:/icones/icones/schema.png Parent Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Exclude indirect dependencies true References 4 4 4 4 6 true QAbstractItemView::NoEditTriggers true QAbstractItemView::NoSelection QAbstractItemView::SelectRows Qt::SolidLine true true 96 30 true true false false 26 false 25 false false ID AlignLeading|AlignVCenter :/icones/icones/uid.png:/icones/icones/uid.png Object AlignLeading|AlignVCenter :/icones/icones/table.png:/icones/icones/table.png Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Parent Object AlignLeading|AlignVCenter :/icones/icones/schema.png:/icones/icones/schema.png Parent Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Include indirect references 0 0 0 48 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 50 false false false true This object does not exists anymore. The dependencies and references listing are disabled. true pgmodeler-0.9.2/libpgmodeler_ui/ui/objectfinderwidget.ui000066400000000000000000000547201360462764600235060ustar00rootroot00000000000000 ObjectFinderWidget 0 0 650 316 0 230 650 0 Form 4 4 4 4 true 0 0 0 0 Defines the search filter Filter :/icones/icones/filter.png:/icones/icones/filter.png 20 20 true Qt::ToolButtonTextBesideIcon 0 0 0 0 true 0 0 50 0 Pattern: false 0 0 0 0 (Un)selects the graphical objects in the results grid Select :/icones/icones/selmovobjeto.png:/icones/icones/selmovobjeto.png 20 20 false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon 0 0 ... 10 false 0 0 0 0 Clears the search results Clear :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 20 20 Qt::ToolButtonTextBesideIcon 0 0 0 0 Find :/icones/icones/objselect.png:/icones/icones/objselect.png 20 20 Qt::ToolButtonTextBesideIcon 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true false 0 0 0 0 Fades outs all the graphical objects in the results grid (or those not listed). The current fade in/out state of all objects is modified. Fade out :/icones/icones/fadeout.png:/icones/icones/fadeout.png 20 20 false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon Qt::Vertical false 0 0 16777215 16777215 QFrame::StyledPanel QFrame::Raised 4 4 4 4 4 Qt::Horizontal 40 20 0 0 Regular Expression 0 0 Case Sensitive 0 0 Exact Match 2 2 2 4 6 8 Qt::Horizontal QSizePolicy::Minimum 40 20 0 0 0 0 Select All 20 20 true 0 0 0 0 Clear All 20 20 false Qt::ToolButtonTextBesideIcon Qt::Horizontal QSizePolicy::Minimum 40 20 0 0 300 0 300 16777215 QAbstractItemView::NoEditTriggers true true QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows Qt::SolidLine true true 96 30 true true false false 26 false 25 false false ID AlignLeading|AlignVCenter :/icones/icones/uid.png:/icones/icones/uid.png Object AlignLeading|AlignVCenter :/icones/icones/table.png:/icones/icones/table.png Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Parent Object AlignLeading|AlignVCenter :/icones/icones/schema.png:/icones/icones/schema.png Parent Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Comment AlignLeading|AlignVCenter Qt::Horizontal QSizePolicy::Expanding 40 20 The attribute of the objects in which the search will occur pattern_edt find_btn filter_btn clear_res_btn select_btn obj_types_lst regexp_chk exact_match_chk case_sensitive_chk select_all_btn clear_all_btn result_tbw hide_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/objectrenamewidget.ui000066400000000000000000000203721360462764600235020ustar00rootroot00000000000000 ObjectRenameWidget 0 0 303 81 0 0 300 0 Form false true 0 0 0 0 0 0 0 0 0 16777215 16777215 QFrame::StyledPanel QFrame::Raised 4 4 4 4 6 32 32 32 32 QFrame::NoFrame QFrame::Plain false Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Qt::Horizontal QSizePolicy::Fixed 32 15 0 0 75 true true .... 0 0 true to: 0 0 true Rename Qt::Horizontal QSizePolicy::Fixed 30 15 6 0 30 9 true 0 0 Rename :/icones/icones/confirmar.png:/icones/icones/confirmar.png 22 22 0 0 Cancel :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 pgmodeler-0.9.2/libpgmodeler_ui/ui/objectselectorwidget.ui000066400000000000000000000106021360462764600240460ustar00rootroot00000000000000 ObjectSelectorWidget 0 0 277 192 0 0 0 0 16777215 16777215 Qt::TabFocus Form 0 0 0 0 4 false 0 0 0 0 Qt::WheelFocus Clear field :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 22 22 0 0 0 0 Qt::WheelFocus Select Object :/icones/icones/objselect.png:/icones/icones/objselect.png 22 22 0 0 0 0 16777215 16777215 true Qt::WheelFocus Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true pgmodeler-0.9.2/libpgmodeler_ui/ui/objectstablewidget.ui000066400000000000000000000372261360462764600235130ustar00rootroot00000000000000 ObjectsTableWidget 0 0 461 236 0 0 Form 0 0 0 0 4 true 0 0 0 0 Add Item :/icones/icones/addrow.png:/icones/icones/addrow.png 22 22 Ins false 0 0 0 0 Remove Item :/icones/icones/delrow.png:/icones/icones/delrow.png 22 22 Del false 0 0 0 0 Remove All :/icones/icones/delrows.png:/icones/icones/delrows.png 22 22 Shift+Del false 0 0 0 0 Duplicate item :/icones/icones/duprow.png:/icones/icones/duprow.png 22 22 Ctrl+D false 0 0 0 0 Edit Item :/icones/icones/editdata.png:/icones/icones/editdata.png 22 22 Space false 0 0 0 0 Update Item :/icones/icones/atualizar.png:/icones/icones/atualizar.png 22 22 Alt+R false 0 0 0 0 Move Up :/icones/icones/movercima.png:/icones/icones/movercima.png 22 22 Ctrl+Up false 0 0 0 0 Move Down :/icones/icones/moverbaixo.png:/icones/icones/moverbaixo.png 22 22 Ctrl+Down false 0 0 0 0 Move to start :/icones/icones/moverprimeiro.png:/icones/icones/moverprimeiro.png 22 22 Ctrl+Home false 0 0 0 0 Move to end :/icones/icones/moverultimo.png:/icones/icones/moverultimo.png 22 22 Ctrl+End, Ctrl+S false 0 0 0 0 Resize columns to fit contents :/icones/icones/resizecols.png:/icones/icones/resizecols.png 22 22 0 0 QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows 16 16 30 true false false 26 true 25 false Qt::Horizontal QSizePolicy::Expanding 92 22 Qt::Horizontal QSizePolicy::Expanding 97 22 add_tb remove_tb remove_all_tb edit_tb move_up_tb move_down_tb move_first_tb move_last_tb table_tbw pgmodeler-0.9.2/libpgmodeler_ui/ui/operationlistwidget.ui000066400000000000000000000265721360462764600237500ustar00rootroot00000000000000 OperationListWidget true 0 0 260 335 0 0 260 0 524287 524287 Executed Operations :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png 0 2 0 2 2 9 0 2 2 2 4 9 false Executed Operations Qt::Horizontal 156 5 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true 0 0 0 0 6 true 0 170 255 0 170 255 0 170 255 QFrame::Sunken QAbstractItemView::NoEditTriggers true true QAbstractItemView::NoSelection QAbstractItemView::SelectItems 14 14 20 false true false true true false 1 true Operations: true 0 true Position: true 0 Qt::Horizontal 106 20 false Delete operation history :/icones/icones/excluir.png:/icones/icones/excluir.png 22 22 false false Undo :/icones/icones/desfazer.png:/icones/icones/desfazer.png 22 22 false false Redo :/icones/icones/refazer.png:/icones/icones/refazer.png 22 22 false operations_tw rem_operations_tb undo_tb redo_tb hide_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/operatorclasswidget.ui000066400000000000000000000125241360462764600237250ustar00rootroot00000000000000 OperatorClassWidget 0 0 559 294 0 0 85 5 25 21 4 4 91 16 0 0 90 0 Default Class: 114 4 68 16 0 0 68 0 Indexing: 178 4 78 24 0 50 481 141 Elements 4 4 4 4 6 Element Type: 0 0 Operator Function Storage Qt::Horizontal 271 20 Function: Operator: Support/Strategy: 1 Op. Family: 4 32 68 16 68 0 Op. Family: def_class_chk indexing_cmb elem_type_cmb stg_num_sb pgmodeler-0.9.2/libpgmodeler_ui/ui/operatorfamilywidget.ui000066400000000000000000000033551360462764600241030ustar00rootroot00000000000000 OperatorFamilyWidget 0 0 243 36 0 0 2 2 2 2 6 0 0 68 0 Indexing: Qt::Horizontal 86 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/operatorwidget.ui000066400000000000000000000077731360462764600227110ustar00rootroot00000000000000 OperatorWidget 0 0 522 224 2 2 2 2 6 0 Arguments Advanced 4 4 4 4 6 Join: Restrict: Commutator: Negator: Qt::Vertical 20 193 Qt::Horizontal 229 20 Operator Func.: HASHES 70 0 Options: MERGES pgmodeler-0.9.2/libpgmodeler_ui/ui/parameterwidget.ui000066400000000000000000000057071360462764600230310ustar00rootroot00000000000000 ParameterWidget 0 0 436 204 430 0 4 53 91 16 80 0 16777215 16777215 Default Value: 100 50 112 23 true 4 129 51 16 75 16777215 Mode: 83 129 200 30 4 IN OUT 0 0 VARIADIC Qt::Horizontal 40 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/permissionwidget.ui000066400000000000000000000355151360462764600232410ustar00rootroot00000000000000 PermissionWidget 0 0 827 575 0 0 16777215 16777215 Edit permissions 2 2 2 2 6 0 Permissions 4 4 4 4 Qt::Horizontal 0 0 16777215 16777215 ID: 0 0 0 25 true true Disable SQL code Qt::Vertical 0 0 0 150 16777215 16777215 Roles 0 0 0 150 16777215 16777215 Privileges 4 4 4 4 6 true &Grant true Re&voke false Cascade QAbstractItemView::SingleSelection QAbstractItemView::SelectRows false true false Privilege GRANT OPTION Qt::Horizontal 35 20 false 0 0 Add Permission :/icones/icones/adicionar.png:/icones/icones/adicionar.png 22 22 false 0 0 Update Permission :/icones/icones/atualizar.png:/icones/icones/atualizar.png 22 22 false 0 0 Cancel Operation :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 Qt::Horizontal 35 20 0 0 250 0 16777215 16777215 Permissions Code Preview 4 4 4 4 DejaVu Sans Mono true perm_id_edt perm_disable_sql_chk grant_rb revoke_rb cascade_chk privileges_tbw add_perm_tb upd_perm_tb cancel_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/pgsqltypewidget.ui000066400000000000000000000464061360462764600231020ustar00rootroot00000000000000 PgSQLTypeWidget 0 0 442 358 0 0 0 0 16777215 16777215 Form 2 4 4 4 6 0 0 0 0 Qt::NoFocus Data Type 4 4 4 4 true 0 0 0 0 font-weight: normal; true 0 0 0 0 PreferDefault font-weight: normal; true QComboBox::AdjustToContentsOnFirstShow SRID: -1 99999 true 0 0 0 0 16777215 16777215 false font-weight: normal; Variation: Z 0 0 M 0 0 60 0 60 16777215 Precision font-weight: normal; -1 1000 1 -1 true 0 0 55 0 55 16777215 false font-weight: normal; Spatial: 0 0 40 0 40 16777215 Dimension font-weight: normal; 99 0 0 0 55 0 55 16777215 font-weight: normal; Format: true 0 0 Qt::LeftToRight font-weight: normal; font-weight: normal; Timezone: true 0 0 0 0 font-weight: normal; true 0 0 55 0 55 16777215 font-weight: normal; Type: 0 0 20 0 16 16777215 false Precision font-weight: normal; P: 0 0 60 0 60 16777215 Length font-weight: normal; 0 2147483647 0 0 0 20 0 16 16777215 false Length font-weight: normal; L: true 0 0 55 0 55 16777215 false font-weight: normal; Interval: 0 0 20 0 16 16777215 false Dimension font-weight: normal; [ ]: 0 0 16777215 16777215 QFrame::Sunken 1 0 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true type_lbl type_cmb length_lbl length_sb precision_lbl precision_sb dimension_lbl dimension_sb interval_lbl spatial_lbl timezone_lbl timezone_chk format_lbl format_txt spatial_cmb interval_cmb pgmodeler-0.9.2/libpgmodeler_ui/ui/pluginsconfigwidget.ui000066400000000000000000000074721360462764600237210ustar00rootroot00000000000000 PluginsConfigWidget 0 0 623 376 Form 2 0 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 true 0 0 0 0 16777215 16777215 Open in file manager :/icones/icones/abrir.png:/icones/icones/abrir.png 22 22 0 0 Plug-ins root directory: 0 0 Loaded plug-ins pgmodeler-0.9.2/libpgmodeler_ui/ui/policywidget.ui000066400000000000000000000113311360462764600223360ustar00rootroot00000000000000 PolicyWidget 0 0 520 400 520 380 4 4 4 4 Basics 4 4 4 4 Command: Permissive true Qt::Horizontal 200 20 Qt::Horizontal QSizePolicy::Fixed 10 20 0 Roles Expressions 4 4 4 4 USING: 0 0 CHECK: 0 0 command_cmb permissive_chk attribs_tbw pgmodeler-0.9.2/libpgmodeler_ui/ui/referencewidget.ui000066400000000000000000000545011360462764600230030ustar00rootroot00000000000000 ReferenceWidget 0 0 689 263 0 0 Reference properties 4 4 4 4 6 true 0 Properties 4 4 4 4 6 0 0 0 0 Ref. type: 0 0 false <strong>SELECT</strong><br/>The reference will be used as part of the SELECT statement to retrieve columns or expressions that will compose the view's columns.<br/><strong>FROM</strong><br/>The reference is used in the FROM portion of the command in order to reference tables or construct JOIN statements.<br/><strong>WHERE</strong><br/>The reference will be used as part of the WHERE clause in form of conditional expression. <br/><strong>GROUP/HAVING</strong><br/>The reference will be appended to the very end of the view's definition. This is useful when using GROUP BY/HAVING statements.<br/><strong>View definition</strong><br/>The reference's expression is used exclusively as the view's definition.<br/> SELECT 0 0 0 0 false FROM 0 0 false WHERE 0 0 false GROUP/HAVING Qt::Horizontal 40 20 0 0 View Definition 0 0 22 22 22 22 View's references can point to a table, column or expression. Table / Column Table / Column Expression 0 0 Ref. alias: 0 0 0 0 16777215 16777215 This is a more friendly description for the reference. When displaying the model in compact view this is the text shown for the reference instead of its real description. If this field is empty the real description will be displayed anyway. true 0 0 22 22 22 22 0 0 Used in: 0 0 Ref. object: 0 0 Table alias: 0 0 true 0 0 Column alias: false 0 0 true 0 0 Expression: 0 0 Expr. alias: 0 0 true Qt::Horizontal 318 17 0 0 22 22 22 22 true Columns 6 4 4 4 4 0 0 16777215 16777215 Name: 0 0 16777215 16777215 Alias: 0 0 0 0 16777215 16777215 This is a more friendly name for the column. When displaying the model in compact view this is the name shown for the column instead of its real name. If this field is empty the real name will be displayed anyway. true 0 0 6 0 0 0 0 0 0 22 22 22 22 0 0 0 0 16777215 16777215 This is the name of the object in the PostgreSQL database. true Referenced tables 30 30 61 22 Table: properties_tbw ref_type_cmb ref_alias_edt select_from_chk from_where_chk after_where_chk end_expr_chk view_def_chk tab_alias_edt col_alias_edt expr_alias_edt name_edt alias_edt pgmodeler-0.9.2/libpgmodeler_ui/ui/relationshipconfigwidget.ui000066400000000000000000001077331360462764600247420ustar00rootroot00000000000000 RelationshipConfigWidget 0 0 584 605 577 410 Form 8 2 0 0 0 0 Connection Mode 4 4 4 4 0 0 QFrame::StyledPanel 4 4 4 4 This mode renders the relationships in crow's foot notation which has a better semantics and readability. It also determines the optimal point where the relationship is connected on the tables' edges taking their position into account. Crow's foot notation true true true 0 0 22 22 22 22 Qt::Horizontal 368 20 true 0 0 555 81 555 81 QFrame::StyledPanel QFrame::Sunken Qt::PlainText :/imagens/imagens/crows_foot_notation.png Qt::NoTextInteraction This mode determines the optimal point where the relationship is connected on the tables' edges taking their position into account. It implies the usage of the classical ER notation. Connect tables' edges true 0 0 22 22 22 22 Qt::Horizontal 338 20 false 0 0 0 0 555 16777215 QFrame::StyledPanel QFrame::Sunken Qt::PlainText :/imagens/imagens/rel_tab_edges.png Qt::NoTextInteraction 0 0 This mode is available only for <strong>one-to-one</strong>, <strong>one-to-many</strong> and <strong>fk relationships</strong> but provides a better semantics when linking tables by placing the lines on the exact point where the relationship occurs. It implies the usage of the classical ER notation. Connect FK to PK columns false true 0 0 22 22 22 22 Qt::Horizontal 318 20 false 0 0 0 101 555 101 QFrame::StyledPanel QFrame::Sunken Qt::PlainText :/imagens/imagens/rel_fk_to_pk.png Qt::NoTextInteraction This mode is the classical one. It connects the relationship to tables through their central points. It implies the usage of the classical ER notation. Connect tables' center points true 0 0 22 22 22 22 Qt::Horizontal 298 20 false 0 0 0 101 555 101 QFrame::StyledPanel QFrame::Sunken Qt::PlainText :/imagens/imagens/rel_center_pnts.png Qt::NoTextInteraction Qt::Vertical 20 40 FK Settings && Patterns 4 4 4 4 0 0 Foreign key settings false false 4 4 4 4 6 false 0 0 0 0 16777215 16777215 Deferral: 0 0 90 0 90 16777215 Deferrable: 0 0 0 0 16777215 16777215 false 0 0 0 0 16777215 16777215 QComboBox::AdjustToContents ON DELETE: ON UPDATE: 0 0 false Name patterns false 4 4 4 4 Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Foreign Key (Source): Relationship type: Pattern for columns generated based upon target table's pk (n-n). Column (Target): Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Column (Source): Pattern for foreign key generated based upon target table's pk (n-n). Foreign Key (Target): Pattern for unique key generated by the relationship. Unique Key Name: Pattern for primary key generated by identifier relationship. Primary Key Name: Pattern for primary key generated by identifier relationship. Primary Key Column: 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff Qt::Vertical 20 132 settings_twg fk_to_pk_rb center_pnts_rb deferrable_chk deferral_cmb del_action_cmb upd_action_cmb rel_type_cmb src_col_pattern_txt dst_col_pattern_txt src_fk_pattern_txt dst_fk_pattern_txt pk_pattern_txt uq_pattern_txt pk_col_pattern_txt pgmodeler-0.9.2/libpgmodeler_ui/ui/relationshipwidget.ui000066400000000000000000001450251360462764600235500ustar00rootroot00000000000000 RelationshipWidget 0 0 858 1251 0 0 0 0 16777215 16777215 2 2 2 2 6 0 0 16777215 16777215 0 General 4 4 4 4 6 0 0 0 0 16777215 16777215 Table 1: 0 0 22 22 22 22 0 0 0 0 16777215 16777215 Cardinality: 0 0 0 0 16777215 16777215 Name of the table generated from many to many relationship Gen. Table Name: 0 0 105 0 105 16777215 Rel. Type: 0 0 22 22 22 22 0 0 0 0 16777215 16777215 Table 2: 0 0 [SRC] is required 0 0 [DST] is required 22 22 22 22 true 75 true rel_type Qt::Horizontal 40 20 0 0 0 0 0 0 0 0 The receiver's primary key will be composed by the generated foreign key columns. Identifier 0 0 22 22 22 22 0 0 0 0 0 0 0 0 Instead of create a multi-valued primary key with the generated foreign keys columns a single column is created and used as primary key. Single PK column 0 0 22 22 22 22 Custom Color: Name of the table generated from many to many relationship true 0 0 22 22 22 22 0 0 0 0 16777215 16777215 true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff Qt::Vertical QSizePolicy::Expanding 20 40 Bounding expression 4 4 4 4 Partitioning type: 75 true NONE Qt::Horizontal QSizePolicy::Fixed 20 20 Default partitions are only supported on <strong>PostgreSQL 11+</strong>. Using this option and exporting the code to PostgreSQL 10 syntax errors will be raised. Default partition 0 0 22 22 22 22 Qt::Horizontal 40 20 Generate the partition bounding expression based upon the partitioning type in use. Generate expression :/icones/icones/codigosql.png:/icones/icones/codigosql.png 22 22 Qt::ToolButtonTextBesideIcon Settings 4 4 4 4 0 0 false Name Patterns false 4 4 4 4 Use the values defined on settings dialogs for the fields below Use global settings for these fields true false 0 0 0 0 Pattern for columns generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Column (Source): Pattern for columns generated based upon target table's pk (n-n). Column (Target): Pattern for foreign key generated based upon reference table's pk (1-1 and 1-n) or based upon source table's pk (n-n). Foreign Key (Source): Pattern for foreign key generated based upon target table's pk (n-n). Foreign Key (Target): Pattern for primary key generated by identifier relationship. Primary Key Name: Pattern for unique key generated by the relationship. Unique Key Name: Pattern for primary key generated by identifier relationship. Primay Key Column: 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 0 0 16777215 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff 0 0 Foreign key Settings false false 6 4 4 4 4 true Use the values defined on settings dialogs for the fields below Use global settings for these fields true false 0 20 0 0 0 0 6 0 0 90 0 90 16777215 Deferrable: 0 0 0 0 16777215 16777215 false 0 0 0 0 16777215 16777215 Deferral: false 0 0 0 0 16777215 16777215 QComboBox::AdjustToContents ON DELETE: ON UPDATE: 0 0 Copy Options 4 4 4 4 false INDEXES false COMMENTS INCLUDING false DEFAULTS 0 0 E&XCLUDING false CONSTRAINTS 0 0 Use defaults true false ALL false STORAGE 0 1 16777215 1 QFrame::StyledPanel QFrame::Sunken false STATISTICS false IDENTITY Qt::Vertical 20 40 Attributes Constraints Primary key 4 4 4 4 6 0 0 QAbstractItemView::SelectedClicked QAbstractItemView::NoSelection 2 true Advanced rel_attribs_tbw table1_mand_chk table2_mand_chk relnn_tab_name_edt ref_table_txt recv_table_txt rel_columns_lst pgmodeler-0.9.2/libpgmodeler_ui/ui/rolewidget.ui000066400000000000000000000151671360462764600220130ustar00rootroot00000000000000 RoleWidget 0 0 517 455 400 0 2 2 2 2 6 false 0 0 yyyy-MMM-dd hh:mm:ss false Qt::OffsetFromUTC 0 0 0 25 -1 65535 -1 Validity 50 false false Connections: Attributes 4 4 4 4 6 Superuser Inherit permissions Can create database Bypass RLS Can use replication Can login Can create role 0 Members Member of Members (Admin.) Password: 0 0 true 0 0 Encrypted passwd_edt encrypt_pass_chk validity_chk validity_dte conn_limit_sb superusr_chk create_db_chk members_twg pgmodeler-0.9.2/libpgmodeler_ui/ui/rulewidget.ui000066400000000000000000000170251360462764600220140ustar00rootroot00000000000000 RuleWidget 0 0 536 203 0 0 2 2 2 2 6 0 0 0 0 Event: 0 0 90 0 16777215 16777215 QComboBox::AdjustToContents 0 0 0 0 16777215 16777215 Execution Type: 10 0 0 90 0 16777215 16777215 QComboBox::AdjustToContents 0 0 0 0 Conditional Expr.: Commands 4 4 4 4 6 0 0 0 0 SQL Command: 0 0 0 50 16777215 120 QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded 0 0 0 0 16777215 65 QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded event_cmb exec_type_cmb cond_expr_txt comando_txt pgmodeler-0.9.2/libpgmodeler_ui/ui/sceneinfowidget.ui000066400000000000000000000223001360462764600230060ustar00rootroot00000000000000 SceneInfoWidget 0 0 429 34 0 0 Form 15 0 0 0 0 6 0 0 18 18 18 18 Current position of the mouse in the canvas QFrame::NoFrame QFrame::Plain :/icones/icones/selecionar.png true Qt::AlignCenter Qt::NoTextInteraction 50 0 0 0 Current position of the mouse in the canvas - 6 0 0 18 18 18 18 Current zoom factor QFrame::NoFrame QFrame::Plain :/icones/icones/objselect.png true Qt::AlignCenter Qt::NoTextInteraction 50 0 0 0 Current zoom factor - 6 0 0 18 18 18 18 Currently selected object(s) QFrame::NoFrame QFrame::Plain :/icones/icones/table.png true Qt::AlignCenter Qt::NoTextInteraction 50 0 0 0 Currently selected object(s) - 6 0 0 18 18 18 18 Dimensions of the selected object(s) QFrame::NoFrame QFrame::Plain :/icones/icones/alinhargrade.png true Qt::AlignCenter Qt::NoTextInteraction 50 0 0 0 Dimensions of the selected object(s) - pgmodeler-0.9.2/libpgmodeler_ui/ui/schemawidget.ui000066400000000000000000000023431360462764600223020ustar00rootroot00000000000000 SchemaWidget 0 0 499 57 0 2 60 16 60 0 Fill color: 134 5 108 20 0 0 Show rectangle true pgmodeler-0.9.2/libpgmodeler_ui/ui/sequencewidget.ui000066400000000000000000000130711360462764600226520ustar00rootroot00000000000000 SequenceWidget 0 0 603 165 0 0 400 102 0 0 0 0 6 Defualt values: Cyclic: Start: 0 25 false Qt::ImhFormattedNumbersOnly false true Increment: 0 25 false Qt::ImhFormattedNumbersOnly false true Minimum: 0 25 false Qt::ImhFormattedNumbersOnly false true Maximum: 0 25 false Qt::ImhFormattedNumbersOnly false true Cache: 0 25 false Qt::ImhFormattedNumbersOnly false true Owner Col.: pgmodeler-0.9.2/libpgmodeler_ui/ui/snippetsconfigwidget.ui000066400000000000000000000516061360462764600241030ustar00rootroot00000000000000 SnippetsConfigWidget 0 0 613 557 Form 2 0 0 0 0 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 0 0 0 0 QComboBox::AdjustToContentsOnFirstShow 18 18 0 0 Label: 0 0 true 0 0 80 0 Applies to: 0 0 ID: 0 0 true 0 0 QComboBox::InsertAlphabetically true 30 25 Create new connection :/icones/icones/novo.png:/icones/icones/novo.png 22 22 true 30 25 Cancel edition :/icones/icones/fechar1.png:/icones/icones/fechar1.png 22 22 false 30 25 Edit selected connection :/icones/icones/editar.png:/icones/icones/editar.png 22 22 false 30 25 Delete selected connection :/icones/icones/excluir.png:/icones/icones/excluir.png 22 22 false 0 0 0 0 Remove All :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 22 22 Shift+Del 0 0 Snippets: Qt::Horizontal 40 20 false 0 0 0 0 16777215 16777215 Parse the snippet in order to check if there are syntax errors. Parse :/icones/icones/buscar.png:/icones/icones/buscar.png 22 22 false 0 0 0 0 16777215 16777215 Add :/icones/icones/adicionar.png:/icones/icones/adicionar.png 22 22 false 0 0 0 0 16777215 16777215 Update :/icones/icones/padroes.png:/icones/icones/padroes.png 22 22 QComboBox::AdjustToContentsOnFirstShow 18 18 Qt::Horizontal 340 20 6 0 0 Parsable or dynamic snippets are written in the <strong>schema micro language</strong> syntax. When using a parsable snippet the attributes surrounded in <strong>{}</strong> will be replaced by the selected object's matching attributes. Parsable 0 0 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 25 20 false 0 0 When handling parsable snippets empty attributes will be replaced by a value in the format <strong>{attribute}</strong>. Note that this option can affect the semantics of the resulting snippet. Placeholders 0 0 22 22 22 22 Qt::Horizontal 40 20 0 0 Filter: 0 1 16777215 1 QFrame::StyledPanel QFrame::Sunken 0 0 pgmodeler-0.9.2/libpgmodeler_ui/ui/sourcecodewidget.ui000066400000000000000000000217031360462764600231760ustar00rootroot00000000000000 SourceCodeWidget 0 0 670 464 Source code visualization 2 2 2 2 6 50 0 50 16777215 Version: Qt::Horizontal QSizePolicy::Fixed 15 20 0 0 75 0 16777215 16777215 true PostgreSQL 0 0 16777215 16777215 QComboBox::InsertAtBottom Qt::Horizontal 28 20 32 32 32 32 iconecodigo QTabWidget::North 0 SQL 4 4 4 4 6 Code display: 0 0 Original Original + depedencies' SQL Original + children's SQL 0 0 22 22 22 22 Qt::Horizontal 40 20 Save the SQL code to a file. Save SQL :/icones/icones/salvar.png:/icones/icones/salvar.png 22 22 Qt::ToolButtonTextBesideIcon 0 0 XML 4 4 4 4 6 version_cmb sourcecode_twg pgmodeler-0.9.2/libpgmodeler_ui/ui/sqlexecutionwidget.ui000066400000000000000000000742561360462764600236010ustar00rootroot00000000000000 SQLExecutionWidget 0 0 843 349 780 0 Form 2 2 2 2 0 0 0 0 0 0 25 25 25 25 Close the current SQL script ... :/icones/icones/fechar.png:/icones/icones/fechar.png 20 20 true 0 25 SQL script currently handled false background: transparent; false 0 true (not saved) 4 false 0 0 0 30 Run the specified SQL command Run :/icones/icones/run.png:/icones/icones/run.png 22 22 F5 Qt::ToolButtonTextBesideIcon true true 0 0 0 30 Cancel the execution of the current SQL command Stop :/icones/icones/stop.png:/icones/icones/stop.png 22 22 Esc Qt::ToolButtonTextBesideIcon true true 0 30 Handle external SQL script &Script :/icones/icones/codigosql.png:/icones/icones/codigosql.png 22 22 Alt+F false false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon true false 0 30 Search in SQL code Fi&nd :/icones/icones/buscar.png:/icones/icones/buscar.png 22 22 Ctrl+F true false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon true false 0 30 Clear sql input field and results Clear All :/icones/icones/limpartexto.png:/icones/icones/limpartexto.png 22 22 Qt::ToolButtonTextBesideIcon true true 0 30 Export results to a CSV file Snippe&ts :/icones/icones/codesnippet.png:/icones/icones/codesnippet.png 22 22 Alt+T false false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon true false 0 30 Export results to a CSV file E&xport :/icones/icones/exportdata.png:/icones/icones/exportdata.png 22 22 Alt+X false false Qt::ToolButtonTextBesideIcon true false 0 30 Filter the retrived results F&ilter :/icones/icones/filter.png:/icones/icones/filter.png 22 22 Alt+I true false Qt::ToolButtonTextBesideIcon true true 0 30 Toggles the output pane &Output :/icones/icones/outputpane.png:/icones/icones/outputpane.png 22 22 Alt+O true false Qt::ToolButtonTextBesideIcon true Qt::Horizontal QSizePolicy::Expanding 10 20 0 0 20 20 22 22 :/icones/icones/database.png true -1 0 0 Current working database 5 Qt::Vertical false true 0 0 0 0 0 0 0 0 0 0 0 0 QTabWidget::South 0 false false false Results 4 4 4 4 0 0 0 0 0 0 0 0 true 0 0 Case sensitive 0 0 Regular expression 0 0 Exact match Qt::Horizontal 40 20 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true 0 0 0 0 6 QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed true QAbstractItemView::ContiguousSelection false true 26 25 Messages 4 4 4 4 QAbstractItemView::NoEditTriggers false true QAbstractItemView::NoSelection QAbstractItemView::SelectRows 20 20 2 History 4 4 4 4 0 0 pgmodeler-0.9.2/libpgmodeler_ui/ui/sqltoolwidget.ui000066400000000000000000000357311360462764600225460ustar00rootroot00000000000000 SQLToolWidget 0 0 658 469 Form true 4 0 0 0 0 0 0 0 0 true QFrame::NoFrame 0 0 0 0 Qt::Horizontal 4 true 0 0 Database explorer 4 4 4 4 0 0 0 0 0 false QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 false 0 0 Disconnect from all databases ... :/icones/icones/disconnect.png:/icones/icones/disconnect.png 22 22 false 0 0 false QComboBox::InsertAlphabetically QComboBox::AdjustToMinimumContentsLengthWithIcon 18 18 false 0 0 Update the database list ... :/icones/icones/atualizar.png:/icones/icones/atualizar.png 22 22 285 0 false true true false 6 3 3 Qt::Horizontal 40 20 0 0 Toggle the object's attributes grid Attributes :/icones/icones/attribute.png:/icones/icones/attribute.png 22 22 Alt+R true true Qt::ToolButtonTextBesideIcon 0 0 Toggle the display of source code pane Source code :/icones/icones/codigosql.png:/icones/icones/codigosql.png 22 22 true true Qt::ToolButtonTextBesideIcon Qt::Horizontal 40 20 Qt::Vertical false 0 0 SQL execution 4 4 4 4 310 0 false true true false 0 0 Source code database_cmb pgmodeler-0.9.2/libpgmodeler_ui/ui/swapobjectsidswidget.ui000066400000000000000000000355351360462764600240770ustar00rootroot00000000000000 SwapObjectsIdsWidget 0 0 568 567 0 0 Change objects creation order 4 11 44 18 0 0 Create: 290 20 18 18 0 0 50 false ID: 410 12 32 32 0 0 32 32 32 32 4 49 45 18 0 0 Before: 290 50 18 18 0 0 50 false ID: 410 50 32 32 0 0 32 32 32 32 20 500 451 60 0 0 0 48 16777215 16777215 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 0 0 50 false false false true Change the objects creation order is an irreversible operation and cause the operations history to be automatically erased. Note that the creation order configured in this form is not definitive and may change after a model validation. true false 130 80 115 29 0 0 0 0 16777215 16777215 Qt::StrongFocus Swap the values of the fields Swap values :/icones/icones/atualizar.png:/icones/icones/atualizar.png 22 22 Qt::ToolButtonTextBesideIcon false 280 80 115 29 0 0 0 0 16777215 16777215 Qt::StrongFocus Swap the object ids changing their creation order Swap ids :/icones/icones/swapobjs.png:/icones/icones/swapobjs.png 22 22 Qt::ToolButtonTextBesideIcon 60 160 274 44 0 0 0 0 true 0 0 Filter: true true Hide system objects true Hide relationships true true 40 240 421 81 QAbstractItemView::NoEditTriggers true QAbstractItemView::SingleSelection QAbstractItemView::SelectRows Qt::SolidLine true true 96 30 true true false false 28 false 25 false false ID AlignLeading|AlignVCenter :/icones/icones/uid.png:/icones/icones/uid.png Object AlignLeading|AlignVCenter :/icones/icones/table.png:/icones/icones/table.png Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png Parent Object AlignLeading|AlignVCenter :/icones/icones/schema.png:/icones/icones/schema.png Parent Type AlignLeading|AlignVCenter :/icones/icones/usertype.png:/icones/icones/usertype.png pgmodeler-0.9.2/libpgmodeler_ui/ui/tabledatawidget.ui000066400000000000000000000537271360462764600227770ustar00rootroot00000000000000 TableDataWidget 0 0 658 412 Edit table data 0 0 0 0 true 0 0 QAbstractScrollArea::AdjustToContents QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked QAbstractItemView::NoDragDrop true QAbstractItemView::ExtendedSelection QAbstractItemView::SelectItems QAbstractItemView::ScrollPerPixel false 0 0 true 25 false true false 25 25 false 0 0 8 Copy items on the grid Copy :/icones/icones/copiar.png:/icones/icones/copiar.png 22 22 QToolButton::InstantPopup Qt::ToolButtonIconOnly true 0 0 Add empty rows Add row :/icones/icones/addrow.png:/icones/icones/addrow.png 22 22 Ins Qt::ToolButtonIconOnly false 0 0 Delete the selected columns Delete column :/icones/icones/delcol.png:/icones/icones/delcol.png 22 22 Del Qt::ToolButtonIconOnly false 0 0 8 Paste items on the grid Paste :/icones/icones/colar.png:/icones/icones/colar.png 22 22 Ctrl+V QToolButton::InstantPopup Qt::ToolButtonIconOnly true 0 0 Fills the grid using a CSV file :/icones/icones/loadcsv.png:/icones/icones/loadcsv.png 22 22 true Qt::ToolButtonIconOnly 0 0 0 30 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_alerta.png true 0 0 50 false false false true <html><head/><body><p>Some invalid or duplicated columns were detected. In order to solve this issue double-click the header of the highlighted ones in order to define the correct name in which the data belongs to or delete the entire column. Note that these columns are completely ignored when generating the <span style=" font-weight:600;">INSERT</span> commands.</p></body></html> true true 0 0 Add an empty column Add column :/icones/icones/addcol.png:/icones/icones/addcol.png 22 22 QToolButton::InstantPopup Qt::ToolButtonIconOnly false 0 0 Duplicate the selected rows Duplicate rows :/icones/icones/duprow.png:/icones/icones/duprow.png 22 22 Ctrl+D Qt::ToolButtonIconOnly Qt::Horizontal 40 20 false 0 0 8 Change the values of all selected cells at once Bulk data edit :/icones/icones/bulkedit.png:/icones/icones/bulkedit.png 22 22 Ctrl+E Qt::ToolButtonIconOnly Qt::Horizontal 40 20 Qt::Horizontal QSizePolicy::Fixed 10 20 0 0 false 0 0 Remove all columns (and rows) from the grid Delete all columns :/icones/icones/delcols.png:/icones/icones/delcols.png 22 22 Ctrl+Shift+Del Qt::ToolButtonIconOnly false 0 0 Delete the selected rows Delete rows :/icones/icones/delrow.png:/icones/icones/delrow.png 22 22 Del Qt::ToolButtonIconOnly 0 0 0 30 QFrame::StyledPanel QFrame::Raised 2 2 2 2 24 24 24 24 Qt::AutoText :/icones/icones/msgbox_info.png true 0 0 50 false false false true <html><head/><body><p>Empty values are assumed as <span style=" font-weight:600;">DEFAULT</span>. To use special values like <span style=" font-weight:600;">NULL</span>, a function call like <span style=" font-weight:600;">now()</span> or a specific data escaping, enclose values in two slashes, e.g., <span style=" font-weight:600;">/value/</span>. To use a slash as part of the value prepend the backslash character, e.g., <span style=" font-weight:600;">\/</span>.</p></body></html> true false 0 0 Remove all rows from the grid preserving columns Delete all rows :/icones/icones/delrows.png:/icones/icones/delrows.png 22 22 Shift+Del Qt::ToolButtonIconOnly Qt::Horizontal QSizePolicy::Fixed 10 20 clear_rows_tb hint_frm data_tbw del_cols_tb add_col_tb dup_rows_tb add_row_tb del_rows_tb clear_cols_tb csv_load_tb csv_load_parent warn_frm bulkedit_tb copy_tb paste_tb pgmodeler-0.9.2/libpgmodeler_ui/ui/tablespacewidget.ui000066400000000000000000000035331360462764600231470ustar00rootroot00000000000000 TablespaceWidget 0 0 239 29 0 0 Form 2 2 2 2 6 0 0 Directory: 0 25 false Qt::ImhNone false true pgmodeler-0.9.2/libpgmodeler_ui/ui/tablewidget.ui000066400000000000000000000215201360462764600221270ustar00rootroot00000000000000 TableWidget 0 0 752 428 0 0 2 2 2 2 6 Attributes 4 4 4 4 10 0 0 Unlogged 0 0 With OID false 0 0 Enable row level security 0 0 Generate ALTER for columns/constraints true 0 0 Force RLS for owner 0 0 0 0 Tag: 0 0 0 0 Server: 0 0 0 20 0 &Columns Co&nstraints Tri&ggers &Rules &Indexes &Policies Partition &keys 4 4 4 4 0 0 Partitioning: 150 0 Qt::Horizontal 40 20 &Tables Options pgmodeler-0.9.2/libpgmodeler_ui/ui/tagwidget.ui000066400000000000000000000050071360462764600216150ustar00rootroot00000000000000 TagWidget 0 0 437 193 0 0 0 0 Colors 4 4 4 4 Body: Title: Schema name: Table name: Extended body: Qt::Vertical 20 40 pgmodeler-0.9.2/libpgmodeler_ui/ui/taskprogresswidget.ui000066400000000000000000000130001360462764600235610ustar00rootroot00000000000000 TaskProgressWidget Qt::ApplicationModal 0 0 550 77 0 0 550 77 16777215 16777215 Executing tasks :/icones/icones/pgsqlModeler48x48.png:/icones/icones/pgsqlModeler48x48.png true 0 0 0 0 0 QFrame::StyledPanel QFrame::Raised 4 4 4 4 4 0 0 64 64 64 64 Qt::PlainText :/imagens/imagens/pgmodeler_logo.png true Qt::AlignCenter 0 0 false Waiting task to start... 0 Qt::AlignCenter false %p% 0 0 35 32 35 32 Qt::AlignCenter 0 pgmodeler-0.9.2/libpgmodeler_ui/ui/textboxwidget.ui000066400000000000000000000140321360462764600225350ustar00rootroot00000000000000 TextboxWidget 0 0 578 204 2 2 2 2 0 0 Font: Text 4 4 4 4 2 1 1.000000000000000 200.000000000000000 9.000000000000000 pt Color: 10 Qt::Horizontal QSizePolicy::Fixed 5 0 45 23 45 23 0 0 0 0 0 0 0 0 0 Qt::Horizontal QSizePolicy::Fixed 10 0 Bold Italic 0 0 Underline font_size_sb bold_chk italic_chk underline_chk pgmodeler-0.9.2/libpgmodeler_ui/ui/triggerwidget.ui000066400000000000000000000475221360462764600225150ustar00rootroot00000000000000 TriggerWidget 0 0 765 419 430 310 4 4 4 4 0 0 0 0 16777215 16777215 Events: 0 0 Type: 0 Arguments 4 4 4 4 6 Argument: 180 0 true false Columns 4 4 4 4 6 0 0 0 0 Column: 0 0 180 0 16777215 16777215 Constraint 4 4 4 4 true 0 0 0 0 16777215 16777215 Options: false 0 0 0 0 16777215 16777215 Deferrable: false 0 0 0 0 16777215 16777215 0 0 0 0 16777215 16777215 QFrame::Sunken 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAsNeeded false 0 0 0 0 16777215 16777215 Refer. Table: 0 0 0 0 16777215 16777215 Condition: 0 0 0 0 0 0 0 0 0 0 16777215 16777215 INSERT 0 0 0 0 16777215 16777215 DELETE 0 0 0 0 16777215 16777215 UPDATE 0 0 0 0 16777215 16777215 TRUNCATE 0 0 Ordinary trigger true 0 0 Constraint trigger 0 0 0 0 16777215 16777215 FOR EACH ROW true 0 0 0 0 16777215 16777215 true 0 0 0 0 16777215 16777215 Excution: true 0 0 0 0 16777215 16777215 Function: 0 0 Transition tables names 4 4 4 4 180 0 true OLD: NEW: 180 0 true deferrable_chk deferral_type_cmb arg_cols_tbw argument_edt column_cmb pgmodeler-0.9.2/libpgmodeler_ui/ui/typewidget.ui000066400000000000000000000377431360462764600220370ustar00rootroot00000000000000 TypeWidget 0 0 562 611 0 0 2 2 2 2 6 0 0 Range 0 Functions 4 4 4 4 6 INPUT: OUTPUT: RECV: SEND: TPMOD_IN: TPMOD_OUT: ANALYZE: Attributes 4 4 4 4 6 Internal Length: 0 0 90 0 Storage: Options: 0 0 By value 0 0 Preferred Collatable Category: Delimiter: 1 true Default Value: true Alignment: 0 0 90 0 integer char smallint double precision Qt::Horizontal 255 20 0 0 Configuration: 80 0 Base Type true 95 0 Enumeration 0 0 80 0 Co&mposite 0 0 0 100 Enumerations 4 4 4 4 6 Enumeration: true 0 0 0 100 Attributes 4 4 4 4 6 Name: true 0 0 Collation: 0 0 Attributes 4 4 4 4 6 Subtype Diff Func.: Operator Class: Canonical Func.: base_type_rb enumeration_rb composite_rb range_rb enum_name_edt attrib_name_edt base_attribs_twg internal_len_sb storage_cmb by_value_chk category_cmb preferred_chk delimiter_edt collatable_chk default_value_edt alignment_cmb pgmodeler-0.9.2/libpgmodeler_ui/ui/updatenotifierwidget.ui000066400000000000000000000267061360462764600240750ustar00rootroot00000000000000 UpdateNotifierWidget false Qt::WindowModal 0 0 450 280 450 280 Update Notifier false 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 6 6 6 6 12 75 true Update found! Qt::AlignCenter 0 0 48 480 :/icones/icones/update.png false Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 20 20 20 20 Hide this widget ... :/icones/icones/fechar1.png:/icones/icones/fechar1.png true 0 0 80 0 16777215 16777215 Released in: 0 0 50 true false mmm dd, yyyy 0 0 80 0 16777215 16777215 New version: 0 0 75 true 0.0.0 Changelog 2 2 2 2 QFrame::Sunken QAbstractScrollArea::AdjustToContents false QTextEdit::WidgetWidth true Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse Qt::Horizontal 40 20 0 30 Redirects to purchase page. Get binary package :/icones/icones/dl_binary.png:/icones/icones/dl_binary.png 22 22 false QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon 0 30 Redirects to GitHub source repository. Get source code :/icones/icones/dl_source.png:/icones/icones/dl_source.png 22 22 false Qt::ToolButtonTextBesideIcon Qt::Horizontal 40 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/usermappingwidget.ui000066400000000000000000000036151360462764600233770ustar00rootroot00000000000000 UserMappingWidget 0 0 462 210 0 0 0 0 0 0 0 0 0 0 Server: Options 0 0 0 20 pgmodeler-0.9.2/libpgmodeler_ui/ui/viewwidget.ui000066400000000000000000000110741360462764600220150ustar00rootroot00000000000000 ViewWidget 0 0 816 453 2 2 2 2 0 References Triggers Rules Indexes Table Expression Code Preview Options 2 2 2 2 0 0 Tag: 0 0 Mode: Ordinary true Recursi&ve false &Materialized false 0 0 With no data false pgmodeler-0.9.2/libpgmodeler_ui/ui/welcomewidget.ui000066400000000000000000000234321360462764600224770ustar00rootroot00000000000000 WelcomeWidget 0 0 714 353 0 0 false Form 0 0 0 0 0 0 190 240 :/styles/styles/pgmodeler_bg_logo.png Qt::AlignCenter 20 10 20 110 80 50 false false New model :/icones/icones/new_big.png:/icones/icones/new_big.png 55 55 Qt::ToolButtonTextUnderIcon true 110 80 50 false false Open model :/icones/icones/open_big.png:/icones/icones/open_big.png 55 55 Qt::ToolButtonTextUnderIcon true true 110 80 50 false false Sample models :/icones/icones/samples_big.png:/icones/icones/samples_big.png 55 55 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon true false 110 80 50 false false Recent models :/icones/icones/recent_big.png:/icones/icones/recent_big.png 55 55 QToolButton::InstantPopup Qt::ToolButtonTextUnderIcon true false 110 80 50 false PreferAntialias false Last session :/icones/icones/last_session_big.png:/icones/icones/last_session_big.png 55 55 Qt::ToolButtonTextUnderIcon true true 110 80 50 false PreferAntialias false Support :/icones/icones/help_big.png:/icones/icones/help_big.png 55 55 Qt::ToolButtonTextUnderIcon true pgmodeler-0.9.2/libutils/000077500000000000000000000000001360462764600153455ustar00rootroot00000000000000pgmodeler-0.9.2/libutils/libutils.pro000066400000000000000000000014411360462764600177160ustar00rootroot00000000000000# libutils.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = lib TARGET = utils windows: DESTDIR = $$PWD HEADERS += src/exception.h \ src/globalattributes.h \ src/pgsqlversions.h \ src/doublenan.h SOURCES += src/exception.cpp \ src/globalattributes.cpp \ src/pgsqlversions.cpp # Deployment settings target.path = $$PRIVATELIBDIR INSTALLS = target pgmodeler-0.9.2/libutils/src/000077500000000000000000000000001360462764600161345ustar00rootroot00000000000000pgmodeler-0.9.2/libutils/src/doublenan.h000066400000000000000000000017051360462764600202570ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libutils \brief Definition of a shortcut to double NAN used by some portions of pgModeler mainly when dealing with graphical operations */ #ifndef DOUBLE_NAN_H #define DOUBLE_NAN_H # define DNaN (__builtin_nan ("")) #endif pgmodeler-0.9.2/libutils/src/exception.cpp000066400000000000000000001216511360462764600206440ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "exception.h" #include QString Exception::messages[Exception::ErrorCount][2]={ {"Custom", QString(" ")}, {"AsgPseudoTypeColumn", QT_TR_NOOP("Assignment of a pseudo-type to the type of the column!")}, {"AsgInvalidPrecision", QT_TR_NOOP("Assignment of a precision greater than the length of the type!")}, {"AsgInvalidPrecisionTimestamp", QT_TR_NOOP("Assignment of an invalid precision to type time, timestamp or interval. The precision in this case must be equal to or less than 6!")}, {"AsgNotAllocatedColumn", QT_TR_NOOP("Assignment of a not allocated column to object `%1' (%2)!")}, {"RefColumnInvalidIndex", QT_TR_NOOP("Reference to a column which index is out of the capacity of the column list!")}, {"AsgNotAllocattedObject", QT_TR_NOOP("Assignment of not allocated object!")}, {"AsgNotAllocatedSchema", QT_TR_NOOP("Assignment of a not allocated schema to object `%1' (%2)!")}, {"AsgObjectInvalidDefinition", QT_TR_NOOP("The object `%1' (%2) has inconsistent SQL or XML definition!")}, {"AsgDuplicatedObject", QT_TR_NOOP("The object `%1' (%2) already exists on `%3' (%4)!")}, {"AsgDuplicatedObjectContainer", QT_TR_NOOP("The object `%1' (%2) cannot be assigned because there is already exists in the container object `%3'!")}, {"AsgObjectInvalidType", QT_TR_NOOP("Assigning object of an invalid type!")}, {"RemObjectInvalidType", QT_TR_NOOP("Removing an object of an invalid type!")}, {"ObtObjectInvalidType", QT_TR_NOOP("Obtaining an object of an invalid type!")}, {"AsgEmptyNameTableReturnType", QT_TR_NOOP("Assignment of empty name to table return type!")}, {"AsgDuplicatedParameterFunction", QT_TR_NOOP("The insertion of the parameter `%1' will not be possible because there is another parameter with same name in the function `%2'!")}, {"InsDuplicatedTableReturnType", QT_TR_NOOP("The insertion of the table return type `%1' will not be possible because there is another return type with the same name in the `%2'!")}, {"RefParameterInvalidIndex", QT_TR_NOOP("Reference to a parameter which index is out of the parameter list bounds!")}, {"RefInvalidTriggerEvent", QT_TR_NOOP("Reference to an event which does not belongs to trigger!")}, {"AsgInvalidColumnTrigger", QT_TR_NOOP("The column `%1' cannot be assigned to the trigger `%2' because they belongs to different parent tables!")}, {"AsgNotAllocatedFunction", QT_TR_NOOP("Assignment of a not allocated function to object `%1' (%2)!")}, {"AsgInvalidTriggerFunction", QT_TR_NOOP("Assignment of a function which return type is different from `%1'!")}, {"AsgFunctionInvalidParamCount", QT_TR_NOOP("Assignment of a function which parameter count is invalid to the object `%1' (%2)!")}, {"AsgFunctionInvalidLanguage", QT_TR_NOOP("Assignment of a function which language is invalid!")}, {"AsgEventTriggerFuncInvalidLang", QT_TR_NOOP("Event trigger function must be coded in any language other than SQL!")}, {"AsgNotAllocatedTable", QT_TR_NOOP("Assignment of not allocated table to object `%1' (%2)!")}, {"RefArgumentInvalidIndex", QT_TR_NOOP("Reference to an argument which index is out of argument list bounds!")}, {"AsgEmptyNameObject", QT_TR_NOOP("Assignment of empty name to an object!")}, {"AsgInvalidNameObject", QT_TR_NOOP("Assignment of a name which contains invalid characters!")}, {"AsgLongNameObject", QT_TR_NOOP("Assignment of a name which length exceeds the maximum of 63 characters!")}, {"AsgInvalidSchemaObject", QT_TR_NOOP("Assignment of schema object which type is invalid!")}, {"AsgInvalidTablespaceObject", QT_TR_NOOP("Assignment of tablespace object with invalid type!")}, {"AsgTablespaceInvalidObject", QT_TR_NOOP("Assignment of tablespace to an invalid object!")}, {"AsgTablespaceInvalidConstraintType", QT_TR_NOOP("Assignment of tablespace to a constraint which type is invalid! To belong to a tablespace the constraint must be a primary key or unique!")}, {"AsgInvalidRoleObject", QT_TR_NOOP("Assignment of owner object which type is invalid!")}, {"AsgRoleObjectInvalidType", QT_TR_NOOP("Assignment of owner to an invalid object!")}, {"AsgCustomSQLObjectInvalidType", QT_TR_NOOP("Assignment of appended or prepended SQL to an invalid object!")}, {"RefFunctionInvalidType", QT_TR_NOOP("Reference to a function with invalid type!")}, {"RefOperatorArgumentInvalidType", QT_TR_NOOP("Reference to an argument of the operator with invalid type!")}, {"RefOperatorInvalidType", QT_TR_NOOP("Reference to an operator with invalid type!")}, {"AsgValueInvalidRoleOptionType", QT_TR_NOOP("Assignment of value to an invalid option type on role!")}, {"RefInvalidRoleType", QT_TR_NOOP("Reference to an invalid role type!")}, {"InsDuplicatedRole", QT_TR_NOOP("The insertion of the role `%1' is not possible because this is already being referenced by role `%2'!")}, {"AsgRoleReferenceRedundancy", QT_TR_NOOP("Reference redundancy detected by having the role `%1' referencing the role `%2'!")}, {"AsgRoleMemberItself", QT_TR_NOOP("The role `%1' can not be listed as a member of itself!")}, {"RefRoleInvalidIndex", QT_TR_NOOP("Reference to a role which index is out of role list bounds!")}, {"InsEmptyRuleCommand", QT_TR_NOOP("Insertion of empty command to the rule!")}, {"RefRuleCommandInvalidIndex", QT_TR_NOOP("Reference to a command which index is out of the command list bounds!")}, {"InvInheritCopyPartRelationship", QT_TR_NOOP("It's not possible to create a self generalization/copy/partition relationship! The table can not inherit or copy its own attributes or be a partition of itself!")}, {"AsgObjectBelongsAnotherTable", QT_TR_NOOP("Assignment of an object that already belongs to another table!")}, {"AsgSchemaSequenceDiffersTableSchema", QT_TR_NOOP("Assignment of a schema to the sequence which differs from the schema of the owner table!")}, {"AsgInvalidValueSequenceAttributes", QT_TR_NOOP("Assignment of an invalid value to one of the sequence attributes!")}, {"AsgInvalidSequenceMinValue", QT_TR_NOOP("Assignment of a minimum value to the sequence which is greater than the maximum value!")}, {"AsgInvalidSequenceStartValue", QT_TR_NOOP("Assignment of a start value to the sequence which is extrapolating the range defined by minimum and maximum values!")}, {"AsgInvalidSequenceIncrementValue", QT_TR_NOOP("Assignment of a null increment value to the sequence!")}, {"AsgInvalidSequenceCacheValue", QT_TR_NOOP("Assignment of null cache value to the sequence!")}, {"AsgSeqOwnerTableDifferentSchema", QT_TR_NOOP("Assignment of owner table which is not in the same schema as the sequence `%1'!")}, {"AsgSeqOwnerTableDifferentRole", QT_TR_NOOP("Assignment of owner table which does not belong to the same owner of the sequence `%1'!")}, {"AsgInexistentSeqOwnerColumn", QT_TR_NOOP("Assignment of a nonexistent owner column to the sequence `%1'!")}, {"AsgInvalidSeqOwnerColumn", QT_TR_NOOP("Assignment of an owner column to the sequence `%1' that is not related to any table!")}, {"RefLabelInvalidIndex", QT_TR_NOOP("Reference to a label which index is out of labels list bounds!")}, {"AllocationObjectInvalidType", QT_TR_NOOP("Allocation of an object with invalid type!")}, {"AsgFunctionInvalidReturnType", QT_TR_NOOP("Assignment of a function with invalid return type to object `%1' (%2)!")}, {"AsgFunctionInvalidParameters", QT_TR_NOOP("Assignment of a function with invalid parameter(s) type(s) to object `%1' (%2)!")}, {"AsgNotAllocatedLanguage", QT_TR_NOOP("Assignment of not allocated language!")}, {"AsgInvalidLanguageObject", QT_TR_NOOP("Assignment of language object which type is invalid!")}, {"RefTypeInvalidIndex", QT_TR_NOOP("Reference to data type with an index outside the capacity of data types list!")}, {"AsgNullTypeObject", QT_TR_NOOP("Assignment of a null type to object `%1' (%2)!")}, {"AsgInvalidTypeObject", QT_TR_NOOP("Assignment of invalid type to the object!")}, {"AsgEmptyDirectoryName", QT_TR_NOOP("Assignment of an empty directory to object `%1' (%2)!")}, {"ObtTypesInvalidQuantity", QT_TR_NOOP("Obtaining types with invalid quantity!")}, {"InsDuplicatedItems", QT_TR_NOOP("Insertion of item which already exists in the attributes list of the type!")}, {"InsInvalidTypeAttribute", QT_TR_NOOP("Insertion of invalid item in the attributes list of the type!")}, {"InsDuplicatedEnumerationItem", QT_TR_NOOP("Insertion of item which already exists in the enumarations list of the type!")}, {"InsInvalidEnumerationItem", QT_TR_NOOP("Insertion of invalid item in the enumerations list of the type!")}, {"RefAttributeInvalidIndex", QT_TR_NOOP("Reference to an attribute which index is out of the attributes list bounds!")}, {"RefEnumerationInvalidIndex", QT_TR_NOOP("Reference to an enumeration which index is out of the enumerations list bounds!")}, {"AsgInvalidTypeConfiguration", QT_TR_NOOP("Assignment of invalid configuration to the type!")}, {"AsgInvalidOperatorArguments", QT_TR_NOOP("Assignment of an operator which input type count is invalid to aggregate function!")}, {"AsgInvalidOperatorTypes", QT_TR_NOOP("Assignment of an operator which types of arguments is invalid!")}, {"AsgReservedName", QT_TR_NOOP("Assignment of system reserved name to the object `%1' (%2)!")}, {"AsgFunctionInvalidConfiguration", QT_TR_NOOP("One function with invalid configuration is been used by the object `%1' (%2)!")}, {"AsgInvalidSupportStrategyNumber", QT_TR_NOOP("Assignment of an invalid strategy/support number to an operator class element!")}, {"InsDuplicatedElement", QT_TR_NOOP("Insertion of element which already exists in the element list!")}, {"RefElementInvalidIndex", QT_TR_NOOP("Reference to an element which index is out of element list bounds!")}, {"RefObjectInvalidIndex", QT_TR_NOOP("Reference to an object which index is out of object list bounds!")}, {"RemNotAllocatedObject", QT_TR_NOOP("Removal of an object not allocated!")}, {"RemDirectReference", QT_TR_NOOP("The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4)!")}, {"RemInderectReference", QT_TR_NOOP("The object `%1' (%2) can not be removed because it is being referenced by object `%3' (%4) that belongs to `%5' (%6)!")}, {"OprObjectInvalidType", QT_TR_NOOP("Operation with object(s) which type(s) is invalid!")}, {"RefObjectInvalidType", QT_TR_NOOP("Reference to object with invalid type!")}, {"OprNotAllocatedObject", QT_TR_NOOP("Operation with object not allocated!")}, {"InvLinkTablesNoPrimaryKey", QT_TR_NOOP("The creation of the relationship `%1' between the table `%2' and `%3' can not be done because one does not have a primary key. If the relationship is of the type n-n both tables must have primary keys!")}, {"NotImplementedRelationshipType", QT_TR_NOOP("The relationship of the type 1-1 where both tables are mandatory participation is not implemented because it requires fusion between the tables that breaks the modeling done by the user!")}, {"AsgInvalidExpressionObject", QT_TR_NOOP("Assignment of an invalid expression to the object!")}, {"AsgExistingPrimaryKeyTable", QT_TR_NOOP("Assignment of a primary key to a table which already has one!")}, {"InvIdentifierRelationship", QT_TR_NOOP("Identifier relationship can not be created for a self relationship, relationships of the type n-n, copy or generalization!")}, {"InvCopyRelationshipDuplicCols", QT_TR_NOOP("Unable to create a copy relationship because the column `%1' in table `%2' already exists in table `%3'!")}, {"InvInheritRelationshipIncompCols", QT_TR_NOOP("Unable to create the generalization relationship because the column `%1' in table `%2' can not be merged with the column `%3' of table `%4' because they have incompatible types!")}, {"InvInheritRelationshipIncompConstrs", QT_TR_NOOP("Unable to create the generalization relationship because the constraint `%1' in table `%2' can not be merged with the constraint `%3' of table `%4' due to their incompatible composition!")}, {"AsgObjectInvalidRelationshipType", QT_TR_NOOP("An attribute can not be added to a copy, generalization or partitioning relationship!")}, {"AsgForeignKeyRelationship", QT_TR_NOOP("A foreign key can not be added to a relationship because is created automatically when this is connected!")}, {"RefObjectInexistsModel", QT_TR_NOOP("The object `%1' (%2) is referencing the object `%3' (%4) which was not found in the model!")}, {"RefUserTypeInexistsModel", QT_TR_NOOP("Reference to an user-defined data type that not exists in the model!")}, {"AsgInvalidMaxSizeOpList", QT_TR_NOOP("Assignment of invalid maximum size to operation list!")}, {"FileDirectoryNotWritten", QT_TR_NOOP("Unable to write the file or directory `%1'! Make sure that the path exists and the user has write permissions over it!")}, {"FileNotWrittenInvalidDefinition", QT_TR_NOOP("Unable to write the file `%1' due to one or more errors in the definition generation process!")}, {"InsDuplicatedRelationship", QT_TR_NOOP("There is already a relationship between `%1' (%2) and `%3' (%4) in the model! When using relationships of the type generalization, copy and one-to-one there can't be other relationships linked to the pair of tables.")}, {"InsRelationshipRedundancy", QT_TR_NOOP("The configuration of the relationship `%1' generates a redundancy between the relationships `%2'. Redundancy on identifier or generalization/copy relationships are not accepted since they result in incorrect column spreading making the model inconsistent!")}, {"RemInvalidatedObjects", QT_TR_NOOP("One or more objects were invalidated and automatically removed because they were referencing table columns which were included through relationships and which no longer exists due to disconnection of relationships or exclusion of such generated columns!")}, {"InvPrimaryKeyAllocation", QT_TR_NOOP("The primary key `%1' can only be allocated if declared within a block of code that defines a table or relationship!")}, {"RefInvalidPrivilegeType", QT_TR_NOOP("Reference to an invalid privilege type!")}, {"InsDuplicatedRolePermission", QT_TR_NOOP("Insertion of a role which already exists in the role list of the permission!")}, {"AsgInvalidPrivilegeObject", QT_TR_NOOP("Assignment of privilege incompatible with the type of object referenced by permission!")}, {"AsgDuplicatedPermission", QT_TR_NOOP("There is already a permission on object `%1' (%2) which has one or more equal roles from those present on permission to be assigned to the object!")}, {"PermissionRefInexistObject", QT_TR_NOOP("A permission is referencing the object `%1' (%2) which was not found in the model!")}, {"InvObjectAllocationNoSchema", QT_TR_NOOP("The object `%1' (%2) can not be created because its not being assigned to any schema!")}, {"AsgTablespaceDuplicatedDirectory", QT_TR_NOOP("The tablespace `%1' can not be inserted into the model because it points to the same directory as the tablespace `%2'!")}, {"AsgInvalidSequenceTypeArray", QT_TR_NOOP("It is not possible to create arrays sequences (dimension >= 1)! PostgreSQL does not yet implement this feature!")}, {"AsgSourceCodeFuncCLanguage", QT_TR_NOOP("The function `%1' can not get a source code as a definition because its language is set to C. Use the attributes symbol and dynamic library instead!")}, {"AsgRefLibraryFuncLanguageNotC", QT_TR_NOOP("The function `%1' can have the attributes symbol and dynamic library configured only if the language is set to C. For all other cases you must specify a source code that defines it in the DBMS!")}, {"AsgInvalidCommutatorOperator", QT_TR_NOOP("The operator `%1' can not be assigned as a commutator of operator `%2' because it has incompatible settings!")}, {"AsgInvalidNegatorOperator", QT_TR_NOOP("The operator `%1' can not be assigned as negator of operator `%2' because it has incompatible settings!")}, {"InvUserTypeSelfReference", QT_TR_NOOP("The type `%1' can not self refer in the attributes `element' or `copy type' or be used as a data type of an attribute in the configuration of a composite type!")}, {"AsgInvalidElementType", QT_TR_NOOP("Assignment of invalid element to type `%1'!")}, {"AsgInvalidAlignmentType", QT_TR_NOOP("Assignment of invalid alignment to type `%1'!")}, {"AsgInvalidNameTableRelNN", QT_TR_NOOP("Assignment of invalid name to the table generated from N-N relationship!")}, {"InvUseSpecialPrimaryKey", QT_TR_NOOP("The relationship `%1' can not make use of the special primary key because it is marked as identifier or it is a self relationship!")}, {"OprRelationshipAddedObject", QT_TR_NOOP("The object `%1' (%2) can not be edited or deleted because it was automatically included through a relationship! If the object is an attribute or constraint the modifications must be done on the relationship editing form.")}, {"RemProtectedObject", QT_TR_NOOP("The object `%1' (%2) can not be deleted because it is protected!")}, {"InvRedeclarationGroup", QT_TR_NOOP("The group `%1' has already been declared earlier!")}, {"InvGroupDeclaration", QT_TR_NOOP("The group `%1' can not be built in the groups declaration block (%2)!")}, {"DefNotDeclaredGroup", QT_TR_NOOP("The group `%1' was built but not declared in the groups declaration block (%2)!")}, {"DefEmptyGroup", QT_TR_NOOP("The group `%1' can not be built without possessing child elements!")}, {"DefDuplicatedGroup", QT_TR_NOOP("The group `%1' can not be built once more because this was done in previous blocks!")}, {"InvGroupDeclarationNotDefined", QT_TR_NOOP("The group `%1' has been declared but not built!")}, {"RefColObjectTabInvalidIndex", QT_TR_NOOP("Reference to a column of the objects table with invalid index!")}, {"RefRowObjectTabInvalidIndex", QT_TR_NOOP("Reference to a row of the objects table with invalid index!")}, {"OprReservedObject", QT_TR_NOOP("The object `%1' (%2) can not be manipulated because it is reserved to PostgreSQL! This object is present in the database model only as a reference!")}, {"InvFuncConfigInvalidatesObject", QT_TR_NOOP("The new configuration of the function invalidates the object `%1' (%2)! In this case it is needed to undo the relationship between the affected object and function in order to the new configuration to take effect!")}, {"InvSQLScopeViewReference", QT_TR_NOOP("A view reference should be used in at least one of these SQL scopes: View Definition, SELECT, FROM, WHERE or GROUP/HAVING!")}, {"InvConstratintNoColumns", QT_TR_NOOP("Constraints like primary key, foreign key or unique must have at least one column related to them! For foreign keys must be selected, in addition, the referenced columns!")}, {"ConfigurationNotLoaded", QT_TR_NOOP("Unable to load the configuration file `%1'! Please check if file exists in its folder and/or if it is not corrupted!")}, {"DefaultConfigNotRestored", QT_TR_NOOP("Could not find the default settings file `%1'! To restore default settings check the existence of the file and try again!")}, {"ExportFailure", QT_TR_NOOP("The export process failed due to an error triggered by the PostgreSQL server in an attempt to execute a SQL command. For more details about the error check the exception stack!\n\n** Executed SQL command: **\n\n%1")}, {"PluginNotLoaded", QT_TR_NOOP("Could not load the plugin `%1' from the library `%2'! Message returned by plugin manager: `%3'")}, {"PluginsNotLoaded", QT_TR_NOOP("One or more plugins were not activated due to errors during the loading process! Check the exception stack for more details.")}, {"InvalidSyntax", QT_TR_NOOP("Invalid syntax in file `%1', line %2, column %3!")}, {"InvalidInstruction", QT_TR_NOOP("Invalid instruction `%1' on file `%2', line %3, column %4!")}, {"UnkownAttribute", QT_TR_NOOP("Unknown attribute `%1' in file `%2', line %3, column %4!")}, {"InvalidMetacharacter", QT_TR_NOOP("Invalid metacharacter `%1' in file `%2', line %3, column %4!")}, {"InvalidOperatorInExpression", QT_TR_NOOP("Invalid operator `%1' in comparison expression, file `%2', line %3, column %4!")}, {"UndefinedAttributeValue", QT_TR_NOOP("Attribute `%1' with an undefined value in file `%2', line %3, column %4!")}, {"InvalidAttribute", QT_TR_NOOP("Attribute `%1' with an invalid name in file `%2', line %3, column %4!")}, {"AsgEmptyXMLBuffer", QT_TR_NOOP("Assignment of empty XML buffer to parser!")}, {"FileDirectoryNotAccessed", QT_TR_NOOP("Could not access the file or directory `%1'! Make sure that it exists or if the user has access permissions on it!")}, {"AsgEmptyDTDFile", QT_TR_NOOP("Assignment of empty DTD file name!")}, {"AsgEmptyDTDName", QT_TR_NOOP("Assignment of empty name to the DTD declaration!")}, {"LibXMLError", QT_TR_NOOP("Error while interpreting XML buffer at line %1 column %2.\nMessage generated by the parser: %3. %4")}, {"OprNotAllocatedElementTree", QT_TR_NOOP("Operation on unallocated element tree! It is necessary to load the XML parser buffer and interpret it so that the tree is generated!")}, {"InvModelFileNotLoaded", QT_TR_NOOP("Could not load file `%1'. The same appears to be inconsistent or one of its dependencies (DTD files) has errors or is missing!")}, {"OprNotAllocatedElement", QT_TR_NOOP("Operation with unallocated tree element!")}, {"OprInexistentElement", QT_TR_NOOP("Operation with element which does not exists in the element tree currently loaded!")}, {"AsgInvalidConnParameter", QT_TR_NOOP("Assignment of a value to an invalid connection parameter!")}, {"OprNotAllocatedConnection", QT_TR_NOOP("Operation on connection not established!")}, {"ConnectionNotConfigured", QT_TR_NOOP("Attempt to connect without define configuration parameters!")}, {"ConnectionAlreadyStablished", QT_TR_NOOP("Attempt to start a connection already stablished!")}, {"ConnectionNotStablished", QT_TR_NOOP("Could not connect to the database.\nMessage returned: `%1'")}, {"AsgNotAllocatedSQLResult", QT_TR_NOOP("Assignment of not allocated SQL command result!")}, {"IncomprehensibleDBMSResponse", QT_TR_NOOP("Unable to allocate the result of the SQL command because the response from the DBMS was not understood by the client!")}, {"DBMSFatalError", QT_TR_NOOP("Unable to allocate command result for the SQL because the server has generated a fatal error!\nMessage returned by the DBMS: `%1'")}, {"RefTupleColumnInvalidIndex", QT_TR_NOOP("Reference to a column of tuple with invalid index!")}, {"RefTupleColumnInvalidName", QT_TR_NOOP("Reference to a column of tuple with invalid name!")}, {"RefInvalidTuple", QT_TR_NOOP("Reference to a tuple with an invalid index or the result is empty (no tuples)!")}, {"RefInvalidTupleColumn", QT_TR_NOOP("Reference to a column of a tuple which was not yet initialized (tuple navigation not started)!")}, {"SQLCommandNotExecuted", QT_TR_NOOP("Could not execute the SQL command.\n Message returned: `%1'")}, {"AsgInvalidViewDefExpression", QT_TR_NOOP("Invalid use of a view reference as whole SQL definition! The assigned reference must be an expression!")}, {"AsgSecondViewDefExpression", QT_TR_NOOP("Assignment of a second definition expression to the view!")}, {"MixingViewDefExprsReferences", QT_TR_NOOP("It is not possible mix ordinary references (SELECT-FROM, FROM-WHERE, After WHERE) with references used as view SQL definition!")}, {"AsgInvalidCollationObject", QT_TR_NOOP("Assignment of collation object which type is invalid!")}, {"UnsupportedPKColsAddedByRel", QT_TR_NOOP("At the moment pgModeler does not support the creation of primary keys which some columns were generated by relationship connection. To create primary keys with this feature you can use the field `Identifier' or the tab `Primary key' on relationship editing form!")}, {"EmptyLCCollationAttributes", QT_TR_NOOP("Collations must be created at least with attributes LC_COLLATE and LC_CTYPE defined!")}, {"ObjectReferencingItself", QT_TR_NOOP("The object `%1' (%2) cannot reference itself! This operation is not permitted for this kind of object!")}, {"AsgInvalidOpFamilyOpClassElem", QT_TR_NOOP("Only operator families which uses `btree' as indexing method are accepted by operator class elements!")}, {"RefInvalidLikeOptionType", QT_TR_NOOP("Reference to an invalid copy table option!")}, {"InvCopyRelTableDefined", QT_TR_NOOP("The copy relationship between the tables `%1' and `%2' cannot be done because the first one already copies attributes from `%3'! Tables can have only one copy table!")}, {"InvPartRelPartitionedDefined", QT_TR_NOOP("The paritioning relationship between the tables `%1' and `%2' cannot be done because the first one is already a partition of the table `%3'! Partition tables can be participating of only one partition hierarchy at a time!")}, {"InvRelTypeForPatitionTables", QT_TR_NOOP("The relationship between the tables `%1' and `%2' can't be created because one of the entities is part of a partitioning hierachy! The table `%3' can't be used in `generalization', `copy' and `one-to-one' relationships. In `one-to-many' and `many-to-many' relationships the mentioned table can't be referenced by the generated foreign key(s).")}, {"InvTableTriggerInsteadOfFiring", QT_TR_NOOP("The INSTEAD OF mode cannot be used on triggers that belongs to tables! This is available only for view triggers!")}, {"InvUsageTruncateOnTrigger", QT_TR_NOOP("The TRUNCATE event can only be used when the trigger executes for each statement and belongs to a table!")}, {"InvUsageInsteadOfOnTrigger", QT_TR_NOOP("The INSTEAD OF mode cannot be used on view triggers that executes for each statement!")}, {"InvConstrTriggerNotAfterRow", QT_TR_NOOP("Constraint triggers can only be executed on AFTER events and for each row!")}, {"InvUsageAfterBeforeViewTrigger", QT_TR_NOOP("A view trigger cannot be AFTER/BEFORE when it executes for each row!")}, {"InvUsageInsteadOfUpdateTrigger", QT_TR_NOOP("A trigger cannot make reference to columns when using INSTEAD OF mode and UPDATE event!")}, {"AsgColumnNoParent", QT_TR_NOOP("Assignment of a column which has no parent table to the object `%1' (%2)!")}, {"InvUseConstraintTriggerAttribs", QT_TR_NOOP("Only constraint triggers can be deferrable or reference another table!")}, {"RefInvalidFunctionIdTypeConfig", QT_TR_NOOP("Reference to a function id which is incompatible with the user define type configuration!")}, {"AsgInvalidOpClassObject", QT_TR_NOOP("The operator class assigned to the object `%1' (%2) must use `btree' as indexing method!")}, {"InvPostgreSQLVersion", QT_TR_NOOP("Unsupported PostgreSQL version (%1) detected! Valid versions are between %2 and %3.")}, {"ValidationFailure", QT_TR_NOOP("The validation process failed due to an error triggered by the validation helper. For more details about the error check the exception stack!")}, {"ExtensionHandlingTypeImmutable", QT_TR_NOOP("The extension `%1' is registered as a data type and cannot have the attribute `handles datatype' modified!")}, {"InvAllocationFKRelationship", QT_TR_NOOP("The fk relationship `%1' cannot be created because the foreign-key that represents it was not created on table `%2'!")}, {"AsgInvalidNamePattern", QT_TR_NOOP("Assignement of an invalid object name pattern to the relationship `%1'!")}, {"RefInvalidNamePatternId", QT_TR_NOOP("Reference to an invalid object name pattern id on the relationship `%1'!")}, {"InvUsageVariadicParamMode", QT_TR_NOOP("Invalid use of variadic parameter mode! This mode can be used only with an array or \"any\" data type!")}, {"MixingIncompExportOptions", QT_TR_NOOP("Mixing incompatibles DBMS export modes: `ignore object duplications', `drop database' or `drop objects' cannot be used with `simulate export'!")}, {"MixingIncompDropOptions", QT_TR_NOOP("Mixing incompatibles DROP options: `drop database' and `drop objects' cannot be used at the same time!")}, {"InvIdSwapSameObject", QT_TR_NOOP("Invalid object id swapping operation! The objects involved are the same!")}, {"InvIdSwapInvalidObjectType", QT_TR_NOOP("Invalid object id swapping operation! The database itself, tablespaces or roles cannot have the ids swapped!")}, {"AsgWidgetAlreadyHasParent", QT_TR_NOOP("The widget already has a parent and cannot be assigned to a different object!")}, {"ObjectNotImported", QT_TR_NOOP("The object `%1' (%2), oid `%3', could not be imported due to one or more errors! Check the exception stack for more details. `HINT:' if the object somehow references objects in `pg_catalog' or `information_schema' consider enable the importing of system objects.")}, {"ModelFileNotLoaded", QT_TR_NOOP("Could not load the database model file `%1'. Check the error stack to see details. Try to run `pgmodeler-cli --fix-model' in order to correct the structure of the file if that is the case.")}, {"InvColumnTableType", QT_TR_NOOP("The column `%1' cannot reference it's parent table `%2' as data type!")}, {"OprInvalidElementId", QT_TR_NOOP("Operation with an invalid element id `%1'!")}, {"RefInvalidElementColorId", QT_TR_NOOP("Reference to an invalid color id `%1' for element `%2'!")}, {"AsgInvalidObjectType", QT_TR_NOOP("Assignment of an invalid object to `%1' (%2)! The assigned object must be of type `%3'.")}, {"IncompColumnTypeForSequence", QT_TR_NOOP("The sequence `%1' can't be assigned to the column `%2' because the data type of the latter is incompatible. The type used must be an integer one!")}, {"InvUsageTempNamesExportOption", QT_TR_NOOP("The option to generate temporary object names can only be used in simulation mode!")}, {"InvConversionIntegerToSerial", QT_TR_NOOP("It's not possible convert the type of the column `%1' to serial! It must have an `integer' based type and its default value must be a call to `nextval(seq_name::regclass)' function or a sequence object must be directly assigned to the column!")}, {"AsgInvalidEventTriggerVariable", QT_TR_NOOP("Could not assign the variable `%1' to event trigger's filter. Currently, PostgreSQL supports only the `TAG' variable!")}, {"RowDataNotManipulated", QT_TR_NOOP("Could not perform the `%1' operation on `%2' using the data on row `%3'! All changes were rolled back. \n\n ** Returned error ** \n\n%4")}, {"MalformedUnescapedValue", QT_TR_NOOP("Malformed unescaped value on row `%1' column `%2'!")}, {"UndoRedoOperationInvalidObject", QT_TR_NOOP("Trying to undo/redo an invalid operation over an object that does not exists anymore or can't be handled! The operation history will be cleaned up.")}, {"RequiredFieldsNotFilled", QT_TR_NOOP("The object `%1' (%2) can't be handled because some needed fields are not set! Please, make sure to fill at least the requires fields in order to properly create or update the object.")}, {"InvRelationshipIdSwap", QT_TR_NOOP("A relationship can only be swapped by other object of the same kind!")}, {"InvInheritParentTableNotFound", QT_TR_NOOP("A parent table of `%1' which OID is `%2' was not found in the set of imported objects!")}, {"AsgEnumInvalidChars", QT_TR_NOOP("The enumeration `%1' can't be assigned to the type `%2' because contains invalid characters!")}, {"AsgEnumLongName", QT_TR_NOOP("The enumeration `%1' can't be assigned to the type `%2' because is too long!")}, {"ConnectionTimeout", QT_TR_NOOP("The connection was idle for too long and was automatically closed!")}, {"ConnectionBroken", QT_TR_NOOP("The connection was unexpectedly closed by the database server `%1' at port `%2'!")}, {"DropCurrentDBDefault", QT_TR_NOOP("Failed to drop the database `%1' because it is defined as the default database for the connection `%2'!")}, {"NullPrimaryKeyColumn", QT_TR_NOOP("The column `%1' must be `NOT NULL' because it composes the primary key of the table `%2'. You need to remove the column from the mentioned contraint in order to disable the `NOT NULL' on it!")}, {"InvalidIdentityColumn", QT_TR_NOOP("The identity column `%1' has an invalid data type! The data type must be `smallint', `integer' or `bigint'.")}, {"RefInvalidAffectedCommand", QT_TR_NOOP("Reference to an invalid affected command in policy `%1'!")}, {"RefInvalidSpecialRole", QT_TR_NOOP("Reference to an invalid special role in policy `%1'!")}, {"InvColumnCountPartRel", QT_TR_NOOP("Unable to create a partition relationship because the partion table `%1' is not empty or has columns that are not present on the partitioned table `%2'!")}, {"InvPartitioningTypePartRel", QT_TR_NOOP("Unable to create a partition relationship between the tables `%1' (partition) and `%2' (partitioned) because no partitioning type is defined on the latter!")}, {"InvPartitionKeyCount", QT_TR_NOOP("Invalid amount of partition keys being assinged to the table `%1'! Multiples partition keys are allowed only on `HASH' and `RANGE' partitioning strategies.")}, {"PartKeyObjectInexistsModel", QT_TR_NOOP("A partition key of the table `%1' is referencing the object `%3' (%4) which was not found in the model!")}, {"AsgInvalidColumnPartitionKey", QT_TR_NOOP("The column `%1' can't be assigned to a partition key because it was created by a relatinship and this kind of operation is not yet supported! HINT: create the column manually on the table and then create the partition key using it.")}, {"RemColumnRefByPartitionKey", QT_TR_NOOP("The column `%1' on the table `%2' can't be removed because it is being referenced by one or more patition keys!")}, {"AsgOptionInvalidName", QT_TR_NOOP("Assignment of an option to the object with an invalid name!")}, {"AsgInvalidNameObjReference", QT_TR_NOOP("Assignment of an invalid name to the object reference!")}, {"AsgNotAllocatedObjectReference", QT_TR_NOOP("Assignment of a not allocated object to the object reference!")}, {"InsDuplicatedObjectReference", QT_TR_NOOP("The object reference name `%1' is already defined!")}, {"ModelFileInvalidSize", QT_TR_NOOP("A zero-byte file was detected while saving to `%1'. In order to avoid data loss the original contents of the file prior to the last saving was restored and a security copy kept on `%2'. You can copy that backup file to a safe place as a last resort to avoid the complete data loss! Note that the backup file will be erased when the application is closed.")}, {"AsgInvalidObjectForeignTable", QT_TR_NOOP("The object `%1' (%2) can't be assigned to the foreign table `%3' because it's unsupported! Foreign tables only accepts columns, check constraints and triggers.")}, {"InvRelTypeForeignTable", QT_TR_NOOP("The creation of the relationship `%1' between the tables `%2' and `%3' can't be done because one of the entities is a foreign table. Foreign tables can only be part of a inheritance, copy or partitioning relationship!")}, {"InvCopyRelForeignTable", QT_TR_NOOP("The creation of the copy relationship `%1' between the tables `%2' and `%3' can't be done because a foreign table is not allowed to copy table columns!")}, {"InvDataDictDirectory", QT_TR_NOOP("Failed to save the data dictionary into `%1'! Make sure that the provided path points to a directory or if the user has write permissions over it!")} }; Exception::Exception(void) { configureException(QString(),ErrorCode::Custom,QString(),QString(),-1,QString()); } Exception::Exception(const QString &msg, const QString &method, const QString &file, int line, Exception *exception, const QString &extra_info) { configureException(msg,ErrorCode::Custom, method, file, line, extra_info); if(exception) addException(*exception); } Exception::Exception(ErrorCode error_code, const QString &method, const QString &file, int line, Exception *exception, const QString &extra_info) { /* Because the Exception class is not derived from QObject the function tr() is inefficient to translate messages so the translation method is called directly from the application specifying the context (Exception) in the ts file and the text to be translated */ configureException(QApplication::translate("Exception",messages[enum_cast(error_code)][ErrorMessage].toStdString().c_str(),"", -1), error_code, method, file, line, extra_info); if(exception) addException(*exception); } Exception::Exception(const QString &msg, ErrorCode error_code, const QString &method, const QString &file, int line, Exception *exception, const QString &extra_info) { configureException(msg,error_code, method, file, line, extra_info); if(exception) addException(*exception); } Exception::Exception(ErrorCode error_code, const QString &method, const QString &file, int line, vector &exceptions, const QString &extra_info) { vector::iterator itr, itr_end; /* Because the Exception class is not derived from QObject the function tr() is inefficient to translate messages so the translation method is called directly from the application specifying the context (Exception) in the ts file and the text to be translated */ configureException(QApplication::translate("Exception",messages[enum_cast(error_code)][ErrorMessage].toStdString().c_str(),"",-1), error_code, method, file, line, extra_info); itr=exceptions.begin(); itr_end=exceptions.end(); while(itr!=itr_end) { addException((*itr)); itr++; } } Exception::Exception(const QString &msg, const QString &method, const QString &file, int line, vector &exceptions, const QString &extra_info) { vector::iterator itr, itr_end; configureException(msg,ErrorCode::Custom, method, file, line, extra_info); itr=exceptions.begin(); itr_end=exceptions.end(); while(itr!=itr_end) { addException((*itr)); itr++; } } Exception::Exception(const QString &msg, ErrorCode error_code, const QString &method, const QString &file, int line, vector &exceptions, const QString &extra_info) { vector::iterator itr=exceptions.begin(); configureException(msg,error_code, method, file, line, extra_info); while(itr!=exceptions.end()) { addException((*itr)); itr++; } } void Exception::configureException(const QString &msg, ErrorCode error_code, const QString &method, const QString &file, int line, const QString &extra_info) { this->error_code=error_code; this->error_msg=msg; this->method=method; this->file=file; this->line=line; this->extra_info=QString(extra_info); } QString Exception::getErrorMessage(void) { return(error_msg); } QString Exception::getErrorMessage(ErrorCode error_code) { if(enum_cast(error_code) < ErrorCount) /* Because the Exception class is not derived from QObject the function tr() is inefficient to translate messages so the translation method is called directly from the application specifying the context (Exception) in the ts file and the text to be translated */ return(QApplication::translate("Exception", messages[enum_cast(error_code)][ErrorMessage].toStdString().c_str(), "", -1)); else return(QString()); } QString Exception::getErrorCode(ErrorCode error_code) { if(enum_cast(error_code) < ErrorCount) return(messages[enum_cast(error_code)][ErrorCodeId]); else return(QString()); } QString Exception::getMethod(void) { return(method); } QString Exception::getFile(void) { return(file); } QString Exception::getLine(void) { return(QString("%1").arg(line)); } ErrorCode Exception::getErrorCode(void) { return(error_code); } QString Exception::getExtraInfo(void) { return(extra_info); } void Exception::addException(Exception &exception) { vector::iterator itr, itr_end; itr=exception.exceptions.begin(); itr_end=exception.exceptions.end(); while(itr!=itr_end) { this->exceptions.push_back(Exception(itr->error_msg,itr->error_code, itr->method,itr->file,itr->line,nullptr,itr->extra_info)); itr++; } exception.exceptions.clear(); this->exceptions.push_back(Exception(exception.error_msg,exception.error_code, exception.method,exception.file,exception.line,nullptr,exception.extra_info)); } void Exception::getExceptionsList(vector &list) { list.assign(this->exceptions.begin(), this->exceptions.end()); list.push_back(Exception(this->error_msg,this->error_code, this->method,this->file,this->line,nullptr,this->extra_info)); } QString Exception::getExceptionsText(void) { vector exceptions; vector::reverse_iterator itr, itr_end; unsigned idx=0, hidden_errors_cnt = 0; QString exceptions_txt; bool stack_truncated = false; //Get the generated exceptions list this->getExceptionsList(exceptions); itr=exceptions.rbegin(); itr_end=exceptions.rend(); idx = 0; if(exceptions.size() > MaximumStackSize) { hidden_errors_cnt = exceptions.size() - Exception::MaximumStackSize; stack_truncated = true; } //Append all usefull information about the exceptions on the string while(itr!=itr_end) { exceptions_txt+=QString("[%1] %2 (%3)\n").arg(idx).arg(itr->getFile()).arg(itr->getLine()); exceptions_txt+=QString(" %1\n").arg(itr->getMethod()); exceptions_txt+=QString(" [%1] %2\n").arg(Exception::getErrorCode(itr->getErrorCode())).arg(itr->getErrorMessage()); if(!itr->getExtraInfo().isEmpty()) exceptions_txt+=QString(" ** %1\n\n").arg(itr->getExtraInfo()); else exceptions_txt+=QString("\n"); itr++; idx++; if(stack_truncated && idx >= Exception::MaximumStackSize) { exceptions_txt += QString(QT_TR_NOOP("** Another %1 error(s) were suppressed due to stacktrace size limits.\n\n")).arg(hidden_errors_cnt); break; } } return(exceptions_txt); } pgmodeler-0.9.2/libutils/src/exception.h000066400000000000000000000257371360462764600203210ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libutils \class Exception \brief Catalogs all the errors raised by pgModeler \note Creation date: 10/07/2006 */ #ifndef EXCEPTION_H #define EXCEPTION_H #include #include "doublenan.h" #include #include #include #include #include using namespace std; //! \brief This function causes the provided enum to be converted to its underlying datatype template constexpr std::underlying_type_t enum_cast (Enum obj_type) noexcept { return(static_cast>(obj_type)); } //! \brief This enum defines the global error codes used throughout the application enum class ErrorCode: unsigned { Custom, AsgPseudoTypeColumn, AsgInvalidPrecision, AsgInvalidPrecisionTimestamp, AsgNotAllocatedColumn, RefColumnInvalidIndex, AsgNotAllocattedObject, AsgNotAllocatedSchema, AsgObjectInvalidDefinition, AsgDuplicatedObject, AsgDuplicatedObjectContainer, AsgObjectInvalidType, RemObjectInvalidType, ObtObjectInvalidType, AsgEmptyNameTableReturnType, AsgDuplicatedParameterFunction, InsDuplicatedTableReturnType, RefParameterInvalidIndex, RefInvalidTriggerEvent, AsgInvalidColumnTrigger, AsgNotAllocatedFunction, AsgInvalidTriggerFunction, AsgFunctionInvalidParamCount, AsgFunctionInvalidLanguage, AsgEventTriggerFuncInvalidLang, AsgNotAllocatedTable, RefArgumentInvalidIndex, AsgEmptyNameObject, AsgInvalidNameObject, AsgLongNameObject, AsgInvalidSchemaObject, AsgInvalidTablespaceObject, AsgTablespaceInvalidObject, AsgTablespaceInvalidConstraintType, AsgInvalidRoleObject, AsgRoleObjectInvalidType, AsgCustomSQLObjectInvalidType, RefFunctionInvalidType, RefOperatorArgumentInvalidType, RefOperatorInvalidType, AsgValueInvalidRoleOptionType, RefInvalidRoleType, InsDuplicatedRole, AsgRoleReferenceRedundancy, AsgRoleMemberItself, RefRoleInvalidIndex, InsEmptyRuleCommand, RefRuleCommandInvalidIndex, InvInheritCopyPartRelationship, AsgObjectBelongsAnotherTable, AsgSchemaSequenceDiffersTableSchema, AsgInvalidValueSequenceAttributes, AsgInvalidSequenceMinValue, AsgInvalidSequenceStartValue, AsgInvalidSequenceIncrementValue, AsgInvalidSequenceCacheValue, AsgSeqOwnerTableDifferentSchema, AsgSeqOwnerTableDifferentRole, AsgInexistentSeqOwnerColumn, AsgInvalidSeqOwnerColumn, RefLabelInvalidIndex, AllocationObjectInvalidType, AsgFunctionInvalidReturnType, AsgFunctionInvalidParameters, AsgNotAllocatedLanguage, AsgInvalidLanguageObject, RefTypeInvalidIndex, AsgNullTypeObject, AsgInvalidTypeObject, AsgEmptyDirectoryName, ObtTypesInvalidQuantity, InsDuplicatedItems, InsInvalidTypeAttribute, InsDuplicatedEnumerationItem, InsInvalidEnumerationItem, RefAttributeInvalidIndex, RefEnumerationInvalidIndex, AsgInvalidTypeConfiguration, AsgInvalidOperatorArguments, AsgInvalidOperatorTypes, AsgReservedName, AsgFunctionInvalidConfiguration, AsgInvalidSupportStrategyNumber, InsDuplicatedElement, RefElementInvalidIndex, RefObjectInvalidIndex, RemNotAllocatedObject, RemDirectReference, RemInderectReference, OprObjectInvalidType, RefObjectInvalidType, OprNotAllocatedObject, InvLinkTablesNoPrimaryKey, NotImplementedRelationshipType, AsgInvalidExpressionObject, AsgExistingPrimaryKeyTable, InvIdentifierRelationship, InvCopyRelationshipDuplicCols, InvInheritRelationshipIncompCols, InvInheritRelationshipIncompConstrs, AsgObjectInvalidRelationshipType, AsgForeignKeyRelationship, RefObjectInexistsModel, RefUserTypeInexistsModel, AsgInvalidMaxSizeOpList, FileDirectoryNotWritten, FileNotWrittenInvalidDefinition, InsDuplicatedRelationship, InsRelationshipRedundancy, RemInvalidatedObjects, InvPrimaryKeyAllocation, RefInvalidPrivilegeType, InsDuplicatedRolePermission, AsgInvalidPrivilegeObject, AsgDuplicatedPermission, PermissionRefInexistObject, InvObjectAllocationNoSchema, AsgTablespaceDuplicatedDirectory, AsgInvalidSequenceTypeArray, AsgSourceCodeFuncCLanguage, AsgRefLibraryFuncLanguageNotC, AsgInvalidCommutatorOperator, AsgInvalidNegatorOperator, InvUserTypeSelfReference, AsgInvalidElementType, AsgInvalidAlignmentType, AsgInvalidNameTableRelNN, InvUseSpecialPrimaryKey, OprRelationshipAddedObject, RemProtectedObject, InvRedeclarationGroup, InvGroupDeclaration, DefNotDeclaredGroup, DefEmptyGroup, DefDuplicatedGroup, InvGroupDeclarationNotDefined, RefColObjectTabInvalidIndex, RefRowObjectTabInvalidIndex, OprReservedObject, InvFuncConfigInvalidatesObject, InvSQLScopeViewReference, InvConstratintNoColumns, ConfigurationNotLoaded, DefaultConfigNotRestored, ExportFailure, PluginNotLoaded, PluginsNotLoaded, InvalidSyntax, InvalidInstruction, UnkownAttribute, InvalidMetacharacter, InvalidOperatorInExpression, UndefinedAttributeValue, InvalidAttribute, AsgEmptyXMLBuffer, FileDirectoryNotAccessed, AsgEmptyDTDFile, AsgEmptyDTDName, LibXMLError, OprNotAllocatedElementTree, InvModelFileNotLoaded, OprNotAllocatedElement, OprInexistentElement, AsgInvalidConnParameter, OprNotAllocatedConnection, ConnectionNotConfigured, ConnectionAlreadyStablished, ConnectionNotStablished, AsgNotAllocatedSQLResult, IncomprehensibleDBMSResponse, DBMSFatalError, RefTupleColumnInvalidIndex, RefTupleColumnInvalidName, RefInvalidTuple, RefInvalidTupleColumn, SQLCommandNotExecuted, AsgInvalidViewDefExpression, AsgSecondViewDefExpression, MixingViewDefExprsReferences, AsgInvalidCollationObject, UnsupportedPKColsAddedByRel, EmptyLCCollationAttributes, ObjectReferencingItself, AsgInvalidOpFamilyOpClassElem, RefInvalidLikeOptionType, InvCopyRelTableDefined, InvPartRelPartitionedDefined, InvRelTypeForPatitionTables, InvTableTriggerInsteadOfFiring, InvUsageTruncateOnTrigger, InvUsageInsteadOfOnTrigger, InvConstrTriggerNotAfterRow, InvUsageAfterBeforeViewTrigger, InvUsageInsteadOfUpdateTrigger, AsgColumnNoParent, InvUseConstraintTriggerAttribs, RefInvalidFunctionIdTypeConfig, AsgInvalidOpClassObject, InvPostgreSQLVersion, ValidationFailure, ExtensionHandlingTypeImmutable, InvAllocationFKRelationship, AsgInvalidNamePattern, RefInvalidNamePatternId, InvUsageVariadicParamMode, MixingIncompExportOptions, MixingIncompDropOptions, InvIdSwapSameObject, InvIdSwapInvalidObjectType, AsgWidgetAlreadyHasParent, ObjectNotImported, ModelFileNotLoaded, InvColumnTableType, OprInvalidElementId, RefInvalidElementColorId, AsgInvalidObjectType, IncompColumnTypeForSequence, InvUsageTempNamesExportOption, InvConversionIntegerToSerial, AsgInvalidEventTriggerVariable, RowDataNotManipulated, MalformedUnescapedValue, UndoRedoOperationInvalidObject, RequiredFieldsNotFilled, InvRelationshipIdSwap, InvInheritParentTableNotFound, AsgEnumInvalidChars, AsgEnumLongName, ConnectionTimeout, ConnectionBroken, DropCurrentDBDefault, NullPrimaryKeyColumn, InvalidIdentityColumn, RefInvalidAffectedCommand, RefInvalidSpecialRole, InvColumnCountPartRel, InvPartitioningTypePartRel, InvPartitionKeyCount, PartKeyObjectInexistsModel, AsgInvalidColumnPartitionKey, RemColumnRefByPartitionKey, AsgOptionInvalidName, AsgInvalidNameObjReference, AsgNotAllocatedObjectReference, InsDuplicatedObjectReference, ModelFileInvalidSize, AsgInvalidObjectForeignTable, InvRelTypeForeignTable, InvCopyRelForeignTable, InvDataDictDirectory }; class Exception { private: static constexpr unsigned ErrorCount=250; /*! \brief Stores other exceptions before raise the 'this' exception. This structure can be used to simulate a stack trace to improve the debug */ vector exceptions; //! \brief Stores the error messages and codes (names of errors) in string format static QString messages[ErrorCount][2]; //! \brief Constants used to access the error details static constexpr unsigned ErrorCodeId=0, ErrorMessage=1; //! \brief Error type related to the exception ErrorCode error_code; //! \brief Formated error message QString error_msg, /*! \brief Holds the class name and method which was triggered the exception. For this to be possible, at the time instantiation of this class the G++ macro __ PRETTY_FUNCTION__ must be passed. This macro contains the format [RETURN][CLASS]::[METHOD][PARAMS] */ method, //! \brief File where the exception was generated (Macro __ FILE__) file, /*! \brief Additional information (optional) may store any other type of information that is interesting on attempt to resolve the error */ extra_info; //! \brief Line of file where the exception were generated (Macro __LINE__) int line; //! \brief Configures the basic attributes of exception void configureException(const QString &msg, ErrorCode error_code, const QString &method, const QString &file, int line, const QString &extra_info); //! \brief Adds a exception to the list of exceptions void addException(Exception &exception); public: static unsigned constexpr MaximumStackSize = 50; Exception(void); Exception(const QString &msg, const QString &method, const QString &file, int line, Exception *exception=nullptr, const QString &extra_info=QString()); Exception(const QString &msg, const QString &method, const QString &file, int line, vector &exceptions, const QString &extra_info=QString()); Exception(const QString &msg, ErrorCode error_code, const QString &method, const QString &file, int line, Exception *exception=nullptr, const QString &extra_info=QString()); Exception(const QString &msg, ErrorCode error_code, const QString &method, const QString &file, int line, vector &exceptions, const QString &extra_info=QString()); Exception(ErrorCode error_code, const QString &method, const QString &file, int line, Exception *exception=nullptr, const QString &extra_info=QString()); Exception(ErrorCode error_code, const QString &method, const QString &file, int line, vector &exceptions, const QString &extra_info=QString()); ~Exception(void){} QString getErrorMessage(void); static QString getErrorMessage(ErrorCode error_code); static QString getErrorCode(ErrorCode error_code); QString getMethod(void); QString getFile(void); QString getLine(void); ErrorCode getErrorCode(void); QString getExtraInfo(void); //! \brief Gets the full exception stack void getExceptionsList(vector &list); //! \brief Gets the exception stack in a formatted text QString getExceptionsText(void); }; #endif pgmodeler-0.9.2/libutils/src/globalattributes.cpp000066400000000000000000000154571360462764600222230ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "globalattributes.h" #include #include namespace GlobalAttributes { const QString PgModelerVersion=QString("0.9.2") /* Appending the snapshot build number to the version number * when the external variable SNAPSHOT_BUILD is defined */ #if defined(SNAPSHOT_BUILD) + QString("_snapshot") + BUILDNUM #endif , /****/ PgModelerAppName=QString("pgmodeler"), PgModelerURI=QString("pgmodeler.io"), PgModelerReverseURI=QString("io.pgmodeler"), PgModelerBuildNumber=QString(BUILDNUM), PgModelerSite=QString("https://pgmodeler.io"), PgModelerSupport=QString("https://pgmodeler.io/support/docs"), PgModelerSourceURL=QString("https://github.com/pgmodeler/pgmodeler/releases"), PgModelerDownloadURL=QString("%1/download").arg(PgModelerSite), PgModelerDonateURL=QString("%1/#donationForm").arg(PgModelerSite), PgModelerUpdateCheckURL=QString("%1/checkupdate?version=").arg(PgModelerSite), BugReportEmail=QString("bug@pgmodeler.io"), BugReportFile=QString("pgmodeler%1.bug"), StacktraceFile=QString(".stacktrace"), DirSeparator=QString("/"), DefaultConfsDir=QString("defaults"), ConfsBackupsDir=QString("backups"), SchemasDir=QString("schemas"), SQLSchemaDir=QString("sql"), XMLSchemaDir=QString("xml"), DataDictSchemaDir=QString("datadict"), AlterSchemaDir=QString("alter"), SchemaExt=QString(".sch"), ObjectDTDDir=QString("dtd"), ObjectDTDExt=QString(".dtd"), RootDTD=QString("dbmodel"), MetadataDTD=QString("metadata"), ConfigurationExt=QString(".conf"), HighlightFileSuffix=QString("-highlight"), CodeHighlightConf=QString("source-code-highlight"), ObjectsStyleConf=QString("objects-style"), GeneralConf=QString("pgmodeler"), ConnectionsConf=QString("connections"), RelationshipsConf=QString("relationships"), SnippetsConf=QString("snippets"), SQLHistoryConf=QString("sql-history"), DiffPresetsConf=QString("diff-presets"), SQLHighlightConf=QString("sql-highlight"), XMLHighlightConf=QString("xml-highlight"), PatternHighlightConf=QString("pattern-highlight"), ExampleModel=QString("example.dbm"), UiStyleConf=QString("ui-style"), DefaultQtStyle=QString("Fusion"), UiStyleOption=QString("-style"), SchemasRootDir=getPathFromEnv(QString("PGMODELER_SCHEMAS_DIR"), QString(SCHEMASDIR), QString("./schemas")), LanguagesDir=getPathFromEnv(QString("PGMODELER_LANG_DIR"), QString(LANGDIR), QString("./lang")), SamplesDir=getPathFromEnv(QString("PGMODELER_SAMPLES_DIR"), QString(SAMPLESDIR), QString("./samples")), TmplConfigurationDir=getPathFromEnv(QString("PGMODELER_TMPL_CONF_DIR"), QString(CONFDIR), QString("./conf")), //Currently, plugins folder is auto-created when missing so it can't be resolved by getPathFromEnv() PluginsDir=getenv("PGMODELER_PLUGINS_DIR") ? QString(getenv("PGMODELER_PLUGINS_DIR")).replace('\\','/') : QString(PLUGINSDIR), #if defined(Q_OS_MAC) ConfigurationsDir=getPathFromEnv(QString("PGMODELER_CONF_DIR"), QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QString("/%1").arg(PgModelerReverseURI)), TemporaryDir=getPathFromEnv(QString("PGMODELER_TMP_DIR"), QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QString("/%1/tmp").arg(PgModelerReverseURI)), #elif defined(Q_OS_LINUX) ConfigurationsDir=getPathFromEnv(QString("PGMODELER_CONF_DIR"), QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QString("/%1").arg(PgModelerAppName)), TemporaryDir=getPathFromEnv(QString("PGMODELER_TMP_DIR"), QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QString("/%1/tmp").arg(PgModelerAppName)), #else ConfigurationsDir=getPathFromEnv(QString("PGMODELER_CONF_DIR"), QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QString("/%1").arg(PgModelerAppName)), TemporaryDir=getPathFromEnv(QString("PGMODELER_TMP_DIR"), QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QString("/%1/tmp").arg(PgModelerAppName)), #endif SQLHighlightConfPath=ConfigurationsDir + DirSeparator + SQLHighlightConf + ConfigurationExt, XMLHighlightConfPath=ConfigurationsDir + DirSeparator + XMLHighlightConf + ConfigurationExt, #if defined(Q_OS_UNIX) #if defined(Q_OS_MAC) //For MacOSX the crash handler path is fixed (inside bundle) PgModelerCHandlerPath=getPathFromEnv(QString("PGMODELER_CHANDLER_PATH"), QString(BINDIR) + QString("/pgmodeler-ch"), QString("./pgmodeler-ch")), #else PgModelerCHandlerPath=getPathFromEnv(QString("PGMODELER_CHANDLER_PATH"), QString(PRIVATEBINDIR) + QString("/pgmodeler-ch"), QString("./pgmodeler-ch")), #endif PgModelerCLIPath=getPathFromEnv(QString("PGMODELER_CLI_PATH"), QString(BINDIR) + QString("/pgmodeler-cli"), QString("./pgmodeler-cli")), PgModelerAppPath=getPathFromEnv(QString("PGMODELER_APP_PATH"), QString(BINDIR) + QString("/pgmodeler"), QString("./pgmodeler")); #else PgModelerCHandlerPath=getPathFromEnv(QString("PGMODELER_CHANDLER_PATH"), QString(PRIVATEBINDIR) + QString("\\pgmodeler-ch.exe"), QString(".\\pgmodeler-ch.exe")), PgModelerCLIPath=getPathFromEnv(QString("PGMODELER_CLI_PATH"), QString(PRIVATEBINDIR) + QString("\\pgmodeler-cli.exe"), QString(".\\pgmodeler-cli.exe")), PgModelerAppPath=getPathFromEnv(QString("PGMODELER_APP_PATH"), QString(BINDIR) + QString("\\pgmodeler.exe"), QString(".\\pgmodeler.exe")); #endif #ifdef DEMO_VERSION //Maximum object creation counter for demo version const unsigned MaxObjectCount=15; #endif QString getPathFromEnv(const QString &varname, const QString &default_val, const QString &fallback_val) { QFileInfo fi; QStringList paths={ QDir::toNativeSeparators(getenv(varname.toStdString().c_str())), QDir::toNativeSeparators(default_val) }; for(int i=0; i < 2; i++) { fi.setFile(paths[i]); if(fi.exists() || (i==1 && fallback_val.isEmpty())) return(paths[i].replace('\\','/')); } fi.setFile(fallback_val); return(fi.absoluteFilePath()); } } pgmodeler-0.9.2/libutils/src/globalattributes.h000066400000000000000000000132201360462764600216520ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libutils \namespace GlobalAttributes \brief Definition of GlobalAttributes namespace wich stores a series of static strings constants used to reference the global configuration attributes of the software. \note Creation date: 14/05/2010 */ #ifndef GLOBAL_ATTRIBUTES_H #define GLOBAL_ATTRIBUTES_H /* Including QByteArray due to 'QByteArray has no toStdString()' error on Qt 5.4 (Windows only) */ #include #include #include #include #include #include namespace GlobalAttributes { extern const QString PgModelerAppName, PgModelerURI, PgModelerReverseURI, PgModelerVersion, PgModelerBuildNumber, PgModelerSite, PgModelerSupport, PgModelerSourceURL, PgModelerDownloadURL, PgModelerDonateURL, PgModelerUpdateCheckURL, BugReportEmail, BugReportFile, StacktraceFile, DirSeparator, DefaultConfsDir, //! \brief Directory name which holds the default pgModeler configuration ConfsBackupsDir, //! \brief Directory name which holds the pgModeler configuration backups SchemasDir, //! \brief Default name for the schemas directory SQLSchemaDir, //! \brief Default name for the sql schemas directory XMLSchemaDir, //! \brief Default name for the xml schemas directory DataDictSchemaDir,//! \brief Default name for the data dictionary schemas directory AlterSchemaDir, //! \brief Default name for the alter schemas directory SchemaExt, //! \brief Default extension for schema files ObjectDTDDir, //! \brief Default directory for dtd files ObjectDTDExt, //! \brief Default extension for dtd files RootDTD, //! \brief Root DTD of model xml files MetadataDTD, //! \brief Root DTD of objects metadata xml files ConfigurationExt, //! \brief Default extension for configuration files HighlightFileSuffix, //! \brief Suffix of language highlight configuration files CodeHighlightConf, //! \brief Default name for the language highlight dtd ObjectsStyleConf, //! \brief Default name for the object style configuration file GeneralConf, //! \brief Default name for the general pgModeler configuration ConnectionsConf, //! \brief Default name for the DBMS connection configuration file RelationshipsConf, //! \brief Default name for the relationships configuration file SnippetsConf, //! \brief Default name for the code snippets configuration file DiffPresetsConf, //! \brief Default name for the diff presets configuration file SQLHighlightConf, //! \brief Configuration file for SQL language highlight XMLHighlightConf, //! \brief Configuration file for XML language highlight PatternHighlightConf, //! \brief Configuration file for name patterns highlight (relationship editing form) SQLHistoryConf, //! \brief Default name for the SQL commands history configuration file ExampleModel, //! \brief Default name for the sample model loaded on appearence configuration form UiStyleConf, //! \brief Configuration file ui style /*! \brief Fusion is the default widget style for pgModeler. User can change this by calling the executable using -style option. This same style is applied to crash handler. */ DefaultQtStyle, UiStyleOption; /*! \brief Environment variables used to reference the pgModeler directories. PGMODELER_SCHEMAS_DIR --> "schemas" folder (SQL/XML generation schema files) PGMODELER_CONF_DIR --> "conf" folder (user's own settings for pgModeler) PGMODELER_TMPL_CONF_DIR --> "conf" folder (used as template settings and copied to user's settings) PGMODELER_LANG_DIR --> "lang" folder (ui translations) PGMODELER_PLUGINS_DIR --> "plugins" folder (where plugins are installed) PGMODELER_TMP_DIR --> "tmp" folder (where temporary work are saved) PGMODELER_SAMPLES_DIR --> "samples" folder (contains sample dbm files) Additional vars are used to specify where to find crash handler, command line interface and main application. PGMODELER_CHANDLER_PATH --> Full path to pgmodeler-ch executable PGMODELER_CLI_PATH --> Full path to pgmodeler-cli executable PGMDOELER_APP_PATH --> Full path to pgmodeler executable */ extern const QString SchemasRootDir, LanguagesDir, PluginsDir, TemporaryDir, SamplesDir, TmplConfigurationDir, ConfigurationsDir, SQLHighlightConfPath, XMLHighlightConfPath, PgModelerCHandlerPath, PgModelerCLIPath, PgModelerAppPath; #ifdef DEMO_VERSION //Maximum object creation counter for demo version extern const unsigned MaxObjectCount; #endif /*! \brief Returns the current value for an environment variable. If the current value is a path and the same does not exists then the function will return 'default_value' if it exists. Finally, if both current value and default values does not exists the the fallback value is returned even if it not exists in the filesystem */ extern QString getPathFromEnv(const QString &varname, const QString &default_val, const QString &fallback_val=QString()); } #endif pgmodeler-0.9.2/libutils/src/pgsqlversions.cpp000066400000000000000000000025261360462764600215640ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pgsqlversions.h" namespace PgSqlVersions { const QString PgSqlVersion90=QString("9.0"), PgSqlVersion91=QString("9.1"), PgSqlVersion92=QString("9.2"), PgSqlVersion93=QString("9.3"), PgSqlVersion94=QString("9.4"), PgSqlVersion95=QString("9.5"), PgSqlVersion96=QString("9.6"), PgSqlVersion100=QString("10.0"), PgSqlVersion110=QString("11.0"), PgSqlVersion120=QString("12.0"), DefaulVersion=PgSqlVersion120; const QStringList AllVersions={ PgSqlVersion120, PgSqlVersion110, PgSqlVersion100, PgSqlVersion96, PgSqlVersion95, PgSqlVersion94, PgSqlVersion93, PgSqlVersion92, PgSqlVersion91, PgSqlVersion90 }; } pgmodeler-0.9.2/libutils/src/pgsqlversions.h000066400000000000000000000024071360462764600212270ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup libutils \namespace PgSQLVersions \brief Definition of PgSQLVersions namespace wich stores a series of static strings constants used to reference the supported PostgreSQL version. */ #ifndef PGSQL_VERSIONS_H #define PGSQL_VERSIONS_H #include namespace PgSqlVersions { extern const QString PgSqlVersion90, PgSqlVersion91, PgSqlVersion92, PgSqlVersion93, PgSqlVersion94, PgSqlVersion95, PgSqlVersion96, PgSqlVersion100, PgSqlVersion110, PgSqlVersion120, DefaulVersion; extern const QStringList AllVersions; } #endif pgmodeler-0.9.2/linuxdeploy.sh000077500000000000000000000252661360462764600164440ustar00rootroot00000000000000#!/bin/bash # Identify architecture case `uname -m` in "x86_64") ARCH="linux64" FALLBACK_QT_ROOT=/opt/qt-5.12.3/5.12.3/gcc_64 FALLBACK_QMAKE_ROOT="$FALLBACK_QT_ROOT/bin" ;; *) ARCH="linux32" FALLBACK_QT_ROOT=/opt/qt-5.6.2/5.6/gcc FALLBACK_QMAKE_ROOT="$FALLBACK_QT_ROOT/bin" ;; esac # Uncomment this line if you want to compile using LLVM (clang) compiler tools # QMAKE_ARGS="-r -spec linux-clang" # Comment this one if you've decided to use LLVM QMAKE_ARGS="-r -spec linux-g++" QMAKE_ROOT=/usr/bin QMAKE_CMD=qmake LOG="$PWD/linuxdeploy.log" QT_IFW_ROOT=/opt/qt-ifw-3.0.4 # Detecting current pgModeler version DEPLOY_VER=`cat libutils/src/globalattributes.cpp | grep PgModelerVersion | sed 's/PgModelerVersion=QString("//g' | sed 's/")//g' | sed 's/^ *//g' | cut -s -f2` STARTUP_SCRIPT="start-pgmodeler.sh" MIME_UPDATE_SCRIPT="dbm-mime-type.sh" ENV_VARS_SCRIPT="pgmodeler.vars" BUILD_DIR="$PWD/build" DIST_DIR="$PWD/dist" INSTALL_ROOT="/opt/pgmodeler" FMT_PREFIX="\/opt\/pgmodeler" INSTALLER_APP_VER=`echo $DEPLOY_VER | cut -d '-' -f1` INSTALLER_CONF_DIR="$PWD/installer/template/config" INSTALLER_PKG_DIR="$PWD/installer/template/packages" INSTALLER_DATA_DIR="$INSTALLER_PKG_DIR/io.pgmodeler/data" INSTALLER_META_DIR="$INSTALLER_PKG_DIR/io.pgmodeler/meta" INSTALLER_TMPL_CONFIG="config.xml.tmpl" INSTALLER_CONFIG="config.xml" INSTALLER_TMPL_PKG_CONFIG="package.xml.tmpl" INSTALLER_PKG_CONFIG="package.xml" QT_CONF="$BUILD_DIR/$INSTALL_ROOT/qt.conf" DEP_PLUGINS_DIR="$BUILD_DIR/$INSTALL_ROOT/lib/qtplugins" BUILD_DATE=`date '+%Y%m%d'` SNAPSHOT_OPT='-snapshot' GEN_INSTALLER_OPT='-gen-installer' DEMO_VERSION_OPT='-demo-version' NO_QT_LIBS_OPT='-no-qt-libs' BUILD_ALL_OPT='-build-all' COMPRESS_INSTALLER_OPT='-comp-installer' SNAPSHOT=0 GEN_INST_PKG=0 COMP_INST_PKG=0 DEMO_VERSION=0 BUNDLE_QT_LIBS=1 BUILD_ALL=0 # pgModeler output paths settings PREFIX="/opt/pgmodeler" BINDIR=$PREFIX PRIVATEBINDIR=$PREFIX PRIVATELIBDIR="$PREFIX/lib" LANGDIR="$PREFIX/lang" SAMPLESDIR="$PREFIX/samples" SCHEMASDIR="$PREFIX/schemas" TEMPDIR="$PREFIX/tmp" PLUGINSDIR="$PREFIX/plugins" CONFDIR="$PREFIX/conf" DOCDIR="$PREFIX" SHAREDIR="$PREFIX" QMAKE_ARGS="$QMAKE_ARGS \ PREFIX=$PREFIX \ BINDIR=$BINDIR \ PRIVATEBINDIR=$PRIVATEBINDIR \ PRIVATELIBDIR=$PRIVATELIBDIR \ LANGDIR=$LANGDIR \ SAMPLESDIR=$SAMPLESDIR \ SCHEMASDIR=$SCHEMASDIR \ PLUGINSDIR=$PLUGINSDIR \ CONFDIR=$CONFDIR \ DOCDIR=$DOCDIR \ SHAREDIR=$SHAREDIR \ TEMPDIR=$TEMPDIR" for param in $@; do if [[ "$param" == "$BUILD_ALL_OPT" ]]; then BUILD_ALL=1 fi if [[ "$param" == "$GEN_INSTALLER_OPT" ]]; then GEN_INST_PKG=1 fi if [[ "$param" == "$COMPRESS_INSTALLER_OPT" ]]; then COMP_INST_PKG=1 fi if [[ "$param" == "$SNAPSHOT_OPT" ]]; then SNAPSHOT=1 QMAKE_ARGS="$QMAKE_ARGS SNAPSHOT_BUILD+=true" DEPLOY_VER="${DEPLOY_VER}_snapshot${BUILD_DATE}" fi if [[ "$param" == "$DEMO_VERSION_OPT" ]]; then DEMO_VERSION=1 GEN_INST_PKG=1 QMAKE_ARGS="$QMAKE_ARGS DEMO_VERSION+=true" fi if [[ "$param" == "$NO_QT_LIBS_OPT" ]]; then BUNDLE_QT_LIBS=0 fi done if [ $BUILD_ALL = 1 ]; then DEMO_VERSION=0 GEN_INST_PKG=1 fi if [ $DEMO_VERSION = 1 ]; then PKGNAME="pgmodeler-$DEPLOY_VER-demo-$ARCH" else PKGNAME="pgmodeler-$DEPLOY_VER-$ARCH" fi PKGFILE=$PKGNAME.tgz if [ $BUNDLE_QT_LIBS = 0 ]; then PKGFILE=$PKGNAME.tgz else #Dependency qt plugins copied to build dir DEP_PLUGINS="imageformats/libqgif.so \ imageformats/libqico.so \ imageformats/libqjpeg.so \ imageformats/libqmng.so \ imageformats/libqsvg.so \ imageformats/libqtga.so \ imageformats/libqtiff.so \ imageformats/libqwbmp.so \ printsupport/libcupsprintersupport.so \ platforms/libqxcb.so" #Needed Qt libs QT_LIBS="libQt5DBus.so.5 \ libQt5PrintSupport.so.5 \ libQt5Widgets.so.5 \ libQt5Network.so.5 \ libQt5Gui.so.5 \ libQt5Core.so.5 \ libQt5XcbQpa.so.5 \ libQt5Svg.so.5 \ libicui18n.so.5* \ libicuuc.so.5* \ libicudata.so.5*" fi clear echo echo "pgModeler Linux deployment script" echo "PostgreSQL Database Modeler Project - pgmodeler.io" echo "Copyright 2006-2019 Raphael A. Silva " # Identifying System Qt version if [ -e "$QMAKE_ROOT/$QMAKE_CMD" ]; then QT_VER_1=`$QMAKE_ROOT/$QMAKE_CMD --version | grep --color=never -m 1 -o -E '[0-9].[0-9]+\.[0-9]+'` QT_VER_1=${QT_VER_1:0:5} fi # Identifying Fallback Qt version if [ -e "$FALLBACK_QMAKE_ROOT/$QMAKE_CMD" ]; then QT_VER_2=`$FALLBACK_QMAKE_ROOT/$QMAKE_CMD --version | grep --color=never -m 1 -o -E '[0-9].[0-9]+\.[0-9]+'` QT_VER_2=${QT_VER_2:0:5} export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"$FALLBACK_QT_ROOT/lib" fi # If Qt was not found in system path or fallback path if [ -z "$QT_VER_1" -a -z "$QT_VER_2" ]; then echo echo "** No Qt framework was found!" echo exit 1 else # Checking if identified versions are valid (>= 5.0.0) if [[ "$QT_VER_1" < "5.0.0" ]]; then if [[ "$QT_VER_2" < "5.0.0" ]]; then if [ -z $QT_VER_2 ]; then QT_VER_2="not found" fi echo echo "** Qt framework found but in no suitable version (>= 5.0.0)!" echo "** System Qt version: $QT_VER_1" echo "** Fallback Qt version: $QT_VER_2" echo exit 1 else # If fallback Qt is suitable then change the standard qmake root dir QMAKE_ROOT=$FALLBACK_QMAKE_ROOT fi fi fi echo echo "Deploying version: $DEPLOY_VER" if [ $BUNDLE_QT_LIBS = 0 ]; then echo "Qt libs will not be included on the package. (Found $NO_QT_LIBS_OPT)" fi if [ $GEN_INST_PKG = 1 ]; then echo "The installer will be generated. (Found $GEN_INSTALLER_OPT)" if [ $COMP_INST_PKG = 1 ]; then echo "The installer will be compressed (Found $COMPRESS_INSTALLER_OPT)" fi fi if [ $SNAPSHOT = 1 ]; then echo "Building snapshot version. (Found $SNAPSHOT_OPT)" fi if [ $DEMO_VERSION = 1 ]; then echo "Building demonstration version. (Found $DEMO_VERSION_OPT)" fi echo "Cleaning previous compilation..." rm -r $BUILD_DIR/* &> $LOG mkdir -p $DIST_DIR >> $LOG 2>&1 if [ $BUILD_ALL -eq 1 ]; then rm -r $DIST_DIR/* >> $LOG 2>&1 fi make distclean >> $LOG 2>&1 echo "Running qmake..." $QMAKE_ROOT/$QMAKE_CMD $QMAKE_ARGS >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to execute qmake with arguments '$QMAKE_ARGS'" echo exit 1 fi echo "Compiling code..." make -j8 >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Compilation failed!" echo exit 1 fi echo "Installing dependencies..." make install INSTALL_ROOT=$BUILD_DIR >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Installation failed!" echo exit 1 fi if [ $BUNDLE_QT_LIBS = 1 ]; then echo "Copying Qt core libraries..." QT_ROOT=`$QMAKE_ROOT/qtpaths --install-prefix` >> $LOG 2>&1 LIB_DIR= MULTIARCH=`gcc -print-multiarch` >> $LOG 2>&1 if [ -n "$MULTIARCH" ]; then LIB_DIR="$MULTIARCH/" fi for lib in $QT_LIBS; do cp -v $QT_ROOT/lib/$LIB_DIR$lib $BUILD_DIR/$INSTALL_ROOT/lib >> $LOG 2>&1 done if [ $? -ne 0 ]; then echo echo "** Library copy failed!" echo exit 1 fi echo "Copying Qt plugins..." #Creates the file build/qt.conf to bind qt plugins mkdir $DEP_PLUGINS_DIR echo "[Paths]" > $QT_CONF echo "Prefix=." >> $QT_CONF echo "Plugins=lib/qtplugins" >> $QT_CONF echo "Libraries=." >> $QT_CONF #Copies the qt plugins to build/qtplugins QT_PLUGIN_ROOT=`$QMAKE_ROOT/qtpaths --plugin-dir` >> $LOG 2>&1 for plug in $DEP_PLUGINS; do pdir=`dirname $plug` if [ -e $QT_PLUGIN_ROOT/$plug ]; then mkdir -p $DEP_PLUGINS_DIR/$pdir >> $LOG 2>&1 cp -v $QT_PLUGIN_ROOT/$plug $DEP_PLUGINS_DIR/$pdir >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Plugins copy failed!" echo exit 1 fi fi done fi echo "Copying scripts..." cp -v $STARTUP_SCRIPT "$BUILD_DIR/$INSTALL_ROOT" >> $LOG 2>&1 cp -v $MIME_UPDATE_SCRIPT "$BUILD_DIR/$INSTALL_ROOT" >> $LOG 2>&1 cp -v $ENV_VARS_SCRIPT "$BUILD_DIR/$INSTALL_ROOT" >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to copy scripts!" echo exit 1 fi chmod +x "$BUILD_DIR/$INSTALL_ROOT/$STARTUP_SCRIPT" chmod +x "$BUILD_DIR/$INSTALL_ROOT/$MIME_UPDATE_SCRIPT" if [ $? -ne 0 ]; then echo echo "** Failed to set permisions to scripts!" echo exit 1 fi if [ $DEMO_VERSION = 0 ]; then echo "Generating tarball..." rm -r $PKGNAME >> $LOG 2>&1 mkdir $BUILD_DIR/$PKGNAME >> $LOG 2>&1 cp -r $BUILD_DIR/$INSTALL_ROOT/* $BUILD_DIR/$PKGNAME >> $LOG 2>&1 cd $BUILD_DIR >> $LOG 2>&1 tar -zcvf $PKGFILE $PKGNAME >> $LOG 2>&1 rm -r $PKGNAME >> $LOG 2>&1 cd .. >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to create package!" echo exit 1 fi mv $BUILD_DIR/$PKGFILE $DIST_DIR >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to move $PKGFILE to $DIST_DIR" echo exit 1 fi echo "File created: dist/$PKGFILE" fi if [ $GEN_INST_PKG = 1 ]; then echo "Generating installer..." rm $INSTALLER_DATA_DIR >> $LOG 2>&1 ln -sf "$BUILD_DIR/$INSTALL_ROOT" $INSTALLER_DATA_DIR >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to configure installer data dir!" echo exit 1 fi # Configuing installer scripts before packaging cat $INSTALLER_CONF_DIR/$INSTALLER_TMPL_CONFIG | sed -e "s/{version}/$INSTALLER_APP_VER/g" | sed -e "s/{prefix}/$FMT_PREFIX/g" > $INSTALLER_CONF_DIR/$INSTALLER_CONFIG if [ $? -ne 0 ]; then echo echo "** Failed to create the installer config file!" echo exit 1 fi # Packaging installation $QT_IFW_ROOT/bin/binarycreator -v -c $INSTALLER_CONF_DIR/config.xml -p $INSTALLER_PKG_DIR "$DIST_DIR/$PKGNAME.run" >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to create installer!" echo exit 1 fi if [ $COMP_INST_PKG = 1 ]; then _PWD=`pwd` cd $DIST_DIR >> $LOG 2>&1 tar -zcvf $PKGNAME.run.tgz $PKGNAME.run >> $LOG 2>&1 rm $PKGNAME.run >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to create compressed installer!" echo exit 1 fi echo "File created: dist/$PKGNAME.run.tgz" cd $_PWD >> $LOG 2>&1 else echo "File created: dist/$PKGNAME.run" fi fi echo "pgModeler successfully deployed!" echo if [ $BUILD_ALL = 1 ]; then EXTRA_OPT="" if [ $SNAPSHOT = 1 ]; then EXTRA_OPT="$SNAPSHOT_OPT" fi if [ $COMP_INST_PKG = 1 ]; then ./linuxdeploy.sh $DEMO_VERSION_OPT $COMPRESS_INSTALLER_OPT $EXTRA_OPT else ./linuxdeploy.sh $DEMO_VERSION_OPT $EXTRA_OPT fi fi pgmodeler-0.9.2/macdeploy.sh000077500000000000000000000111411360462764600160300ustar00rootroot00000000000000#!/bin/bash USR=`whoami` PGSQL_ROOT=/Library/PostgreSQL/11 QT_ROOT=/Users/$USR/Qt5.12.3/5.12.3/clang_64 QMAKE_ARGS="-r CONFIG+=x86_64 CONFIG+=release -spec macx-clang" LOG=macdeploy.log # Detecting current pgModeler version DEPLOY_VER=`cat libutils/src/globalattributes.cpp | grep PgModelerVersion | sed 's/PgModelerVersion=QString("//g' | sed 's/")//g' | sed 's/^ *//g' | cut -s -f2` BUILD_NUM=$(date '+%Y%m%d') DEMO_VERSION_OPT='-demo-version' DEMO_VERSION=0 SNAPSHOT_OPT='-snapshot' SNAPSHOT=0 for param in $@; do if [[ "$param" == "$DEMO_VERSION_OPT" ]]; then DEMO_VERSION=1 QMAKE_ARGS="$QMAKE_ARGS DEMO_VERSION+=true" fi if [[ "$param" == "$SNAPSHOT_OPT" ]]; then SNAPSHOT=1 QMAKE_ARGS="$QMAKE_ARGS SNAPSHOT_BUILD+=true" DEPLOY_VER="${DEPLOY_VER}_snapshot${BUILD_NUM}" fi done if [ $DEMO_VERSION = 1 ]; then PKGNAME="pgmodeler-$DEPLOY_VER-demo-macos" else PKGNAME="pgmodeler-$DEPLOY_VER-macos" fi PKGFILE=$PKGNAME.dmg APPNAME=pgmodeler INSTALL_ROOT="$PWD/build" APP_PREFIX="Applications" BUNDLE="$INSTALL_ROOT/$APP_PREFIX/$APPNAME.app" clear echo echo "pgModeler Mac OSX deployment script" echo "PostgreSQL Database Modeler Project - pgmodeler.io" echo "Copyright 2006-2019 Raphael A. Silva " # Identifying System Qt version if [ -e "$QT_ROOT/bin/qmake" ]; then QT_VER=`$QT_ROOT/bin/qmake --version | grep -m 1 -o -E '[0-9]\.[0-9]+\.[0-9]+'` QT_VER=${QT_VER:0:5} fi # If Qt was not found in system path if [ -z "$QT_VER" ]; then echo echo "** No Qt framework was found!" echo exit 1 else # Checking if identified version is valid (>= 5.0.0) if [[ "$QT_VER" < "5.0.0" ]]; then echo echo "** Qt framework found but in no suitable version (>= 5.0.0)!" echo "** Installed Qt version: $QT_VER" echo exit 1 fi fi echo echo "Deploying version: $DEPLOY_VER" if [ $SNAPSHOT = 1 ]; then echo "Building snapshot version. (Found $SNAPSHOT_OPT)" fi if [ $DEMO_VERSION = 1 ]; then echo "Building demonstration version. (Found $DEMO_VERSION_OPT)" fi echo "Cleaning previous compilation..." rm -r $INSTALL_ROOT/* &> $LOG mkdir -p ./dist >> $LOG 2>&1 make distclean >> $LOG 2>&1 echo "Running qmake..." $QT_ROOT/bin/qmake $QMAKE_ARGS >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to execute qmake with arguments '$QMAKE_ARGS'" echo exit 1 fi echo "Compiling code..." make -j6 >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Compilation failed!" echo exit 1 fi echo "Installing dependencies..." make install INSTALL_ROOT=$INSTALL_ROOT >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Installation failed!" echo exit 1 fi echo "Packaging installation..." # Deploy the Qt libraries onto app bundle $QT_ROOT/bin/macdeployqt $BUNDLE -executable=$BUNDLE/Contents/MacOS/pgmodeler-ch -executable=$BUNDLE/Contents/MacOS/pgmodeler-cli >> $LOG 2>&1 cp $PGSQL_ROOT/lib/libpq.5.dylib $BUNDLE/Contents/Frameworks >> $LOG 2>&1 cp $PGSQL_ROOT/lib/libssl.1.* $BUNDLE/Contents/Frameworks >> $LOG 2>&1 cp $PGSQL_ROOT/lib/libcrypto.1.* $BUNDLE/Contents/Frameworks >> $LOG 2>&1 # Fixing the support of ssl by forcing the usage of the bundled libpq install_name_tool -change "@loader_path/../lib/libcrypto.1.0.0.dylib" "@loader_path/../Frameworks/libcrypto.1.0.0.dylib" $BUNDLE/Contents/Frameworks/libssl.1.0.0.dylib >> $LOG 2>&1 install_name_tool -change "@loader_path/../lib/libcrypto.1.0.0.dylib" "@loader_path/../Frameworks/libcrypto.1.0.0.dylib" $BUNDLE/Contents/Frameworks/libpq.5.dylib >> $LOG 2>&1 install_name_tool -change "@loader_path/../lib/libssl.1.0.0.dylib" "@loader_path/../Frameworks/libssl.1.0.0.dylib" $BUNDLE/Contents/Frameworks/libpq.5.dylib >> $LOG 2>&1 install_name_tool -change libpq.5.dylib "@loader_path/../Frameworks/libpq.5.dylib" $BUNDLE/Contents/Frameworks/libpgconnector.dylib >> $LOG 2>&1 # Creates an empty dmg file named cp installer/macosx/installer_icon.icns $INSTALL_ROOT/.VolumeIcon.icns >> $LOG 2>&1 mv $BUNDLE $INSTALL_ROOT >> $LOG 2>&1 rm -r "$INSTALL_ROOT/$APP_PREFIX" >> $LOG 2>&1 ln -s /Applications $INSTALL_ROOT/Applications >> $LOG 2>&1 rm $PKGFILE >> $LOG 2>&1 hdiutil create -format UDRW -fs HFS+ $PKGFILE -volname $APPNAME -srcfolder $INSTALL_ROOT >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to create package!" echo exit 1 fi echo "Updating package default icon..." open $PKGFILE --hide >> $LOG 2>&1 sleep 3 SetFile -a C /Volumes/$APPNAME >> $LOG 2>&1 umount /Volumes/$APPNAME >> $LOG 2>&1 if [ $? -ne 0 ]; then echo echo "** Failed to update package icon!" echo exit 1 fi mv $PKGFILE ./dist/ >> $LOG 2>&1 PKGFILE="dist/$PKGFILE" echo "File created: $PKGFILE" echo "pgModeler successfully deployed!" echo pgmodeler-0.9.2/main-cli/000077500000000000000000000000001360462764600152075ustar00rootroot00000000000000pgmodeler-0.9.2/main-cli/main-cli.pro000066400000000000000000000032241360462764600174230ustar00rootroot00000000000000# main-cli.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) CONFIG += console TEMPLATE = app TARGET = pgmodeler-cli INCLUDEPATH += ../main/src windows:RC_FILE=../main/res/windows_ico.qrc windows: RCC_DIR=src/ windows: DESTDIR = $$PWD SOURCES += src/main.cpp \ src/pgmodelercli.cpp HEADERS += src/pgmodelercli.h unix|windows: LIBS += -L$$OUT_PWD/../libpgmodeler_ui/ -lpgmodeler_ui \ -L$$OUT_PWD/../libobjrenderer/ -lobjrenderer \ -L$$OUT_PWD/../libpgconnector/ -lpgconnector \ -L$$OUT_PWD/../libpgmodeler/ -lpgmodeler \ -L$$OUT_PWD/../libparsers/ -lparsers \ -L$$OUT_PWD/../libutils/ -lutils INCLUDEPATH += $$PWD/../libpgmodeler_ui \ $$PWD/../libpgmodeler_ui/src \ $$PWD/../libobjrenderer/src \ $$PWD/../libpgconnector/src \ $$PWD/../libpgmodeler/src \ $$PWD/../libparsers/src \ $$PWD/../libutils/src DEPENDPATH += $$PWD/../libpgmodeler_ui \ $$PWD/../libobjrenderer \ $$PWD/../libpgconnector \ $$PWD/../libpgmodeler \ $$PWD/../libparsers \ $$PWD/../libutils # Deployment settings target.path = $$BINDIR INSTALLS = target pgmodeler-0.9.2/main-cli/src/000077500000000000000000000000001360462764600157765ustar00rootroot00000000000000pgmodeler-0.9.2/main-cli/src/main.cpp000066400000000000000000000035411360462764600174310ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include #include "pgmodelercli.h" int main(int argc, char **argv) { QTextStream out(stdout); #ifdef DEMO_VERSION out << endl; out << QString("pgModeler ") << GlobalAttributes::PgModelerVersion << QT_TR_NOOP(" command line interface.") << endl; out << QT_TR_NOOP("PostgreSQL Database Modeler Project - pgmodeler.io") << endl; out << QT_TR_NOOP("Copyright 2006-2019 Raphael A. Silva ") << endl; out << QT_TR_NOOP("\n** CLI disabled in demonstration version! **") << endl << endl; #else try { QTranslator translator; PgModelerCli pgmodeler_cli(argc, argv); //Tries to load the ui translation according to the system's locale translator.load(QLocale::system().name(), GlobalAttributes::LanguagesDir); //Installs the translator on the application pgmodeler_cli.installTranslator(&translator); //Executes the cli return(pgmodeler_cli.exec()); } catch(Exception &e) { out << endl; out << e.getExceptionsText(); out << QString("** pgmodeler-cli aborted due to critical error(s). **") << endl << endl; return(e.getErrorCode()==ErrorCode::Custom ? -1 : enum_cast(e.getErrorCode())); } #endif } pgmodeler-0.9.2/main-cli/src/main.cpp.old000066400000000000000000000155131360462764600202100ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2013 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "application.h" #include "globalattributes.h" #include #include //Creates an standard out to handles QStrings QTextStream out(stdout); //Stores the long option names. The boolean indicates if the option accepts a value map long_opts; //Stores the short option names. map short_opts; //Option names constants QString INPUT="-input", OUTPUT="-output", EXPORT_TO_FILE="-export-to-file", EXPORT_TO_PNG="-export-to-png", EXPORT_TO_DBMS="-export-to-dbms", PGSQL_VER="-pgsql-ver", HELP="-help", SHOW_GRID="-show-grid", SHOW_DELIMITERS="-show-delimiters", IGNORE_DUPLICATES="-ignore-duplicates", CONN_ALIAS="-conn-alias", HOST="-host", USER="-user", PASSWD="-passwd", INITIAL_DB="-initial-db"; void initializeOptions(void) { long_opts[INPUT]=true; long_opts[OUTPUT]=true; long_opts[EXPORT_TO_FILE]=false; long_opts[EXPORT_TO_PNG]=false; long_opts[EXPORT_TO_DBMS]=false; long_opts[PGSQL_VER]=true; long_opts[HELP]=false; long_opts[SHOW_GRID]=false; long_opts[SHOW_DELIMITERS]=false; long_opts[IGNORE_DUPLICATES]=false; long_opts[CONN_ALIAS]=true; long_opts[HOST]=true; long_opts[USER]=true; long_opts[PASSWD]=true; long_opts[INITIAL_DB]=true; short_opts[INPUT]="-i"; short_opts[OUTPUT]="-o"; short_opts[EXPORT_TO_FILE]="-f"; short_opts[EXPORT_TO_PNG]="-p"; short_opts[EXPORT_TO_DBMS]="-d"; short_opts[PGSQL_VER]="-v"; short_opts[HELP]="-h"; short_opts[SHOW_GRID]="-g"; short_opts[SHOW_DELIMITERS]="-l"; short_opts[IGNORE_DUPLICATES]="-I"; short_opts[CONN_ALIAS]="-c"; short_opts[HOST]="-H"; short_opts[USER]="-u"; short_opts[PASSWD]="-P"; short_opts[INITIAL_DB]="-D"; } //Returns if the specified options exists on short options map bool isOptionRecognized(const QString &op, bool &accepts_val) { map::iterator itr=short_opts.begin(); bool found=false; while(itr!=short_opts.end() && !found) { found=(op==itr->first || op==itr->second); accepts_val=(found && long_opts[itr->first]); itr++; } return(found); } void showMenu(void) { out << endl; out << "Usage: pgmodeler-cli [OPTIONS]" << endl; out << "pgModeler " << GlobalAttributes::PGMODELER_VERSION << " command line interface." << endl; out << "PostgreSQL Database Modeler Project" << endl; out << "Copyright 2006-2013 Raphael A. Silva " << endl; out << endl; out << "This tool provides a way to export pgModeler's database models without" << endl; out << "the need to load them on graphical interface. All available exporting" << endl; out << "modes are described below." << endl; out << endl; out << "Options: " << endl; out << QString(" %1, %2=[FILE]\t Input model file (.dbm).\n").arg(short_opts[INPUT]).arg(INPUT); out << QString(" %1, %2=[FILE]\t Output file. Available only on export to file or png.\n").arg(short_opts[OUTPUT]).arg(OUTPUT); out << QString(" %1, %2\t Export to a sql script file.\n").arg(short_opts[EXPORT_TO_FILE]).arg(EXPORT_TO_FILE); out << QString(" %1, %2\t Export to a png image.\n").arg(short_opts[EXPORT_TO_PNG]).arg(EXPORT_TO_PNG); out << QString(" %1, %2\t Export directly to a PostgreSQL server.\n").arg(short_opts[EXPORT_TO_DBMS]).arg(EXPORT_TO_DBMS); out << QString(" %1, %2\t\t Version of generated SQL code. Only for file or dbms export.\n").arg(short_opts[PGSQL_VER]).arg(PGSQL_VER); out << QString(" %1, %2\t\t Show this help menu.\n").arg(short_opts[HELP]).arg(HELP); out << endl; out << "PNG export options: " << endl; out << QString(" %1, %2\t\t Draws the grid on the exported png image.\n").arg(short_opts[SHOW_GRID]).arg(SHOW_GRID); out << QString(" %1, %2\t Draws the page delimiters on the exported png image.\n").arg(short_opts[SHOW_DELIMITERS]).arg(SHOW_DELIMITERS); out << endl; out << "DBMS export options: " << endl; out << QString(" %1, %2\t Ignores errors related to duplicated objects that eventually exists on server side.\n").arg(short_opts[IGNORE_DUPLICATES]).arg(IGNORE_DUPLICATES); out << QString(" %1, %2=[ALIAS]\t Connection configuration alias to be used.\n").arg(short_opts[CONN_ALIAS]).arg(CONN_ALIAS); out << QString(" %1, %2=[HOST]\t\t PostgreSQL host which export will operate.\n").arg(short_opts[HOST]).arg(HOST); out << QString(" %1, %2=[USER]\t\t PosrgreSQL username.\n").arg(short_opts[USER]).arg(USER); out << QString(" %1, %2=[PASSWORD]\t PosrgreSQL user password.\n").arg(short_opts[PASSWD]).arg(PASSWD); out << QString(" %1, %2=[DBNAME]\t Connection's initial database.\n").arg(short_opts[INITIAL_DB]).arg(INITIAL_DB); out << endl; } //Parsers the options and executes the action specified by them void parserOptions(map &opts) { if(opts.empty() || opts.count(HELP) > 0) showMenu(); else { if(opts.count(EXPORT_TO_FILE)==0 && opts.count(EXPORT_TO_PNG)==0 && opts.count(EXPORT_TO_DBMS)==0) throw Exception("No export mode specified!", ERR_CUSTOM,__PRETTY_FUNCTION__,__FILE__,__LINE__); } } int main(int argc, char **argv) { try { QCoreApplication app(argc, argv); QString op, value; bool accepts_val=false; initializeOptions(); map opts; app.exec(); app. if(argc > 1) { for(int i=1; i < argc; i++) { op=argv[i]; //If the retrieved option starts with - it will be treated as a command option if(op[0]=='-') { value.clear(); //Raises an error if the option is not recognized if(!isOptionRecognized(op, accepts_val)) throw Exception(QString("Unrecognized option '%1'.").arg(op), ERR_CUSTOM,__PRETTY_FUNCTION__,__FILE__,__LINE__); //If the option accepts a value if(accepts_val) { //If the next option does not starts with '-', is considered a value if(i < argc-1 && argv[i+1][0]!='-') value=argv[++i]; //Raises an error if the value is empty if(value.isEmpty()) throw Exception(QString("Value not specified for option '%1'.").arg(op), ERR_CUSTOM,__PRETTY_FUNCTION__,__FILE__,__LINE__); } opts[op]=value; } } } //Validates and executes the options parserOptions(opts); return(0); } catch(Exception &e) { out << e.getExceptionsText(); out << "** pgmodeler-cli aborted due critical error(s). **\n"; return(1); } } pgmodeler-0.9.2/main-cli/src/pgmodelercli.cpp000066400000000000000000002124271360462764600211600ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "pgmodelercli.h" QTextStream PgModelerCli::out(stdout); const QRegExp PgModelerCli::PasswordRegExp=QRegExp("(password)(=)(.)*( )"); const QString PgModelerCli::PasswordPlaceholder=QString("password=******"); const QString PgModelerCli::Input=QString("--input"); const QString PgModelerCli::Output=QString("--output"); const QString PgModelerCli::InputDb=QString("--input-db"); const QString PgModelerCli::ExportToFile=QString("--export-to-file"); const QString PgModelerCli::ExportToPng=QString("--export-to-png"); const QString PgModelerCli::ExportToSvg=QString("--export-to-svg"); const QString PgModelerCli::ExportToDbms=QString("--export-to-dbms"); const QString PgModelerCli::ExportToDict=QString("--export-to-dict"); const QString PgModelerCli::ImportDb=QString("--import-db"); const QString PgModelerCli::NoIndex=QString("--no-index"); const QString PgModelerCli::Splitted=QString("--splitted"); const QString PgModelerCli::Diff=QString("--diff"); const QString PgModelerCli::DropDatabase=QString("--drop-database"); const QString PgModelerCli::DropObjects=QString("--drop-objects"); const QString PgModelerCli::PgSqlVer=QString("--pgsql-ver"); const QString PgModelerCli::Help=QString("--help"); const QString PgModelerCli::ShowGrid=QString("--show-grid"); const QString PgModelerCli::ShowDelimiters=QString("--show-delimiters"); const QString PgModelerCli::PageByPage=QString("--page-by-page"); const QString PgModelerCli::IgnoreDuplicates=QString("--ignore-duplicates"); const QString PgModelerCli::IgnoreErrorCodes=QString("--ignore-error-codes"); const QString PgModelerCli::ConnAlias=QString("--conn-alias"); const QString PgModelerCli::Host=QString("--host"); const QString PgModelerCli::Port=QString("--port"); const QString PgModelerCli::User=QString("--user"); const QString PgModelerCli::Passwd=QString("--passwd"); const QString PgModelerCli::InitialDb=QString("--initial-db"); const QString PgModelerCli::Silent=QString("--silent"); const QString PgModelerCli::ListConns=QString("--list-conns"); const QString PgModelerCli::Simulate=QString("--simulate"); const QString PgModelerCli::FixModel=QString("--fix-model"); const QString PgModelerCli::FixTries=QString("--fix-tries"); const QString PgModelerCli::ZoomFactor=QString("--zoom"); const QString PgModelerCli::UseTmpNames=QString("--use-tmp-names"); const QString PgModelerCli::DbmMimeType=QString("--dbm-mime-type"); const QString PgModelerCli::Install=QString("install"); const QString PgModelerCli::Uninstall=QString("uninstall"); const QString PgModelerCli::IgnoreImportErrors=QString("--ignore-errors"); const QString PgModelerCli::ImportSystemObjs=QString("--import-sys-objs"); const QString PgModelerCli::ImportExtensionObjs=QString("--import-ext-objs"); const QString PgModelerCli::DebugMode=QString("--debug-mode"); const QString PgModelerCli::CompareTo=QString("--compare-to"); const QString PgModelerCli::SaveDiff=QString("--save-diff"); const QString PgModelerCli::ApplyDiff=QString("--apply-diff"); const QString PgModelerCli::NoDiffPreview=QString("--no-diff-preview"); const QString PgModelerCli::DropClusterObjs=QString("--drop-cluster-objs"); const QString PgModelerCli::RevokePermissions=QString("--revoke-perms"); const QString PgModelerCli::DropMissingObjs=QString("--drop-missing"); const QString PgModelerCli::ForceDropColsConstrs=QString("--force-drop-cols"); const QString PgModelerCli::RenameDb=QString("--rename-db"); const QString PgModelerCli::TruncOnColsTypeChange=QString("--trunc-type-change"); const QString PgModelerCli::NoSequenceReuse=QString("--no-sequence-reuse"); const QString PgModelerCli::NoCascadeDropTrunc=QString("--no-cascade"); const QString PgModelerCli::NoForceObjRecreation=QString("--no-force-recreation"); const QString PgModelerCli::NoUnmodObjRecreation=QString("--no-unmod-recreation"); const QString PgModelerCli::TagExpr=QString("<%1"); const QString PgModelerCli::EndTagExpr=QString(" 1) { for(int i=1; i < argc; i++) { op=argv[i]; //If the retrieved option starts with - it will be treated as a command option if(op[0]=='-') { value.clear(); eq_pos=op.indexOf('='); // if the option has a = attached strip the string, assuming as value the right part of it if(eq_pos >= 0) { value=op.mid(eq_pos+1); op=op.mid(0,eq_pos); } else if(i < argc-1 && argv[i+1][0]!='-') { //If the next option does not starts with '-', is considered a value value=argv[++i]; } //Raises an error if the option is not recognized if(!isOptionRecognized(op, accepts_val)) throw Exception(trUtf8("Unrecognized option '%1'.").arg(op), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Raises an error if the value is empty and the option accepts a value if(accepts_val && value.isEmpty()) throw Exception(trUtf8("Value not specified for option '%1'.").arg(op), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!accepts_val && !value.isEmpty()) throw Exception(trUtf8("Option '%1' does not accept values.").arg(op), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); opts[op]=value; } } } //Validates and executes the options parseOptions(opts); if(!parsed_opts.empty()) { model=new DatabaseModel; xmlparser=model->getXMLParser(); silent_mode=(parsed_opts.count(Silent)); //If the export is to png or svg loads additional configurations if(parsed_opts.count(ExportToPng) || parsed_opts.count(ExportToSvg) || parsed_opts.count(ImportDb)) { connect(model, SIGNAL(s_objectAdded(BaseObject*)), this, SLOT(handleObjectAddition(BaseObject *))); connect(model, SIGNAL(s_objectRemoved(BaseObject*)), this, SLOT(handleObjectRemoval(BaseObject *))); //Creates a scene to scene=new ObjectsScene; scene->setParent(this); scene->setSceneRect(QRectF(0,0,2000,2000)); //Load the general configuration including grid and delimiter options GeneralConfigWidget conf_wgt; conf_wgt.loadConfiguration(); //Load the objects styles BaseObjectView::loadObjectsStyle(); } if(parsed_opts.count(ExportToDbms) || parsed_opts.count(ImportDb) || parsed_opts.count(Diff)) { configureConnection(false); //Replacing the initial db parameter for the input database when reverse engineering if((parsed_opts.count(ImportDb) || parsed_opts.count(Diff)) && !parsed_opts[InputDb].isEmpty()) connection.setConnectionParam(Connection::ParamDbName, parsed_opts[InputDb]); } if(parsed_opts.count(Diff)) { configureConnection(true); if(!extra_connection.isConfigured()) extra_connection = connection; extra_connection.setConnectionParam(Connection::ParamDbName, parsed_opts[CompareTo]); } if(!silent_mode) { connect(&export_hlp, SIGNAL(s_progressUpdated(int,QString)), this, SLOT(updateProgress(int,QString))); connect(&export_hlp, SIGNAL(s_errorIgnored(QString,QString,QString)), this, SLOT(printIgnoredError(QString,QString,QString))); connect(&import_hlp, SIGNAL(s_progressUpdated(int,QString,ObjectType)), this, SLOT(updateProgress(int,QString))); connect(&diff_hlp, SIGNAL(s_progressUpdated(int,QString,ObjectType)), this, SLOT(updateProgress(int,QString))); } } } catch(Exception &e) { throw e; } } PgModelerCli::~PgModelerCli(void) { if(scene) delete(scene); delete(model); } void PgModelerCli::printMessage(const QString &msg) { if(!silent_mode) out << msg << endl; } void PgModelerCli::configureConnection(bool extra_conn) { QString chr = (extra_conn ? "1" : ""); Connection *conn = (extra_conn ? &extra_connection : &connection); //Getting the connection using its alias if(parsed_opts.count(ConnAlias + chr)) { if(!connections.count(parsed_opts[ConnAlias + chr])) throw Exception(trUtf8("Connection aliased as '%1' was not found in the configuration file.").arg(parsed_opts[ConnAlias + chr]), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Make a copy of the named connection *conn = (*connections[parsed_opts[ConnAlias + chr]]); } else { conn->setConnectionParam(Connection::ParamServerFqdn, parsed_opts[Host + chr]); conn->setConnectionParam(Connection::ParamUser, parsed_opts[User + chr]); conn->setConnectionParam(Connection::ParamPort, parsed_opts[Port + chr]); conn->setConnectionParam(Connection::ParamPassword, parsed_opts[Passwd + chr]); conn->setConnectionParam(Connection::ParamDbName, parsed_opts[InitialDb + chr]); } } void PgModelerCli::initializeOptions(void) { long_opts[Input]=true; long_opts[Output]=true; long_opts[InputDb]=true; long_opts[ExportToFile]=false; long_opts[ExportToPng]=false; long_opts[ExportToSvg]=false; long_opts[ExportToDbms]=false; long_opts[ImportDb]=false; long_opts[Diff]=false; long_opts[DropDatabase]=false; long_opts[DropObjects]=false; long_opts[PgSqlVer]=true; long_opts[Help]=false; long_opts[ShowGrid]=false; long_opts[ShowDelimiters]=false; long_opts[PageByPage]=false; long_opts[IgnoreDuplicates]=false; long_opts[IgnoreErrorCodes]=true; long_opts[ConnAlias]=true; long_opts[Host]=true; long_opts[Port]=true; long_opts[User]=true; long_opts[Passwd]=true; long_opts[InitialDb]=true; long_opts[ListConns]=false; long_opts[Simulate]=false; long_opts[FixModel]=false; long_opts[FixTries]=true; long_opts[ZoomFactor]=true; long_opts[UseTmpNames]=false; long_opts[DbmMimeType]=true; long_opts[IgnoreImportErrors]=false; long_opts[ImportSystemObjs]=false; long_opts[ImportExtensionObjs]=false; long_opts[DebugMode]=false; long_opts[CompareTo]=true; long_opts[SaveDiff]=false; long_opts[ApplyDiff]=false; long_opts[NoDiffPreview]=false; long_opts[DropClusterObjs]=false; long_opts[RevokePermissions]=false; long_opts[DropMissingObjs]=false; long_opts[ForceDropColsConstrs]=false; long_opts[RenameDb]=false; long_opts[TruncOnColsTypeChange]=false; long_opts[NoSequenceReuse]=false; long_opts[NoCascadeDropTrunc]=false; long_opts[NoForceObjRecreation]=false; long_opts[NoUnmodObjRecreation]=false; long_opts[ExportToDict]=false; long_opts[NoIndex]=false; long_opts[Splitted]=false; short_opts[Input]=QString("-if"); short_opts[Output]=QString("-of"); short_opts[InputDb]=QString("-id"); short_opts[ExportToFile]=QString("-ef"); short_opts[ExportToPng]=QString("-ep"); short_opts[ExportToSvg]=QString("-es"); short_opts[ExportToDbms]=QString("-ed"); short_opts[ExportToDict]=QString("-et"); short_opts[ImportDb]=QString("-im"); short_opts[Diff]=QString("-df"); short_opts[DropDatabase]=QString("-dd"); short_opts[DropObjects]=QString("-do"); short_opts[PgSqlVer]=QString("-v"); short_opts[Help]=QString("-h"); short_opts[ShowGrid]=QString("-sg"); short_opts[ShowDelimiters]=QString("-sl"); short_opts[PageByPage]=QString("-pp"); short_opts[IgnoreDuplicates]=QString("-ir"); short_opts[IgnoreErrorCodes]=QString("-ic"); short_opts[ConnAlias]=QString("-ca"); short_opts[Host]=QString("-H"); short_opts[Port]=QString("-p"); short_opts[User]=QString("-u"); short_opts[Passwd]=QString("-w"); short_opts[InitialDb]=QString("-D"); short_opts[Silent]=QString("-s"); short_opts[ListConns]=QString("-lc"); short_opts[Simulate]=QString("-sm"); short_opts[FixModel]=QString("-fm"); short_opts[FixTries]=QString("-ft"); short_opts[ZoomFactor]=QString("-zf"); short_opts[UseTmpNames]=QString("-tn"); short_opts[DbmMimeType]=QString("-mt"); short_opts[IgnoreImportErrors]=QString("-ie"); short_opts[ImportSystemObjs]=QString("-is"); short_opts[ImportExtensionObjs]=QString("-ix"); short_opts[DebugMode]=QString("-d"); short_opts[CompareTo]=QString("-ct"); short_opts[SaveDiff]=QString("-sd"); short_opts[ApplyDiff]=QString("-ad"); short_opts[NoDiffPreview]=QString("-np"); short_opts[DropClusterObjs]=QString("-dc"); short_opts[RevokePermissions]=QString("-rv"); short_opts[DropMissingObjs]=QString("-dm"); short_opts[ForceDropColsConstrs]=QString("-fd"); short_opts[RenameDb]=QString("-rn"); short_opts[TruncOnColsTypeChange]=QString("-tt"); short_opts[NoSequenceReuse]=QString("-ns"); short_opts[NoCascadeDropTrunc]=QString("-nd"); short_opts[NoForceObjRecreation]=QString("-nf"); short_opts[NoUnmodObjRecreation]=QString("-nu"); short_opts[NoIndex]=QString("-ni"); short_opts[Splitted]=QString("-sp"); } bool PgModelerCli::isOptionRecognized(QString &op, bool &accepts_val) { bool found=false, append_chr = false; if(op.endsWith('1')) { op.chop(1); append_chr = true; } for(auto &itr : short_opts) { found=(op==itr.first || op==itr.second); accepts_val=(found && long_opts[itr.first]); if(found) { op = itr.first; break; } } if(append_chr) op += '1'; return(found); } void PgModelerCli::showMenu(void) { out << endl; out << QString("pgModeler ") << GlobalAttributes::PgModelerVersion << trUtf8(" command line interface.") << endl; out << trUtf8("PostgreSQL Database Modeler Project - pgmodeler.io") << endl; out << trUtf8("Copyright 2006-2018 Raphael A. Silva ") << endl; out << endl; out << trUtf8("Usage: pgmodeler-cli [OPTIONS]") << endl << endl; out << trUtf8("This CLI tool provides several operations over models and databases without the need to perform them\nin pgModeler's graphical interface. All available options are described below.") << endl; out << endl; out << trUtf8("General options: ") << endl; out << trUtf8(" %1, %2 [FILE]\t\t Input model file (.dbm). This is mandatory for fix, export operations.").arg(short_opts[Input]).arg(Input) << endl; out << trUtf8(" %1, %2 [DBNAME]\t Input database name. This is mandatory for import operation.").arg(short_opts[InputDb]).arg(InputDb) << endl; out << trUtf8(" %1, %2 [FILE]\t\t Output file. This is mandatory for fixing model or exporting to file, png or svg.").arg(short_opts[Output]).arg(Output) << endl; out << trUtf8(" %1, %2\t\t Try to fix the structure of the input model file in order to make it loadable again.").arg(short_opts[FixModel]).arg(FixModel) << endl; out << trUtf8(" %1, %2 [NUMBER]\t Model fix tries. When reaching the maximum count the invalid objects will be discarded.").arg(short_opts[FixTries]).arg(FixTries) << endl; out << trUtf8(" %1, %2\t\t Export the input model to a sql script file.").arg(short_opts[ExportToFile]).arg(ExportToFile)<< endl; out << trUtf8(" %1, %2\t\t Export the input model to a png image.").arg(short_opts[ExportToPng]).arg(ExportToPng) << endl; out << trUtf8(" %1, %2\t\t Export the input model to a svg file.").arg(short_opts[ExportToSvg]).arg(ExportToSvg) << endl; out << trUtf8(" %1, %2\t\t Export the input model directly to a PostgreSQL server.").arg(short_opts[ExportToDbms]).arg(ExportToDbms) << endl; out << trUtf8(" %1, %2\t\t Export the input model to a data directory in HTML format.").arg(short_opts[ExportToDict]).arg(ExportToDict) << endl; out << trUtf8(" %1, %2\t\t Import a database to an output file.").arg(short_opts[ImportDb]).arg(ImportDb) << endl; out << trUtf8(" %1, %2\t\t\t Compares a model and a database or two databases generating the SQL script to synch the latter in relation to the first.").arg(short_opts[Diff]).arg(Diff) << endl; out << trUtf8(" %1, %2\t\t Force the PostgreSQL version of generated SQL code.").arg(short_opts[PgSqlVer]).arg(PgSqlVer) << endl; out << trUtf8(" %1, %2\t\t\t Silent execution. Only critical messages and errors are shown during process.").arg(short_opts[Silent]).arg(Silent) << endl; out << trUtf8(" %1, %2\t\t\t Show this help menu.").arg(short_opts[Help]).arg(Help) << endl; out << endl; out << trUtf8("Connection options: ") << endl; out << trUtf8(" %1, %2\t\t List available connections in file %3.").arg(short_opts[ListConns]).arg(ListConns).arg(GlobalAttributes::ConnectionsConf + GlobalAttributes::ConfigurationExt) << endl; out << trUtf8(" %1, %2 [ALIAS]\t Connection configuration alias to be used.").arg(short_opts[ConnAlias]).arg(ConnAlias) << endl; out << trUtf8(" %1, %2 [HOST]\t\t PostgreSQL host in which a task will operate.").arg(short_opts[Host]).arg(Host) << endl; out << trUtf8(" %1, %2 [PORT]\t\t PostgreSQL host listening port.").arg(short_opts[Port]).arg(Port) << endl; out << trUtf8(" %1, %2 [USER]\t\t PostgreSQL username.").arg(short_opts[User]).arg(User) << endl; out << trUtf8(" %1, %2 [PASSWORD]\t PostgreSQL user password.").arg(short_opts[Passwd]).arg(Passwd) << endl; out << trUtf8(" %1, %2 [DBNAME]\t Connection's initial database.").arg(short_opts[InitialDb]).arg(InitialDb) << endl; out << endl; out << trUtf8("PNG and SVG export options: ") << endl; out << trUtf8(" %1, %2\t\t Draws the grid in the exported image.").arg(short_opts[ShowGrid]).arg(ShowGrid) << endl; out << trUtf8(" %1, %2\t Draws the page delimiters in the exported image.").arg(short_opts[ShowDelimiters]).arg(ShowDelimiters) << endl; out << trUtf8(" %1, %2\t\t Each page will be exported in a separated png image. (Only for PNG images)").arg(short_opts[PageByPage]).arg(PageByPage) << endl; out << trUtf8(" %1, %2 [FACTOR]\t\t Applies a zoom (in percent) before export to png image. Accepted zoom interval: %3-%4 (Only for PNG images)").arg(short_opts[ZoomFactor]).arg(ZoomFactor).arg(ModelWidget::MinimumZoom*100).arg(ModelWidget::MaximumZoom*100) << endl; out << endl; out << trUtf8("DBMS export options: ") << endl; out << trUtf8(" %1, %2\t Ignores errors related to duplicated objects that eventually exist in the server.").arg(short_opts[IgnoreDuplicates]).arg(IgnoreDuplicates) << endl; out << trUtf8(" %1, %2 [CODES] Ignores additional errors by their codes. A comma-separated list of alphanumeric codes should be provided.").arg(short_opts[IgnoreErrorCodes]).arg(IgnoreErrorCodes) << endl; out << trUtf8(" %1, %2\t\t Drop the database before execute a export process.").arg(short_opts[DropDatabase]).arg(DropDatabase) << endl; out << trUtf8(" %1, %2\t\t Runs the DROP commands attached to SQL-enabled objects.").arg(short_opts[DropObjects]).arg(DropObjects) << endl; out << trUtf8(" %1, %2\t\t Simulates an export process by executing all steps but undoing any modification in the end.").arg(short_opts[Simulate]).arg(Simulate) << endl; out << trUtf8(" %1, %2\t\t Generates temporary names for database, roles and tablespaces when in simulation mode.").arg(short_opts[UseTmpNames]).arg(UseTmpNames) << endl; out << endl; out << trUtf8("Data dictionary export options: ") << endl; out << trUtf8(" %1, %2\t\t The data dictionaries are generated in separated files inside the selected output directory.").arg(short_opts[Splitted]).arg(Splitted) << endl; out << trUtf8(" %1, %2\t\t Avoids the generation of the index that is used to help navigating through the data dictionary.").arg(short_opts[NoIndex]).arg(NoIndex) << endl; out << endl; out << trUtf8("Database import options: ") << endl; out << trUtf8(" %1, %2\t\t Ignore all errors and try to create as many as possible objects.").arg(short_opts[IgnoreImportErrors]).arg(IgnoreImportErrors) << endl; out << trUtf8(" %1, %2\t Import system built-in objects. This option causes the model bloating due to the importing of unneeded objects.").arg(short_opts[ImportSystemObjs]).arg(ImportSystemObjs) << endl; out << trUtf8(" %1, %2\t Import extension objects. This option causes the model bloating due to the importing of unneeded objects.").arg(short_opts[ImportExtensionObjs]).arg(ImportExtensionObjs) << endl; out << trUtf8(" %1, %2\t\t Run import in debug mode printing all queries executed in the server.").arg(short_opts[DebugMode]).arg(DebugMode) << endl; out << endl; out << trUtf8("Diff options: ") << endl; out << trUtf8(" %1, %2 [DBNAME]\t The database used in the comparison. All the SQL code generated is applied to it.").arg(short_opts[CompareTo]).arg(CompareTo) << endl; out << trUtf8(" %1, %2\t\t Save the generated diff code to output file.").arg(short_opts[SaveDiff]).arg(SaveDiff) << endl; out << trUtf8(" %1, %2\t\t Apply the generated diff code on the database server.").arg(short_opts[ApplyDiff]).arg(ApplyDiff) << endl; out << trUtf8(" %1, %2\t Don't preview the generated diff code when applying it to the server.").arg(short_opts[NoDiffPreview]).arg(NoDiffPreview) << endl; out << trUtf8(" %1, %2\t Drop cluster level objects like roles and tablespaces.").arg(short_opts[DropClusterObjs]).arg(DropClusterObjs) << endl; out << trUtf8(" %1, %2\t\t Revoke permissions already set on the database. New permissions configured in the input model are still applied.").arg(short_opts[RevokePermissions]).arg(RevokePermissions) << endl; out << trUtf8(" %1, %2\t\t Drop missing objects. Generates DROP commands for objects that are present in the input model but not in the compared database.").arg(short_opts[DropMissingObjs]).arg(DropMissingObjs) << endl; out << trUtf8(" %1, %2\t Force the drop of missing columns and constraints. Causes only columns and constraints to be dropped, other missing objects aren't removed.").arg(short_opts[ForceDropColsConstrs]).arg(ForceDropColsConstrs) << endl; out << trUtf8(" %1, %2\t\t Rename the destination database when the names of the involved databases are different.").arg(short_opts[RenameDb]).arg(RenameDb) << endl; out << trUtf8(" %1, %2\t\t Don't drop or truncate objects in cascade mode.").arg(short_opts[NoCascadeDropTrunc]).arg(NoCascadeDropTrunc) << endl; out << trUtf8(" %1, %2\t Truncate tables prior to alter columns. Avoids errors related to type casting when the new type of a column isn't compatible to the old one.").arg(short_opts[TruncOnColsTypeChange]).arg(TruncOnColsTypeChange) << endl; out << trUtf8(" %1, %2\t Don't reuse sequences on serial columns. Drop the old sequence assigned to a serial column and creates a new one.").arg(short_opts[NoSequenceReuse]).arg(NoSequenceReuse) << endl; out << trUtf8(" %1, %2\t Don't force the recreation of objects. Avoids the usage of a DROP and CREATE commands to create a new version of the objects.").arg(short_opts[NoForceObjRecreation]).arg(NoForceObjRecreation) << endl; out << trUtf8(" %1, %2\t Don't recreate the unmodifiable objects. These objects are the ones which can't be changed via ALTER command.").arg(short_opts[NoUnmodObjRecreation]).arg(NoUnmodObjRecreation) << endl; out << endl; #ifndef Q_OS_MAC out << trUtf8("Miscellaneous options: ") << endl; out << trUtf8(" %1, %2 [ACTION]\t Handles the file association to .dbm files. The ACTION can be [%3 | %4].").arg(short_opts[DbmMimeType]).arg(DbmMimeType).arg(Install).arg(Uninstall) << endl; out << endl; #endif out << trUtf8("** The diff process allows the usage of the following options related to import and export operations: ") << endl; out << " " << QStringList({ trUtf8("* Export: "), IgnoreDuplicates, IgnoreErrorCodes, "\n ", trUtf8("* Import: "), ImportSystemObjs, ImportExtensionObjs, IgnoreImportErrors, DebugMode }).join(" ") << endl; out << endl; out << trUtf8("** When running the diff using two databases (%1 and %2) there's the need to specify two connections/aliases. ").arg(InputDb).arg(CompareTo) << endl; out << trUtf8(" If only one connection is set it will be used to import the input database as well to retrieve database used in the comparison.") << endl; out << trUtf8(" A second connection can be specified by appending a 1 on any connection configuration parameter listed above.") << endl; out << endl; } void PgModelerCli::parseOptions(attribs_map &opts) { //Loading connections if(opts.count(ListConns) || opts.count(ExportToDbms) || opts.count(ImportDb) || opts.count(Diff)) { conn_conf.loadConfiguration(); conn_conf.getConnections(connections, false); } //Loading general and relationship settings when exporting to image formats else if(opts.count(ExportToPng) || opts.count(ExportToSvg)) { general_conf.loadConfiguration(); rel_conf.loadConfiguration(); } if(opts.empty() || opts.count(Help)) showMenu(); //Listing connections else if(opts.count(ListConns)) { map::iterator itr=connections.begin(); if(connections.empty()) out << endl << trUtf8("There are no connections configured.") << endl << endl; else { unsigned id=0; out << endl << trUtf8("Available connections (alias : connection string)") << endl; while(itr != connections.end()) { out << QString("[") << id++ << QString("] ") << itr->first << QString(" : ") << itr->second->getConnectionString().replace(PasswordRegExp, PasswordPlaceholder) << endl; itr++; } out << endl; } } else { int mode_cnt=0, other_modes_cnt=0; bool fix_model=(opts.count(FixModel) > 0), upd_mime=(opts.count(DbmMimeType) > 0), import_db=(opts.count(ImportDb) > 0), diff=(opts.count(Diff) > 0); //Checking if multiples export modes were specified mode_cnt+=opts.count(ExportToFile); mode_cnt+=opts.count(ExportToPng); mode_cnt+=opts.count(ExportToSvg); mode_cnt+=opts.count(ExportToDbms); mode_cnt+=opts.count(ExportToDict); other_modes_cnt+=opts.count(FixModel); other_modes_cnt+=opts.count(ImportDb); other_modes_cnt+=opts.count(Diff); other_modes_cnt+=opts.count(DbmMimeType); if(opts.count(ZoomFactor)) zoom=opts[ZoomFactor].toDouble()/static_cast(100); if(other_modes_cnt==0 && mode_cnt==0) throw Exception(trUtf8("No operation mode was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if((mode_cnt > 0 && (fix_model || upd_mime || import_db || diff)) || (mode_cnt==0 && other_modes_cnt > 1)) throw Exception(trUtf8("Export, fix model, import database, diff and update mime operations can't be used at the same time!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!fix_model && !upd_mime && mode_cnt > 1) throw Exception(trUtf8("Multiple export mode was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!upd_mime && !import_db && !diff && opts[Input].isEmpty()) throw Exception(trUtf8("No input file was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(import_db && opts[InputDb].isEmpty()) throw Exception(trUtf8("No input database was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!opts.count(ExportToDbms) && !upd_mime && !diff && opts[Output].isEmpty()) throw Exception(trUtf8("No output file was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!opts.count(ExportToDbms) && !upd_mime && !import_db && !opts[Input].isEmpty() && !opts[Output].isEmpty() && QFileInfo(opts[Input]).absoluteFilePath() == QFileInfo(opts[Output]).absoluteFilePath()) throw Exception(trUtf8("Input file must be different from output!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(opts.count(ExportToDbms) && !opts.count(ConnAlias) && (!opts.count(Host) || !opts.count(User) || !opts.count(Passwd) || !opts.count(InitialDb)) ) throw Exception(trUtf8("Incomplete connection information!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(opts.count(ExportToPng) && (zoom < ModelWidget::MinimumZoom || zoom > ModelWidget::MaximumZoom)) throw Exception(trUtf8("Invalid zoom specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(upd_mime && opts[DbmMimeType]!=Install && opts[DbmMimeType]!=Uninstall) throw Exception(trUtf8("Invalid action specified to update mime option!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(opts.count(Diff)) { if(opts[Input].isEmpty() && opts[InputDb].isEmpty()) throw Exception(trUtf8("No input file or database was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!opts[Input].isEmpty() && !opts[InputDb].isEmpty()) throw Exception(trUtf8("The input file and database can't be used at the same time!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!opts.count(CompareTo)) throw Exception(trUtf8("No database to be compared was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(!opts.count(SaveDiff) && !opts.count(ApplyDiff)) throw Exception(trUtf8("No diff action (save or apply) was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); if(opts.count(SaveDiff) && opts[Output].isEmpty()) throw Exception(trUtf8("No output file for the diff code was specified!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); } //Converting input and output files to absolute paths to avoid that they are read/written on the app's working dir if(!opts[Input].isEmpty()) opts[Input]=QFileInfo(opts[Input]).absoluteFilePath(); if(!opts[Output].isEmpty()) opts[Output]=QFileInfo(opts[Output]).absoluteFilePath(); parsed_opts=opts; } } int PgModelerCli::exec(void) { try { if(!parsed_opts.empty()) { printMessage(QString("\npgModeler %1 %2").arg(GlobalAttributes::PgModelerVersion).arg(trUtf8("command line interface."))); if(parsed_opts.count(FixModel)) fixModel(); else if(parsed_opts.count(DbmMimeType)) updateMimeType(); else if(parsed_opts.count(ImportDb)) importDatabase(); else if(parsed_opts.count(Diff)) diffModelDatabase(); else exportModel(); } return(0); } catch(Exception &e) { throw e; } } void PgModelerCli::updateProgress(int progress, QString msg, ObjectType) { if(progress > 0) out << QString("[%1%] ").arg(progress > 100 ? 100 : progress) << msg << endl; else out << msg << endl; } void PgModelerCli::printIgnoredError(QString err_cod, QString err_msg, QString cmd) { out << endl; out << trUtf8("** Error code `%1' found and ignored. Proceeding with export.").arg(err_cod) << endl; out << trUtf8("** Command: %1").arg(cmd) << endl; out << err_msg << endl; out << endl; } void PgModelerCli::handleObjectAddition(BaseObject *object) { BaseGraphicObject *graph_obj=dynamic_cast(object); if(graph_obj) { ObjectType obj_type=graph_obj->getObjectType(); QGraphicsItem *item=nullptr; switch(obj_type) { case ObjectType::Table: item=new TableView(dynamic_cast(graph_obj)); break; case ObjectType::ForeignTable: item=new TableView(dynamic_cast(graph_obj)); break; case ObjectType::View: item=new GraphicalView(dynamic_cast(graph_obj)); break; case ObjectType::Relationship: case ObjectType::BaseRelationship: item=new RelationshipView(dynamic_cast(graph_obj)); break; case ObjectType::Schema: item=new SchemaView(dynamic_cast(graph_obj)); break; default: item=new StyledTextboxView(dynamic_cast(graph_obj)); break; } scene->addItem(item); if(BaseTable::isBaseTable(obj_type)) dynamic_cast(graph_obj->getSchema())->setModified(true); } } void PgModelerCli::handleObjectRemoval(BaseObject *object) { BaseGraphicObject *graph_obj=dynamic_cast(object); if(graph_obj) { scene->removeItem(dynamic_cast(graph_obj->getOverlyingObject())); //Updates the parent schema if the removed object were a table or view if(graph_obj->getSchema() && BaseTable::isBaseTable(graph_obj->getObjectType())) dynamic_cast(graph_obj->getSchema())->setModified(true); } } void PgModelerCli::extractObjectXML(void) { QFile input; QString buf, lin, def_xml, end_tag; QTextStream ts; QRegExp regexp(QString("^(\\<\\?xml)(.)*(\\<%1)( )*").arg(Attributes::DbModel)), //[schema].[func_name](...OUT [type]...) func_signature=QRegExp(QString("(\")(.)+(\\.)(.)+(\\()(.)*(OUT )(.)+(\\))(\")")), //[,]OUT [schema].[type] out_param=QRegExp(QString("(,)?(OUT )([a-z]|[0-9]|(\\.)|(\\_)|(\\-)|( )|(\\[)|(\\])|("))+((\\()([0-9])+(\\)))?")); int start=-1, end=-1; bool open_tag=false, close_tag=false, is_rel=false, short_tag=false, end_extract_rel; printMessage(trUtf8("Extracting objects' XML...")); input.setFileName(parsed_opts[Input]); input.open(QFile::ReadOnly); if(!input.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(parsed_opts[Input]), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__); buf.append(input.readAll()); input.close(); //Check if the file contains a valid header (for .dbm file) start=regexp.indexIn(buf); if(start < 0) throw Exception(trUtf8("Invalid input file! It seems that is not a pgModeler generated model or the file is corrupted!"), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { //Extracting layers informations from the tag QRegExp dbm_regexp = QRegExp(TagExpr.arg(Attributes::DbModel)), db_end_regexp = QRegExp(EndTagExpr.arg(Attributes::Database)); int attr_start =-1, attr_end = -1, dbm_start = dbm_regexp.indexIn(buf); QString aux_buf = buf.mid(dbm_start, buf.indexOf(db_end_regexp) - dbm_start), layers, active_layers, attr_expr = QString("(%1)( )*(=)(\")"); QList act_layers_ids; //Layers names attr_start = aux_buf.indexOf(Attributes::Layers); attr_end = aux_buf.indexOf(Attributes::ActiveLayers); layers = aux_buf.mid(attr_start, attr_end - attr_start); layers.remove(QRegExp(attr_expr.arg(Attributes::Layers))); layers.remove('"'); model->setLayers(layers.trimmed().split(';', QString::SkipEmptyParts)); //Active layers attr_start = attr_end; attr_end = aux_buf.indexOf('>', attr_start); active_layers = aux_buf.mid(attr_start, attr_end - attr_start); active_layers.remove(QRegExp(attr_expr.arg(Attributes::ActiveLayers))); active_layers.remove('"'); for(auto id : active_layers.trimmed().split(';', QString::SkipEmptyParts)) act_layers_ids.push_back(id.toUInt()); model->setActiveLayers(act_layers_ids); //Remove the header entry from buffer buf.remove(start, regexp.matchedLength()+1); //Checking if the header ends on a role declaration QRegExp role_regexp = QRegExp(QString("(<%1)(.)*(<\\/%2>)").arg(Attributes::Role).arg(Attributes::Role)); end = buf.indexOf(role_regexp); // If we found role declarations we clear the header until there if(end >= 0) buf.remove(0, end); else // Instead, we clear the header until the starting of database declaration buf.remove(0, buf.indexOf(QString("<%1").arg(Attributes::Database))); buf.remove(QString("<\\%1>").arg(Attributes::DbModel)); ts.setString(&buf); //Extracts the objects xml line by line while(!ts.atEnd()) { lin=ts.readLine(); /* Special case for empty tags like , they will be converted to in order to be correctly extracted further. Currently only language has this behaviour, so additional object may be added in the future. */ if(lin.contains(QString("<%1").arg(BaseObject::getSchemaName(ObjectType::Language)))) { lin=lin.simplified(); if(lin.contains(QString("/>"))) lin.replace(QString("/>"), QString(">").arg(BaseObject::getSchemaName(ObjectType::Language))); } /* Special case for function signatures. In previous releases, the function's signature was wrongly including OUT parameters and according to docs they are not part of the signature, so it is needed to remove them if the current line contains a valid signature with parameters. */ else if(lin.contains(func_signature)) lin.remove(out_param); if(is_rel && (((short_tag && lin.contains(QString("/>"))) || (lin.contains(QString("[a-z]+")) && !containsRelAttributes(lin))))) open_tag=close_tag=true; else { //If the line contains an objects open tag if(lin.contains(QRegExp("^(((\n)|(\t))*(<))")) && !open_tag) { //Check the flag indicating an open tag open_tag=true; start=lin.indexOf('<'); end=lin.indexOf(' '); if(end < 0) end=lin.indexOf('>'); //Configures the end tag with the same word extracted from open tag end_tag=lin.mid(start, end-start+1).trimmed(); end_tag.replace(QString("<"),QString("')) end_tag+=QString(">"); /* Checking if the line start a relationship. Relationships are treated a little different because they can be empty or contain open and close tags */ is_rel=lin.contains(Attributes::Relationship); if(is_rel) { end_extract_rel=short_tag=false; while(!end_extract_rel && !ts.atEnd()) { def_xml+=lin + QString("\n"); lin=lin.trimmed(); //Checking if the current line is the end of a short-tag relationship if(!short_tag && !lin.startsWith('<') && lin.endsWith(QString("/>"))) short_tag=true; end_extract_rel=((!short_tag && lin.contains(end_tag)) || short_tag); if(!end_extract_rel) lin=ts.readLine(); } close_tag=true; } else close_tag=lin.contains(end_tag); } else if(open_tag && lin.contains(end_tag)) close_tag=true; } if(!is_rel && !lin.isEmpty()) def_xml+=lin + QString("\n"); else if(lin.isEmpty()) def_xml+=QString("\n"); //If the iteration reached the end of the object's definition if(open_tag && close_tag) { //Pushes the extracted definition to the list (only if not empty) if(def_xml!=QString("\n")) objs_xml.push_back(def_xml); def_xml.clear(); open_tag=close_tag=is_rel=false; } } } } void PgModelerCli::recreateObjects(void) { QStringList fail_objs, constr, list; QString xml_def, aux_def, start_tag="<%1", end_tag="", aux_tag; BaseObject *object=nullptr; ObjectType obj_type=ObjectType::BaseObject; vector types={ ObjectType::Index, ObjectType::Trigger, ObjectType::Rule }; attribs_map attribs; bool use_fail_obj=false; unsigned tries=0, max_tries=parsed_opts[FixTries].toUInt(); int start_pos=-1, end_pos=-1, len=0; printMessage(trUtf8("Recreating objects...")); if(max_tries==0) max_tries=1; model->createSystemObjects(false); while(!objs_xml.isEmpty()) { //If there are failed objects and the flag is set if(use_fail_obj && !fail_objs.isEmpty()) { xml_def=fail_objs.front(); fail_objs.pop_front(); use_fail_obj=false; } else { xml_def=objs_xml.front(); objs_xml.pop_front(); fixObjectAttributes(xml_def); } try { xmlparser->restartParser(); xmlparser->loadXMLBuffer(xml_def); obj_type=BaseObject::getObjectType(xmlparser->getElementName()); xmlparser->getElementAttributes(attribs); if(obj_type==ObjectType::Database) model->configureDatabase(attribs); else { if(obj_type==ObjectType::Table) { //Before create a table extract it's foreign keys list=extractForeignKeys(xml_def); /* If fks were extracted insert them on the main constraints list and restarts the XMLParser with the modified buffer */ if(!list.isEmpty()) { constr.append(list); xmlparser->restartParser(); xmlparser->loadXMLBuffer(xml_def); } } //Discarding fk relationships if(obj_type!=ObjectType::Relationship || (obj_type==ObjectType::Relationship && !xml_def.contains(QString("\"%1\"").arg(Attributes::RelationshipFk)))) { object=model->createObject(obj_type); if(object) { if(!dynamic_cast(object) && obj_type!=ObjectType::Relationship && obj_type!=ObjectType::BaseRelationship) model->addObject(object); } //For each sucessful created object the method will try to create a failed one use_fail_obj=(!fail_objs.isEmpty()); } /* Additional step to extract indexes/triggers/rules from within tables/views * and putting their xml on the list of object to be created */ if(BaseTable::isBaseTable(obj_type) && xml_def.contains(QRegExp("(<)(index|trigger|rule)"))) { for(ObjectType type : types) { do { //Checking where the object starts and ends aux_tag=start_tag.arg(BaseObject::getSchemaName(type)); start_pos=xml_def.indexOf(aux_tag); end_pos=(start_pos >=0 ? xml_def.indexOf(end_tag.arg(BaseObject::getSchemaName(type))) : -1); if(start_pos >=0 && end_pos >= 0) { //Extracts the xml code len=(end_pos - start_pos) + end_tag.arg(BaseObject::getSchemaName(type)).length() + 1; aux_def=xml_def.mid(start_pos, len); //Remove the code from original table's definition xml_def.remove(start_pos, len); //If the extract object doesn't contains the 'table=' attribute it'll be added. if(!aux_def.contains("table=")) { aux_def.replace(aux_tag, QString("%1 table=\"%2\"").arg(aux_tag).arg(object->getName(true))); aux_def=SchemaParser::convertCharsToXMLEntities(aux_def); } objs_xml.push_back(aux_def); } } while(start_pos >= 0); } } } } catch(Exception &e) { if(obj_type!=ObjectType::Database) fail_objs.push_back(xml_def); else throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } if(objs_xml.isEmpty() && (!fail_objs.isEmpty() || !constr.isEmpty())) { tries++; //If the maximum creation tries reaches the maximum value if(tries > max_tries) { //Outputs the code of the objects that wasn't created out << trUtf8("\n** Object(s) that couldn't fixed: ") << endl; while(!fail_objs.isEmpty()) { out << fail_objs.front() << endl; fail_objs.pop_front(); } break; } else { printMessage(trUtf8("WARNING: There are objects that maybe can't be fixed. Trying again... (tries %1/%2)").arg(tries).arg(max_tries)); model->validateRelationships(); objs_xml=fail_objs; objs_xml.append(constr); fail_objs.clear(); constr.clear(); } } } } void PgModelerCli::fixObjectAttributes(QString &obj_xml) { //Placing objects , , outside of
if(!obj_xml.startsWith(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Tablespace))) && obj_xml.startsWith(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Table)))) { int start_idx=-1, end_idx=-1, len=0; ObjectType obj_types[3]={ ObjectType::Rule, ObjectType::Trigger, ObjectType::Index }; QString curr_tag, curr_end_tag, def, tab_name, sch_name, name_attr=QString("name=\""), sch_name_attr=TagExpr.arg(BaseObject::getSchemaName(ObjectType::Schema)) + QString(" ") + name_attr; //Extracting the table's name start_idx=obj_xml.indexOf(name_attr); end_idx=obj_xml.indexOf("\"", start_idx + name_attr.size()); tab_name=obj_xml.mid(start_idx, end_idx - start_idx).remove(name_attr); //Extracting the table's schema name start_idx=obj_xml.indexOf(sch_name_attr); end_idx=obj_xml.indexOf('"', start_idx + sch_name_attr.size()); sch_name=obj_xml.mid(start_idx, end_idx - start_idx).remove(sch_name_attr); //Configuring the table=[name] attribute to be included on rule objects tab_name=QString("table=\"%1.%2\"").arg(sch_name).arg(tab_name); for(unsigned idx=0; idx < 3; idx++) { curr_tag=TagExpr.arg(BaseObject::getSchemaName(obj_types[idx])); curr_end_tag=EndTagExpr.arg(BaseObject::getSchemaName(obj_types[idx])) + QString(">"); start_idx=obj_xml.indexOf(curr_tag); while(start_idx >=0) { end_idx=obj_xml.indexOf(curr_end_tag); len=(end_idx - start_idx) + curr_end_tag.size(); def=obj_xml.mid(start_idx, len) + QString("\n\n"); obj_xml.remove(start_idx, len); //If the object is a rule include the table attribute if(def.startsWith(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Rule)))) { start_idx=def.indexOf('>'); def.replace(start_idx, 1, QString(" ") + tab_name + QString(">")); } start_idx=obj_xml.indexOf(curr_tag); if(!def.isEmpty()) //Puts the object's defintion to the list in order to be evaluated in the main process objs_xml.push_back(def); } } } //Remove recheck attribute from tags. if(obj_xml.contains(TagExpr.arg(Attributes::Element))) obj_xml.remove(QRegExp(AttributeExpr.arg(QString("recheck")))); //Remove values greater-op, less-op, sort-op or sort2-op from ref-type attribute from tags. if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Operator)))) { obj_xml.remove(QString("greater-op")); obj_xml.remove(QString("less-op")); obj_xml.remove(QString("sort-op")); obj_xml.remove(QString("sort2-op")); } //Replacing attribute owner by onwer-col for sequences if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Sequence)))) obj_xml.replace(QRegExp(QString("(%1)( )*(=)(\")").arg(Attributes::Owner)), QString("%1 = \"").arg(Attributes::OwnerColumn)); //Remove sysid attribute from tags. if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Role)))) obj_xml.remove(QRegExp(AttributeExpr.arg(QString("sysid")))); //Replace tag by on tags. if(obj_xml.contains(TagExpr.arg(QString("usertype")))) { obj_xml.replace(TagExpr.arg(Attributes::Parameter), TagExpr.arg(Attributes::TypeAttribute)); obj_xml.replace(EndTagExpr.arg(Attributes::Parameter), EndTagExpr.arg(Attributes::TypeAttribute)); } if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Relationship)))) { //Remove auto-sufix, src-sufix, dst-sufix, col-indexes, constr-indexes, attrib-indexes from tags. obj_xml.remove(QRegExp(AttributeExpr.arg(QString("auto-sufix")))); obj_xml.remove(QRegExp(AttributeExpr.arg(QString("src-sufix")))); obj_xml.remove(QRegExp(AttributeExpr.arg(QString("dst-sufix")))); obj_xml.remove(QRegExp(AttributeExpr.arg(QString("col-indexes")))); obj_xml.remove(QRegExp(AttributeExpr.arg(QString("constr-indexes")))); obj_xml.remove(QRegExp(AttributeExpr.arg(QString("attrib-indexes")))); obj_xml.replace(QString("line-color"), Attributes::CustomColor); } //Renaming the tag to on indexes if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Index)))) { obj_xml.replace(TagExpr.arg(Attributes::Condition), TagExpr.arg(Attributes::Predicate)); obj_xml.replace(EndTagExpr.arg(Attributes::Condition), EndTagExpr.arg(Attributes::Predicate)); } //Renaming the attribute default to default-value on domain if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Domain)))) obj_xml.replace(Attributes::Default, Attributes::DefaultValue); //Renaming the tag to if(obj_xml.contains(TagExpr.arg(QString("grant")))) { obj_xml.replace(TagExpr.arg(QString("grant")), TagExpr.arg(BaseObject::getSchemaName(ObjectType::Permission))); obj_xml.replace(EndTagExpr.arg(QString("grant")), EndTagExpr.arg(BaseObject::getSchemaName(ObjectType::Permission))); } //Replace the constraint attribute and tag expression by constraint tag in . if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Domain))) && obj_xml.contains(TagExpr.arg(Attributes::Expression))) { int start_idx=-1, end_idx=-1; QRegExp regexp = QRegExp(AttributeExpr.arg(Attributes::Constraint)); QString constr_name; regexp.indexIn(obj_xml); constr_name = regexp.capturedTexts().at(0); constr_name.remove(QString("%1=\"").arg(Attributes::Constraint)); constr_name.remove(constr_name.length() - 1, 1); obj_xml.remove(QRegExp(AttributeExpr.arg(Attributes::Constraint))); start_idx = obj_xml.indexOf(TagExpr.arg(Attributes::Expression)); obj_xml.insert(start_idx, QString("\n\t\n\t\t").arg(constr_name)); end_idx = obj_xml.indexOf(EndTagExpr.arg(Attributes::Expression)); obj_xml.insert(end_idx + EndTagExpr.arg(Attributes::Expression).length() + 1, QString("\n\t\n")); } //Remove the deprecated attribute hide-ext-attribs from
and if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Table))) || obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::View)))) { obj_xml.replace(QRegExp(AttributeExpr.arg(Attributes::HideExtAttribs)), QString()); } //Remove the usage of IN keyword in functions' signatures since it is the default if absent QRegExp regexp = QRegExp(AttributeExpr.arg(Attributes::Signature)); int sig_idx = regexp.indexIn(obj_xml), len = 0; QString signature, in_keyw = QString("IN "); while(sig_idx >= 0) { signature = obj_xml.mid(sig_idx, regexp.matchedLength()); len = signature.length(); if(!signature.contains(in_keyw)) { sig_idx = regexp.indexIn(obj_xml, sig_idx + len); continue; } signature.remove(in_keyw); obj_xml.remove(sig_idx, len); obj_xml.insert(sig_idx, signature); sig_idx = regexp.indexIn(obj_xml, sig_idx + len); } //Fix the references to op. classes and families if needed fixOpClassesFamiliesReferences(obj_xml); } void PgModelerCli::fixOpClassesFamiliesReferences(QString &obj_xml) { ObjectType ref_obj_type; if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Index))) || obj_xml.contains(QRegExp(QString("(%1)(.)+(type=)(\")(%2)(\")") .arg(TagExpr.arg(BaseObject::getSchemaName(ObjectType::Constraint))) .arg(Attributes::ExConstr)))) ref_obj_type=ObjectType::OpClass; else if(obj_xml.contains(TagExpr.arg(BaseObject::getSchemaName(ObjectType::OpClass)))) ref_obj_type=ObjectType::OpFamily; else return; QString ref_obj_name=BaseObject::getSchemaName(ref_obj_type); if(!obj_xml.contains(TagExpr.arg(ref_obj_name))) return; QString obj_name, aux_obj_name, signature=QString("%1 USING %2"); QRegExp sign_regexp=QRegExp(AttributeExpr.arg(QString("signature"))); QStringList index_types; int pos=0; obj_xml.replace(TagExpr.arg(ref_obj_name) + QString(" name="), TagExpr.arg(ref_obj_name) + QString(" signature=")); IndexingType::getTypes(index_types); do { pos=sign_regexp.indexIn(obj_xml, pos); if(pos >= 0) { //Extracting the signature attribute obj_name=obj_xml.mid(pos, sign_regexp.matchedLength()); //Removing useless portions signature=" in order to retrive only the object's name obj_name.remove(QRegExp("(signature)( )*(=)")); obj_name.remove('"'); //Transforming xml entity for quote into the char obj_name.replace(XmlParser::CharQuot, QString("\"")); for(QString idx_type : index_types) { //Building a name by appe aux_obj_name=signature.arg(obj_name).arg(idx_type); if(model->getObjectIndex(aux_obj_name, ref_obj_type) >= 0) { //Replacing the old signature with the corrected form aux_obj_name.replace(QString("\""), XmlParser::CharQuot); obj_xml.replace(pos, sign_regexp.matchedLength(), QString("signature=\"%1\"").arg(aux_obj_name)); break; } } pos+=sign_regexp.matchedLength(); } } while(pos >= 0); } void PgModelerCli::fixModel(void) { printMessage(trUtf8("Starting model fixing...")); printMessage(trUtf8("Loading input file: %1").arg(parsed_opts[Input])); printMessage(trUtf8("Fixed model file: %1").arg(parsed_opts[Output])); extractObjectXML(); recreateObjects(); model->updateTablesFKRelationships(); model->saveModel(parsed_opts[Output], SchemaParser::XmlDefinition); printMessage(trUtf8("Model successfully fixed!")); } void PgModelerCli::exportModel(void) { printMessage(trUtf8("Starting model export...")); printMessage(trUtf8("Loading input file: %1").arg(parsed_opts[Input])); //Create the systems objects on model before loading it model->createSystemObjects(false); //Load the model file model->loadModel(parsed_opts[Input]); //Export to PNG if(parsed_opts.count(ExportToPng)) { printMessage(trUtf8("Export to PNG image: %1").arg(parsed_opts[Output])); export_hlp.exportToPNG(scene, parsed_opts[Output], zoom, parsed_opts.count(ShowGrid) > 0, parsed_opts.count(ShowDelimiters) > 0, parsed_opts.count(PageByPage) > 0); } //Export to SVG else if(parsed_opts.count(ExportToSvg)) { printMessage(trUtf8("Export to SVG file: %1").arg(parsed_opts[Output])); export_hlp.exportToSVG(scene, parsed_opts[Output], parsed_opts.count(ShowGrid) > 0, parsed_opts.count(ShowDelimiters) > 0); } //Export to SQL file else if(parsed_opts.count(ExportToFile)) { printMessage(trUtf8("Export to SQL script file: %1").arg(parsed_opts[Output])); export_hlp.exportToSQL(model, parsed_opts[Output], parsed_opts[PgSqlVer]); } //Export data dictionary else if(parsed_opts.count(ExportToDict)) { printMessage(trUtf8("Export to data dictionary: %1").arg(parsed_opts[Output])); export_hlp.exportToDataDict(model, parsed_opts[Output], parsed_opts.count(NoIndex) == 0, parsed_opts.count(Splitted) > 0); } //Export to DBMS else { printMessage(trUtf8("Export to DBMS: %1").arg(connection.getConnectionString().replace(PasswordRegExp, PasswordPlaceholder))); if(parsed_opts.count(IgnoreErrorCodes)) export_hlp.setIgnoredErrors(parsed_opts[IgnoreErrorCodes].split(',')); export_hlp.exportToDBMS(model, connection, parsed_opts[PgSqlVer], parsed_opts.count(IgnoreDuplicates) > 0, parsed_opts.count(DropDatabase) > 0, parsed_opts.count(DropObjects) > 0, parsed_opts.count(Simulate) > 0, parsed_opts.count(UseTmpNames) > 0); } printMessage(trUtf8("Export successfully ended!\n")); } void PgModelerCli::importDatabase(void) { printMessage(trUtf8("Starting database import...")); printMessage(trUtf8("Input database: %1").arg(connection.getConnectionId(true, true))); ModelWidget *model_wgt = new ModelWidget; importDatabase(model_wgt->getDatabaseModel(), connection); model_wgt->rearrangeSchemasInGrid(); printMessage(trUtf8("Saving the imported database to file...")); model_wgt->getDatabaseModel()->saveModel(parsed_opts[Output], SchemaParser::XmlDefinition); printMessage(trUtf8("Import successfully ended!\n")); delete(model_wgt); } void PgModelerCli::importDatabase(DatabaseModel *model, Connection conn) { try { map> obj_oids; map> col_oids; Catalog catalog; QString db_oid; catalog.setConnection(conn); //For diff we don't need the oids of all system objects catalog.setFilter(Catalog::ListAllObjects | Catalog::ExclBuiltinArrayTypes | Catalog::ExclExtensionObjs | Catalog::ExclSystemObjs); catalog.getObjectsOIDs(obj_oids, col_oids, {{Attributes::FilterTableTypes, Attributes::True}}); db_oid = catalog.getObjectOID(conn.getConnectionParam(Connection::ParamDbName), ObjectType::Database); obj_oids[ObjectType::Database].push_back(db_oid.toUInt()); catalog.closeConnection(); import_hlp.setConnection(conn); import_hlp.setImportOptions(parsed_opts.count(ImportSystemObjs) > 0, parsed_opts.count(ImportExtensionObjs) > 0, true, parsed_opts.count(IgnoreImportErrors) > 0, parsed_opts.count(DebugMode) > 0, !parsed_opts.count(Diff), !parsed_opts.count(Diff)); model->createSystemObjects(true); import_hlp.setSelectedOIDs(model, obj_oids, col_oids); import_hlp.importDatabase(); import_hlp.closeConnection(); } catch(Exception &e) { throw Exception(e.getErrorMessage(), e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e); } } void PgModelerCli::diffModelDatabase(void) { DatabaseModel *model_aux = new DatabaseModel(); QString dbname; printMessage(trUtf8("Starting diff process...")); if(!parsed_opts[Input].isEmpty()) printMessage(trUtf8("Input model: %1").arg(parsed_opts[Input])); else printMessage(trUtf8("Input database: %1").arg(connection.getConnectionId(true, true))); dbname = extra_connection.getConnectionId(true, true); printMessage(trUtf8("Compare to: %1").arg(dbname)); if(!parsed_opts[Input].isEmpty()) { printMessage(trUtf8("Loading input model...")); model->createSystemObjects(false); model->loadModel(parsed_opts[Input]); } else { printMessage(trUtf8("Importing the database `%1'...").arg(connection.getConnectionId(true, true))); importDatabase(model, connection); } printMessage(trUtf8("Importing the database `%1'...").arg(dbname)); importDatabase(model_aux, extra_connection); diff_hlp.setModels(model, model_aux); diff_hlp.setDiffOption(ModelsDiffHelper::OptKeepClusterObjs, !parsed_opts.count(DropClusterObjs)); diff_hlp.setDiffOption(ModelsDiffHelper::OptCascadeMode, !parsed_opts.count(NoCascadeDropTrunc)); diff_hlp.setDiffOption(ModelsDiffHelper::OptTruncateTables, parsed_opts.count(TruncOnColsTypeChange)); diff_hlp.setDiffOption(ModelsDiffHelper::OptForceRecreation, !parsed_opts.count(NoForceObjRecreation)); diff_hlp.setDiffOption(ModelsDiffHelper::OptRecreateUnchangeble, !parsed_opts.count(NoUnmodObjRecreation)); diff_hlp.setDiffOption(ModelsDiffHelper::OptKeepObjectPerms, !parsed_opts.count(RevokePermissions)); diff_hlp.setDiffOption(ModelsDiffHelper::OptReuseSequences, !parsed_opts.count(NoSequenceReuse)); diff_hlp.setDiffOption(ModelsDiffHelper::OptPreserveDbName, !parsed_opts.count(RenameDb)); diff_hlp.setDiffOption(ModelsDiffHelper::OptDontDropMissingObjs, !parsed_opts.count(DropMissingObjs)); diff_hlp.setDiffOption(ModelsDiffHelper::OptDropMissingColsConstr, !parsed_opts.count(ForceDropColsConstrs)); if(!parsed_opts[PgSqlVer].isEmpty()) diff_hlp.setPgSQLVersion(parsed_opts[PgSqlVer]); else { extra_connection.connect(); diff_hlp.setPgSQLVersion(extra_connection.getPgSQLVersion(true)); extra_connection.close(); } printMessage(trUtf8("Comparing the generated models...")); diff_hlp.diffModels(); if(diff_hlp.getDiffDefinition().isEmpty()) printMessage(trUtf8("No differences were detected.")); else { if(parsed_opts.count(SaveDiff)) { QFile output; printMessage(trUtf8("Saving diff to file `%1'").arg(parsed_opts[Output])); output.setFileName(parsed_opts[Output]); if(!output.open(QFile::WriteOnly)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(parsed_opts[Output]), ErrorCode::FileDirectoryNotWritten, __PRETTY_FUNCTION__,__FILE__,__LINE__); output.write(diff_hlp.getDiffDefinition().toUtf8()); output.close(); } else { bool apply_diff = true; if(!parsed_opts.count(NoDiffPreview)) { QString res, buff, line; QTextStream in(stdin), preview; buff += "\n** Press ENTER to scroll the preview **\n"; buff += "\n### DIFF PREVIEW ###\n\n"; buff += diff_hlp.getDiffDefinition(); buff += "\n### END OF PREVIEW ###\n\n"; preview.setString(&buff, QIODevice::ReadOnly); while(!preview.atEnd()) { line = preview.readLine(); res.append(line + '\n'); if(res.count(QChar('\n')) >= 30 || preview.atEnd()) { out << res; out.flush(); res.clear(); if(!preview.atEnd()) in.readLine(); } } out << endl; out << trUtf8("** WARNING: You are about to apply the generated diff code to the server. Data can be lost in the process!") << endl; do { out << trUtf8("** Proceed with the diff applying? (yes/no) > "); out.flush(); in.skipWhiteSpace(); res = in.readLine(); } while(res.toLower() != trUtf8("yes") && res.toLower() != trUtf8("no")); if(res.toLower() == trUtf8("no")) { apply_diff = false; printMessage(trUtf8("Diff code not applied to the server.")); } } if(apply_diff) { printMessage(trUtf8("Applying diff to the database `%1'...").arg(dbname)); export_hlp.setExportToDBMSParams(diff_hlp.getDiffDefinition(), &extra_connection, parsed_opts[CompareTo], parsed_opts.count(IgnoreDuplicates)); if(parsed_opts.count(IgnoreErrorCodes)) export_hlp.setIgnoredErrors(parsed_opts[IgnoreErrorCodes].split(',')); export_hlp.exportToDBMS(); } } } printMessage(trUtf8("Diff successfully ended!\n")); } void PgModelerCli::updateMimeType(void) { #ifndef Q_OS_MAC try { printMessage(trUtf8("Starting mime update...")); handleMimeDatabase(parsed_opts[DbmMimeType]==Uninstall); printMessage(trUtf8("Mime database successfully updated!\n")); } catch (Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } #endif } QStringList PgModelerCli::extractForeignKeys(QString &obj_xml) { QStringList constr_lst; int start=0, end=0, pos=0, count=0; QString start_tag=QString("<%1").arg(Attributes::Constraint), end_tag=QString(" 0 && end > 0) { count=(end - start) + end_tag.size() + 1; constr=obj_xml.mid(start, count); if(constr.contains(Attributes::FkConstr)) { obj_xml.remove(start, count); constr_lst.push_back(constr); pos=0; } else pos=end; } else break; } while(pos >= 0 && pos < obj_xml.size()); return(constr_lst); } bool PgModelerCli::containsRelAttributes(const QString &str) { bool found=false; static vector attribs={ Attributes::Relationship, Attributes::Type, Attributes::SrcRequired, Attributes::DstRequired, Attributes::SrcTable, Attributes::DstTable, Attributes::Points, Attributes::Columns, Attributes::Column, Attributes::Constraint, Attributes::Label, Attributes::Line, Attributes::Position, Attributes::Identifier, Attributes::Deferrable, Attributes::DeferType, Attributes::TableName, Attributes::SpecialPkCols, Attributes::Table, Attributes::AncestorTable, Attributes::CopyOptions, Attributes::CopyMode, Attributes::SrcColPattern, Attributes::DstColPattern, Attributes::PkPattern, Attributes::UqPattern, Attributes::SrcFkPattern, Attributes::DstFkPattern }; for(unsigned i=0; i < attribs.size() && !found; i++) found=str.contains(attribs[i]); return(found); } void PgModelerCli::handleMimeDatabase(bool uninstall) { SchemaParser schparser; QString msg_file_associated=trUtf8("Database model files (.dbm) are already associated to pgModeler!"), msg_no_association=trUtf8("There is no file association related to pgModeler and .dbm files!"); printMessage(trUtf8("Mime database operation: %1").arg(uninstall ? QString("uninstall") : QString("install"))); #ifdef Q_OS_LINUX attribs_map attribs; QString str_aux, //Configures the path to the application logo exec_icon=QDir(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + QString("pgmodeler_logo.png")).absolutePath(), //Configures the path to the document logo dbm_icon=QDir(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + QString("pgmodeler_dbm.png")).absolutePath(), //Path to directory that register mime types mime_db_dir=QDir::homePath() + QString("/.local/share/mime"), //Path to the file that associates apps to mimetypes mimeapps=QDir::homePath() + QString("/.local/share/applications/mimeapps.list"), base_conf_dir=GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::SchemasDir + GlobalAttributes::DirSeparator, //Files generated after update file association (application-dbm.xml and pgModeler.desktop) files[] = { QDir::homePath() + QString("/.local/share/applications/pgModeler.desktop"), mime_db_dir + QString("/packages/application-dbm.xml") }, schemas[] = { base_conf_dir + QString("desktop") + GlobalAttributes::SchemaExt, base_conf_dir + QString("application-dbm") + GlobalAttributes::SchemaExt }; QByteArray buf, buf_aux; QFile out; //When installing, check if the necessary file exists. If exists, raises an error and abort. if(!uninstall && (QFileInfo(files[0]).exists() || QFileInfo(files[1]).exists())) { throw Exception(msg_file_associated, ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(uninstall && (!QFileInfo(files[0]).exists() && !QFileInfo(files[1]).exists())) { throw Exception(msg_no_association, ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else if(!uninstall) { QString startup_script=QString("%1/start-pgmodeler.sh") .arg(QFileInfo(GlobalAttributes::PgModelerAppPath).absolutePath()); attribs[Attributes::WorkingDir]=QStandardPaths::writableLocation(QStandardPaths::HomeLocation); attribs[Attributes::Application]=(QFileInfo(startup_script).exists() ? startup_script : GlobalAttributes::PgModelerAppPath); attribs[Attributes::Icon]=exec_icon; } try { for(unsigned i=0; i < 2; i++) { if(uninstall) { if(!QFile(files[i]).remove()) throw Exception(trUtf8("Can't erase the file %1! Check if the current user has permissions to delete it and if the file exists.").arg(files[i]), ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); } else { schparser.loadFile(schemas[i]); buf.append(schparser.getCodeDefinition(attribs)); QDir(QString(".")).mkpath(QFileInfo(files[i]).absolutePath()); out.setFileName(files[i]); out.open(QFile::WriteOnly); if(!out.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(files[i]), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); out.write(buf.data(), buf.size()); out.close(); buf.clear(); attribs[Attributes::Icon]=dbm_icon; } } out.setFileName(mimeapps); //If the file mimeapps.list doesn't exists (generally in Ubuntu) creates a new one if(!uninstall && !QFileInfo(mimeapps).exists()) { out.open(QFile::WriteOnly); out.write(QByteArray("[Added Associations]\napplication/dbm=pgModeler.desktop;\n")); out.write(QByteArray("\n[Default Applications]\napplication/dbm=pgModeler.desktop;\n")); out.close(); } else { out.open(QFile::ReadOnly); if(!out.isOpen()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(mimeapps), ErrorCode::FileDirectoryNotWritten,__PRETTY_FUNCTION__,__FILE__,__LINE__); //Opens the mimeapps.list to add a entry linking pgModeler to .dbm files buf=out.readAll(); out.close(); QTextStream ts(&buf); while(!ts.atEnd()) { //Remove any reference to application/dbm mime from file str_aux=ts.readLine(); str_aux.replace(QRegExp(QString("application/dbm*"),Qt::CaseSensitive,QRegExp::Wildcard),QString()); if(!str_aux.isEmpty()) { //Updates the application/dbm mime association if(!uninstall && (str_aux.contains(QString("[Added Associations]")) || str_aux.contains(QString("[Default Applications]")))) str_aux.append(QString("\napplication/dbm=pgModeler.desktop;\n")); else str_aux+=QString("\n"); if(str_aux.startsWith("[") && !str_aux.contains("Added Associations")) str_aux=QString("\n") + str_aux; buf_aux.append(str_aux); } } //Write a new copy of the mimeapps.list file out.open(QFile::Truncate | QFile::WriteOnly); out.write(buf_aux.data(), buf_aux.size()); out.close(); } //Update the mime database printMessage(trUtf8("Running update-mime-database command...")); QProcess::execute(QString("update-mime-database"), QStringList { mime_db_dir }); } catch(Exception &e) { throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } #else #ifdef Q_OS_WIN //Checking if the .dbm registry key exists QSettings dbm_ext(QString("HKEY_CURRENT_USER\\Software\\Classes\\.dbm"), QSettings::NativeFormat); QString exe_path=QDir::toNativeSeparators(GlobalAttributes::PgModelerAppPath); //If there is no value assigned to .dbm/Default key and the user wants to uninstall file association, raises an error if(uninstall && dbm_ext.value(QString("Default")).toString().isEmpty()) throw Exception(msg_no_association, ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); else if(!uninstall && !dbm_ext.value(QString("Default")).toString().isEmpty()) throw Exception(msg_file_associated, ErrorCode::Custom,__PRETTY_FUNCTION__,__FILE__,__LINE__); else { if(!uninstall) //Write the default value for .dbm registry key dbm_ext.setValue(QString("Default"), QString("dbm_auto_file")); else dbm_ext.remove(QString()); dbm_ext.sync(); } //Other registry keys values map confs = { { QString("\\HKEY_CURRENT_USER\\Software\\Classes\\dbm_auto_file"), { QString("FriendlyTypeName") , QString("pgModeler Database Model") } }, { QString("\\HKEY_CURRENT_USER\\Software\\Classes\\dbm_auto_file\\DefaultIcon"), { QString("Default") , QString("%1,1").arg(exe_path) } }, { QString("\\HKEY_CURRENT_USER\\Software\\Classes\\dbm_auto_file\\shell\\open\\command"), { QString("Default") , QString("\"%1\" \"%2\"").arg(exe_path).arg("%1") } }, { QString("\\HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.dbm"), { QString("OpenWithList/a"), QString("pgmodeler.exe"), QString("OpenWithList/MRUList"), QString("a")} } }; map::iterator itr; itr=confs.begin(); //Iterates over the configuration map writing the other keys on registry while(itr!=confs.end()) { QSettings s(itr->first, QSettings::NativeFormat); if(uninstall) s.remove(QString()); else { for(int i=0; i < itr->second.size(); i+=2) s.setValue(itr->second[i], itr->second[i+1]); } s.sync(); itr++; } #endif #endif } pgmodeler-0.9.2/main-cli/src/pgmodelercli.h000066400000000000000000000140411360462764600206150ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /** \ingroup pgmodeler-cli \class PgModelerCli \brief Implements the operations export models whitout use the graphical interface */ #ifndef PGMODELER_CLI_H #define PGMODELER_CLI_H #include #include #include #include "exception.h" #include "globalattributes.h" #include "modelwidget.h" #include "modelexporthelper.h" #include "generalconfigwidget.h" #include "connectionsconfigwidget.h" #include "relationshipconfigwidget.h" #include "generalconfigwidget.h" #include "databaseimporthelper.h" #include "modelsdiffhelper.h" class PgModelerCli: public QApplication { private: Q_OBJECT XmlParser *xmlparser; //! \brief Export helper object ModelExportHelper export_hlp; //! \brief Import helper object DatabaseImportHelper import_hlp; //! \brief Diff helper object ModelsDiffHelper diff_hlp; //! \brief Reference database model DatabaseModel *model; //! \brief Graphical scene used to export the model to png ObjectsScene *scene; //! \brief Stores the configured connection Connection connection, //! \brief Stores the extra configured connection (only for diff) extra_connection; //! \brief Loaded connections map connections; //! \brief Connection configuration widget used to load available connections from file ConnectionsConfigWidget conn_conf; //! \brief Relationship configuration widget used to load custom relationship settings RelationshipConfigWidget rel_conf; GeneralConfigWidget general_conf; //! \brief Creates an standard out to handles QStrings static QTextStream out; //! \brief Stores the long option names. The boolean indicates if the option accepts a value map long_opts; //! \brief Stores the short option names. attribs_map short_opts; //! \brief Stores the parsed options names and values. attribs_map parsed_opts; //! \brief Indicates if the cli must run in silent mode bool silent_mode; //! \brief Stores the xml code for the objects being fixed QStringList objs_xml; //! \brief Zoom to be applied onto the png export double zoom; static const QRegExp PasswordRegExp; static const QString PasswordPlaceholder; //! \brief Option names constants static const QString Input, Output, InputDb, ExportToFile, ExportToPng, ExportToSvg, ExportToDbms, ExportToDict, ImportDb, Diff, DropDatabase, DropObjects, PgSqlVer, Help, ShowGrid, ShowDelimiters, PageByPage, IgnoreDuplicates, IgnoreErrorCodes, ConnAlias, Host, Port, User, Passwd, InitialDb, Silent, ListConns, Simulate, FixModel, FixTries, ZoomFactor, UseTmpNames, DbmMimeType, Install, Uninstall, NoIndex, Splitted, IgnoreImportErrors, ImportSystemObjs, ImportExtensionObjs, DebugMode, CompareTo, SaveDiff, ApplyDiff, NoDiffPreview, DropClusterObjs, RevokePermissions, DropMissingObjs, ForceDropColsConstrs, RenameDb, TruncOnColsTypeChange, NoSequenceReuse, NoCascadeDropTrunc, NoForceObjRecreation, NoUnmodObjRecreation, TagExpr, EndTagExpr, AttributeExpr; //! \brief Parsers the options and executes the action specified by them void parseOptions(attribs_map &parsed_opts); //! \brief Shows the options menu void showMenu(void); //! \brief Returns if the specified options exists on short options map bool isOptionRecognized(QString &op, bool &accepts_val); //! \brief Initializes the options maps void initializeOptions(void); /*! \brief Extracts the xml defintions from the input model and store them on obj_xml list in order to be parsed by the recreateObjects() method */ void extractObjectXML(void); //! \brief Recreates the objects from the obj_xml list fixing the creation order for them void recreateObjects(void); //! \brief Fix some xml attributes and remove unused tags void fixObjectAttributes(QString &obj_xml); /*! \brief Extracts the foreign key code for the specified table xml. The foreign keys are recreated after all the other objects */ QStringList extractForeignKeys(QString &obj_xml); //! \brief Returns if the specified string contains some of relationship attributes bool containsRelAttributes(const QString &str); /*! \brief Install the .dbm file association in the mime database (default behaviour). The paramenter 'uninstall' is used to clean up any file association done previously. */ void handleMimeDatabase(bool uninstall); /*! \brief Fixes the references to opertor classes and families by replacing tags like by . This method operates only over operator classes, indexes and constraints */ void fixOpClassesFamiliesReferences(QString &obj_xml); void fixModel(void); void exportModel(void); void importDatabase(void); void diffModelDatabase(void); void updateMimeType(void); void configureConnection(bool extra_conn); void importDatabase(DatabaseModel *model, Connection conn); void printMessage(const QString &msg); public: PgModelerCli(int argc, char **argv); ~PgModelerCli(void); int exec(void); private slots: void handleObjectAddition(BaseObject *); void updateProgress(int progress, QString msg, ObjectType = ObjectType::BaseObject); void printIgnoredError(QString err_cod, QString err_msg, QString cmd); void handleObjectRemoval(BaseObject *object); }; #endif pgmodeler-0.9.2/main/000077500000000000000000000000001360462764600144425ustar00rootroot00000000000000pgmodeler-0.9.2/main/main.pro000066400000000000000000000035741360462764600161210ustar00rootroot00000000000000# main.pro (reviewed version) # # Refactored by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # Reviewed by: Raphal Araújo e Silva # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(../pgmodeler.pri) TEMPLATE = app TARGET = pgmodeler windows:RC_FILE=res/windows_ico.qrc windows:RCC_DIR=src/ windows: DESTDIR = $$PWD HEADERS += src/application.h SOURCES += src/main.cpp \ src/application.cpp unix|windows: LIBS += -L$$OUT_PWD/../libpgmodeler_ui/ -lpgmodeler_ui \ -L$$OUT_PWD/../libobjrenderer/ -lobjrenderer \ -L$$OUT_PWD/../libpgconnector/ -lpgconnector \ -L$$OUT_PWD/../libpgmodeler/ -lpgmodeler \ -L$$OUT_PWD/../libparsers/ -lparsers \ -L$$OUT_PWD/../libutils/ -lutils INCLUDEPATH += $$PWD/../libpgmodeler_ui \ $$PWD/../libpgmodeler_ui/src \ $$PWD/../libobjrenderer/src \ $$PWD/../libpgconnector/src \ $$PWD/../libpgmodeler/src \ $$PWD/../libparsers/src \ $$PWD/../libutils/src DEPENDPATH += $$PWD/../libpgmodeler_ui \ $$PWD/../libobjrenderer \ $$PWD/../libpgconnector \ $$PWD/../libpgmodeler \ $$PWD/../libparsers \ $$PWD/../libutils # Deployment settings target.path = $$BINDIR INSTALLS = target macx { macdeps.files = $$PWD/res/Resources $$PWD/res/Info.plist $$PWD/res/PkgInfo macdeps.path = $$PREFIX macscript.files = $$PWD/res/startapp macscript.path = $$BINDIR INSTALLS += macdeps macscript } # Print the current build settins (see pgmodeler.pri) printBuildDetails() pgmodeler-0.9.2/main/res/000077500000000000000000000000001360462764600152335ustar00rootroot00000000000000pgmodeler-0.9.2/main/res/Info.plist000066400000000000000000000026461360462764600172130ustar00rootroot00000000000000 CFBundleDocumentTypes CFBundleTypeRole Editor CFBundleTypeExtensions dbm CFBundleTypeIconFile pgmodeler_dbm.icns CFBundleTypeName pgModeler Database Model CFBundleIconFile pgmodeler.icns CFBundleExecutable pgmodeler CFBundleDisplayName pgModeler CFBundleIdentifier br.com.pgmodeler.pgModeler CFBundleInfoDictionaryVersion 1.0 CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 0.9.2 CSResourcesFileMapped NSPrincipalClass NSApplication NSHighResolutionCapable True pgmodeler-0.9.2/main/res/PkgInfo000066400000000000000000000000111360462764600165030ustar00rootroot00000000000000APPL???? pgmodeler-0.9.2/main/res/Resources/000077500000000000000000000000001360462764600172055ustar00rootroot00000000000000pgmodeler-0.9.2/main/res/Resources/empty.lproj000066400000000000000000000000001360462764600214010ustar00rootroot00000000000000pgmodeler-0.9.2/main/res/Resources/pgmodeler.icns000066400000000000000000004020321360462764600220420ustar00rootroot00000000000000icnsis32 {vtHKMdk{_xXP·XuwVȷaSriTjĸtHthgUvȾHhb_V`¼U;\J S\Eƺja*, YTP>wu[+,]4-GWfqJ!^%PSilyqVcŗbVӧrȅaͫǿV~sdbĀѮ{rd1gm]-^gYnWj\h/YwYSy]0,F>4Ky3Tʩ/Գqa9Q˭.sΰïRLK~y!8eiNoUm6ƹcX5ZW?.|oVg7>%OQӜiրxWwԦeVvݜ%༆Fzͺop›ٍ̉p̭3pĽŀiͫ/^i[z_ĹonyϮ1ZyYۘ\e9,H@6{S%OQs8mkE̵Du|o'&'''?'@KAR>76<ɥ(Dx%X\5il32 iv{kejjl[]__^\ZXVVUhlRGy{{vWWONNQVYOh¾qj?-}wP?VfidWG=;DGi»b8jM@yoAeɶzX:CIJc.omrslNGyw?qÿ]=flqStWF]:{RRbhpoWT[X;xľB7nW{~yybTR`h<¼~1tc}}UTR_d:þC=`|~vvTUR^b:ÿi%Q|yqqTUS\c;¿):qlhkOVTZaC[7!BAAB? VTY\S5ƹZCA?A:669ztlb4 LV~SHJIDa`^]U=5$$lnkh5 KL;pea\<(bok_% JKmb`Z9NogX JMUj`[/ gd] ,7886MBjec_.^`SXrW][F>?>B8H[UH?{ L:TTP,Ʒu9k] Yec6! 3=tBnb6"" WoT_]A465/.56266:(Ľk]nT=\F¯a}sQ-UO@҉j±Q*X_2a~DH.XdYjaYHpaN;.l85<Yn]qKgP-U4TYaW~rLh?)~D}Chv[VRdiiLhDtb3B@ 4COOMNOFh ?=pɽF8:#"RZ!? S¨C;z'QAnÒ'`waīD}˜"/t6!v Dqj]`Zn!`iVx[7ĵs-TH淼+ J[q̸H!1llvtf(749'ѹƥ}yϱϏokMm=O`e`UKK\`8~iB`ϯXAGðaNñhp>pl;dU|?q6w|QĿɿKwO$6Uө½GΧ0D^ߓ¼DW\Ւ½FˑUє¿Vô%A¸¿{YĽ?D3¿ҷ4oHźS@dz_¿r?وʪ]1VUBtȻ].Yh4hIżT3Yf[lb\IwӣmWA0{@=CYo^sLoX0V<aYcYtMoE,ΔDzO}ű]XSfkkNnƿK t8DK#;>QPOPRGr HHmnbZ/9;$!5c_]Sqd#J _yg[4;8+(oKNӉ, ^Ùi~yh[1q?21}~VV(srÞ^ffc]5/60eyuT]%5W\Z\W #843NXXK^# Nq -0/$ "N#wYxi 8Ŷs0(Z_Uxrƿ/)_`rǺR#8mɧn'749'l8mk%$%mNAECI&  +  )9;9999989A9g9k9k5kkkkeT3_`_`^_a`e_b`d+36 M>;<=?)ю)"A=>>>?7ih32MAffSVSTUVVWXYZ[X(q$urm{}^DAƺ_B-CǺ~&usnxcEA|72|"Ei*ghh_cpznxsK;¾=.&suqr[AR46ckqZCXTZ]b\^[VXTXVLE:w'1Z`Nhzwvvtv`\ZU\bbL8¾O) q]m{{I,[XS^hdH?'=zZk|wzF,[YT\ebDFL"\Yk{xrvG,[YT\daBG¿s">Qk{wtnsG\[YT[b`CD¿4(Bi|vrnhoG[ZTZ``H9N5i{vsqltJ'[ZUZ^_O0c"GUPQ+W3 [ZUY]]U3aq#!5B@??J [[UX\ZY@5ƽy$iy,#.-+*)(F[[VXZXYM/Wu~"2~{/!..,+))E[\VWYXVT@+lT|z1++*)('E[\WVXVUTM8*hKo}yy4**)(&%D]^ZWVVUSRG4'Jf1~zwt+))'&%#DSVRPJKJJINI6'(HlzZ$~{xuq(''&%$"DvIG<0$&rDNxttg'&%#"!D֎CKHC>842'$}54#HpsW&$#"!C ӄDIFEDCA?5"){lNuq= %$#! C ԆCHECB@?><0&p^#Wm ! C -ԆCFCBA?><;9,Z~y*,{:%L 0**)(''A<ԅBDB@?><;:96*@yysA!A:awsuutyeI׋CECA@>>;8764)muqwrik-1 =qBLIJIPB455'Exomhil2 3 ,_iedcb_ND25(4tolhkc+ 2 "&,ƷzPA2-*nojglX 2 &]94{yMA/eohfkJ 2 9L9xxMB$OpfeiE  0 &]E@uxMA"hfcfL%.221016 ]JFrxM@(fa_c' +Sb`b fXWz||{m]RNozP?]^[^4 -hW^Z]QPOF@I^WVW8 W8A#$[SRNY+Du}|ifc>% 7VNQH ?\ic>"$ :H3Hù\ic=!%  X]ke:  'k[a]NACBB?:79;L>̱c;%AŸ{&w>?˻60z'Z*I8Ǫ=,$m5-b\g0YK_ƒ&w-ewprrqxL/d6W-dz"z**^ '[ʀ 51 u c uƩZ4o K p¿P{Ĵ7j PIp0.k l3$Gr`!)!q +TTNNMLKLnI40( P]+x +[~m]KK.;/Wq: ZucNH(cL L $WtaMHt%tp ^ TrwwsbMHnl/'y5-b1v #Q`ecdaNGv!JR$&RN8R_ONQQPQLK{8 7qNDBAC>T T?)[ƿ &c=3#Qƾ &\ʮ /w $Q}ƾ &ql̬%b .U¿ VlˬihY6] &xr˫9g EsDz{uˀ˫+). DLpcddcgV{ů@EzxytuheO/uÿj*~}z9 SľĻUQ|rOʾ 'WqN5[·" (_qM-1Gba4>;<<>:q@&('  wB ʽÇΏŀ„`$Ľȥʹuľ$ɿyF406::7306DYxԾs¼|$J2R«kK0'4bw|$»;?پi=$Bƹ|&ü:B̖80z-v*»K9ۼA,%ĻŊ;SԶ45_flW p^3Ԗ%"./(ˤc2]& RV5},ƿT;˫)2I3x,ƿSB]:2y,ƿOCə!,-y\ƿV?<'xǿo1½e!~'؎%Ɖ!|Z] Ҵ/iʸ=\-¸ќ"Ž,,IJ ӡ'`ـ܌ͥ 85!¯ k|ظbɰ:¯ ̽PxU¼>z 5θWMz33{ %x5$K{h!ƹ-$ $VVPPONMNŧ{Q94* ¿·[l/ +\o_MM÷1οC-eĮ A \wePJƀ˘*̼ĘtY W $XucOJɃ'ʸć"m #UtxxtdOJ|{»4%x25t8Àȶ "ScfefcPJŀSÆ"Ta++b [~Q]QPTSSTNNÿȋA>YzwpkdabPEC%D@^aI/j^zk\d&3>:877'aͽpE;(^]yj]c& !Trdm^a]^]^Y`0Fzxysf;\="~OĽbldfik0Ahgf;]//5P4E?>A40&$=ACEſaeS˿,nd;_ø& /luZ5:Stüg3>;<<>:}ɲE(**+*) wBh8mk /FABBBBBBBBBBBBC=?زgdfugsgtgtjrYx 1 THSRTQTQTRTRTOT\TTTSTIm } fzwxyu  #    u 5666667$^feeg[XVVVUگÈ ^6%('''(! it32nffehjlnmpZ4A99UbacX8 0[ffecba`i>g^TUVUVUVXldV{|k|}vCcMU\ZYYXWWVVUUTSRRQPQPPONNMChG Io|qrsrssrxz6cQbjhiihgffedca``__^^]\[[ZZYYXWVHkw27pptz}|{zywwppx.gQ`fc]XZTSSRRWVUUV\Z\\]\\ZZYXYYXW VVUUTTUGls³(!`pt~||tr{)QOMLLGEDEEDBABFGOQPUYXWVWVUTSTGlq%"Wpu}~}{yyunjF?HGFFHGGFFGFEDBBAA@@?BEDFONRVUTSTGlq¿%)Wpu}~}{y{wdMEJJHHGIHHIHDCCB@@BAADCBCA?'>>=?CDLORSSRRSGlq¿%[Wpu|~}z{|jRFHIHHIIH@>>:;LNMQTQJMK;69:89?AB@@?>=<<;=?EKOQQFk q%[Wpuz~}z|v]GHIHHJH?=Bayżrj[D:688<@?>><;;::=DJClp¿%[Wpuy~|z{rPDIIHII=CfͭbZH3579?=<<;99:9W o¿%[Wpuy}|z}hJGJHHKBApŭzNG0369<;;989c$[Wpux~|z}fEHIHHK;XÿtK>036;:99>UǾ$[Wpvw~|z|cEIIHHG:~_A12886/J$ Wpvv}}z|lFHI?U238807~$=Wovt{zztKGHHGI8C.674.u$Wovs~zy{UEHHGI?EZ05640q$[Wovr}x{hEIGGI>oq-553/s$[Wovr|xwTEHFGF@j*340<}$ WounvtqJGEH;e-33.@p %mTLo|oqtXDHGFDLX)32-O|$T~jwwvzVCGFH9D-20. /iA( 5IEG@3/00/@PZ^_`V-jqtuti;ʧK_`X^[YSCFEE@[m)0/.AB7ҀU>$*&0LO^)xr|}|zyxvutrponmf{_?]XWebba``I>AB5срVb!)'(>IX)wqz~{zxwutsqpomkke{_?]XVdaa`_aI=@A3πс΀Tz+&(%4CR'vqy}zxxwtsqponlkid{_?]XUd` _`Q>?A1р ƀK?"'&&@3y͂΁W\('#4G#spwzxwutsponmkihgb{_?]XUc`__^^V=>?:M̀Xs'%A!pmqurqpnmljihfecc^z_?]XUb__^^]ZD<=;C΁ɀB1!%#,>otpro`?]XTb^ \\H:=<7ȀɀȀBE%#&2`qtsxX?]YTa^^]]\[L;h$#"(7GTYZY\>?]YS`]]\[\ZWC:;;5ŀ:{/ $!'3ANTVWXSkT?]YS_]\\[[YZI9;<0n:ms~0""!(,--,+* ))(('&]Q?]YR^\[ZYYQ;9;8A9|i%m}7#"!)./..-, ++**))aO?]YR_[ZYYXWD79;.qɽ>k"(&!g|W#! (-.//.-,*))aNa?]YQ^[[ZZYXXWN98879¼]~u )'&!h~{\"!&,.- ,,++**))'(aN ?]YQ^Z[ZYX VS@6790bĻH7&%''$$|~}z]! %+.-.--,++*)(('(aN?]YQ\ZZYYXXWVTK9779-Ʒ]7,_ G}|z^!#*-,-,+**))(''aN?]YP\YXYYXWWVTRB56748=%Uo<;c}}|y~^ #),+**)(%'aN?]YO\XWWVUTRM<46618]'}|zx{e!(+,,+**))(%'aN?]YP[XYWVRTSPF6557.E%7~}|ywyi#!'+*))(''&$&aN&?]YO[XXWWVVUTTSQM@4546.H<< [~}|zywxl&'**++*)('&$%aN ?]YOZWVWVUTTSQOJ=1435-<>f#)~}|zyxvvn(%)*)(('&%$%aN ?]YNZWVVUTTSRRQMF72324.3{8}(&C}|{yxwuwe!%)*('&%#%aN ?]YNYVVUUTSRRQPOKF92 30'U90)#s~}|yyxvtxZ%)('('&%$#%aN?]YOZWVUUTRPOKD:212)2g<7('A~}|zywvtrwW%())(''&%#$"$aN?]WDMKKJIHGFEB=7100/1.&5^9%+%$~}|zyywutrwX%(''&&%%$%$#"#aN~]jZ]]^L\YN<;2-.//0,%+Hhi/&,#k~}}{zxwvttqvR%(''&%$##!#aN5yASOLKMJN]i@D=4.,,-/0.'#+,--,#(,#Q~}|{yywvutrouV%'&&% $##"" "aNxf[VUTY1iCID?82,))(,--,+*+*+*)'1,~}|}{yyxvutsqos5%'&&%#"!! #aNւ؄N}lDJHFA=81,(&#!#&%%"#*()!EB%%/r{zyxwutsqqoq%%&%$$#"!!"aN Ѷ|lDJIGFCA=950,)'$#" "(3)Wp)!n~xxwutsrqonj% %&%%$$##""!"aNa˽ձ|lDJIHGEECA?;8521.--,*(('( h}'" -yxvuutrppmrV %&%$$# "!! !aNb˾״wmDIIHGGFEDCB@><:98775,&&'$&F#w{!>sttrqpolqJ!$%##""!"! !aNֳ̽umDHGFFEEDCBB@??>=<;7*%%&#+z7u! g`"F|srqpnmlo+!%$%%#$#"!"!!  aN̼׳tmDIHGFFEDCBBAA@??>=;5'%$&!)y"R..Gyopomln`"$#"!  aNֳ̻tmCGFFEEDC@BBA@@??>=91&$$& )yBX*IxnmmjpI"#$$#"!!  aNֳ̻tmCGGFFEECDCBBAA@??==;7/$##$ %r$*"Prjlij("#$"!! aNֳ̺tmCFFEDDCBBA@??>=<95-"##(i~4e\qgm^!#"!!  bN̹׳tmCFEEDCBBA@?=>>=<<;83+"!!#X|I.ofl5!#"##"!! bN ֳ̹tmCEEDDCCBA@??>=<;961( !!" D~}2r$QNqZ ! bNͷށ׳tmBEDDCBA@?>=<<;;9850( 1r}|xZ.TdgbZ=<;:9874/' ' Z~{{zyw}e* TQC_dijkgvPͶ؆ ׳tnBDCBA@?>==<4;;::98853.( 9x|yxxvtxuO*2i"R];13 ͵ׇ ֳtnBCBBA@@??>>=<<;;::9887752.( %A~xwvutssvv[SH#&#'DMj: ZDʹӁ ֳtnBCBBA@?>?>=<;;:9 8776542.( 'syuutsrqportqmkjsG^D+͵ՀՁ ٵtnBCBBA@??>>=<;;::847765441.(/wvttsqqponlkjihhefV `D&ͫtl>==<;:9988;977654420*(U}rtrqqpnmlkjihhfhc aE' ċtuYZ[[ZZ[ZXJ9625544335-xssrqppnmlkjihgefb(!aE'eWWVUmX6766554324&fvqqppommlkjhdgi" !bE'N311.-,. S[56654/33 Uxpqqpomllkihhgdk['!bE'icdbbaa``]c; 3YA9<=A!&NJˠBbiZkm*eq(R\..>haba``__^\`3 =\W`a`cOBbiYkk&eq(R\..7f`a``^^]\[a: Cb*BbiYkkfq(R\.-# b__^]\[Y^C Ca(BbiYlc{xyxyxyywap(R\.,%Tb\'[ZZYYX[3  ?](ĭBbhWqjhglv)R\.+* Fb[\[ZYX"WTb?  1V&@^dUdged%S\-*+"^YZYX$WUUTRWP. K" 7#  X[-*+!P^W&VVUUTSSPQY1 :ZZ,*)& (]VWU$TSRRQPONT .g \Z,))( F[TUSSRQ PONKS *} ^Y,)(($ WSSQ#PPONMLMK )x89_Y+)(&& *VPQPPONMMLJP- .w _Y*()&&#9TNONL JLN/ /y E_Y*((&%$)DQKLKJKND$ 0}¿8E_Y*''&%##  GPNNOD$ 38E_Y*&'&%$"   %78  #:Ŀ8E_Y)&&%%$#!   'C!¼E_Y(%%$%$"! #  /N%E_Y)%%$##"!   8X'E_Y)%%$#,!!  @`(E_Z(#$"!   Ec*E_V'$$# ""!  Cc'zcE`fVZ [Z[[ZZYWURPON PSUXYX_nCM^[YWVTSRQ RTUUVWXO }7*n/x~ľmtbr{íJtF _e¯Āü:m0;ڔS˸}|5i¿($~ߓPfSWD89;=<<:75>QOPY3h$t䓙O>=@A@EGFEFFE2B<=<;873HVRd3g¿$)t䓙}P@EGGFFGGEFFA@@>=>?>?C.BCBA;78754CY`3g$[t䓙XADHEEGGE=:;79JMLQSOHKI835766<@A?@?>:552=Np3g¿$[t䓙lABHFEHE=9?`{Ʒwm\C83549>>==<9416Kx3f¿$[t䓙T>HGEGF:Aeݸe\G/247=<<;94/5S-e$[t䓚GDHEFI>=pػOF,137;;97/5!a$t䓚~AFGEFH7W=Ϲ{L=+049976;Sż$[t䓚y@GFEFE6ǮeA./764-H$[t䓚AFFEFE=ȷX/076.5|$[t䓚KEFEEG8¿‘D+662+s$[t䓚_?FEDG:Ĵ^+332.o$t䓛@FEEF;oEz*320.r$ t䒛]@FD@Bv&22.:z$ t㒚IDSG8m)21,>n$"/Zߒo@EDCAJ8\%20+Nx$a=ECF5=H+0/+ ?Y|C) 5FBCC>0-/.4ay??DCD=[E|%/-*NzF ŲkBBCE4R&/-'rCt:DBD6Z,+-'IǷ?m8DB?F Pj$.,(o=}h:CA>KU3)-&B=}e:BA<|c8AA3߀Tb*'+m<|c8@@4܀ڀM&((!J{;|b7@?4݁߁XA!(#6mu;|e6??3܂[p)%'Vn9|e3??0ځ܁׀M)$&"Bf}8|8>?-ـ܁ڀ׀Ā8B'$)Zt5| <}$"Ho ]1:93ҁӀҁ΀:2#>oͦ {1::,sЀҀπ>þ}4"/[u<795Aρ̀ʀ9ćz#~:!*\t l098*xρ̀ɀ:ɢrƽ($xa"(Xn 86757́΀̀ɀ$¿`˺(%${r! Kl  a-87-eˀ̀̀ɀŮ6»,%%&&#"r!Ei =456*́ʀƀ=d7nPt!Deu,7536ɂƁÀ Į"`ƹ(B@tv Cc} X,65/7ɀŀ:cĸ}@a|8045,DƁ>Ɠ!7>`y  3233+H€À==`÷">^w x,023*: p '+$>\tl4.22,2nj%%D%~?[ux4*11/#Xž:Ħ.( s@\uG*.01'.nƿ;ĩ8&%Bp?^wQZ1*-1.$3eǣ:#*"nE^z*Ƹ(tI0(+.,"(Kqr,$, vj"O^|߰QŠiL7+(+,$*+.,+ &+ Vc#O`~3118A6.)'&%*' ZɥmZC<+,-%$%$#*)(&1 :'Pc 432a`[]__``abcbr&^ʦ~th[TM:;:9:6%()H-G&%2*1Sgc5=;`@XTRPNMKIHFDB@>>2a-aɧ|smjea__[/$')]'&=Uk;5>>ZWyrkd^VS9_,]ʧ~zxvzb$&%'v&&"!.lAXp95>=ZVzsle^VS:`*Y˧Q&%$!K#wz!EX LZu85>=[Tzsle^WS:`)V̧J&%"*g` !T.-N_{5>=[Ryrle^WS:`)U̦ 2%$)&_,- W~8Re5><[Pysle^VS9`)U̦~*!$$)$EX(XY CTk5><\Nzsle^VS9`)U̦w !#$%/!a +!KXs 5><\Lzsle^WS9`)U̦j "#$y&9esr3O_{5><]Jzsle^WS9`)U̦j !!f!W,;>Rg5>;]H|yzyzzysle^VS:`)U̦:e! JPas%KUp5>;]Fvrsrs rle^WS9`)U̦4i&! 4m.SdfbZN1:N^z5>;^Dnklje^WS9`)U̦o)  h%{)   jh "ISfȀȂؠ5>;^Bgddedded^VS:`)U̦7 =^- =!7M[pd5>:^@_]^^]^^]VS:`)U̦9 JsiM(*),SgB %GQg{ y{|{b 5>:_>XVVWVWVWV S:`)U̦1?'Z BM[uՄւ5>:_=RQT;`)U̦ /2'q1KShͷ͢5>:_4??>??>? >?>A1^)Uˢ@zd}'IN`xϼ¿ϡ5;7gPOPJp(VԺ@)0& CKYpϼО520PYVUTSXMǸB;' @JSh™ϻН.O*TQNKIHJ9k-u" 4HPcz™ϻ¾Н YMGh_e 4JN_v™ϻН!gGCkEI 3HM]r™ϻНN{ýF;3 6JM\p™Ϻȃ НPAC*.x! 4JM]p™Ϻȁ Н&gſAP (!e6JN]r™кÅ Н(b@~uMBKO_r™кНbۀ@5_%8(EJRat™й Нbـ@@% 4JKUex™йНbւ@?"  8KLZj| ™й Нbӂ@X% FJO^p™йН#b@n - 0GJSbu™иНbτ@J=E>JLWev϶Ϝb̄@.Sq;JMaĀƇ؜΋bς@1RJ 3JN]zhw bɀ@.O5 >OZp>L\[]JbɀƄ%@7 => Jn|Jbň—@e $'[ JHb@| p#<  OGÿcA* T#Q iB¿a ;2 %!~v8-;Q3r  c!~|> s6$  +~}{}y W2|8RX~~~~}}||{y~$ Q,u |~~}}|{x}k N*r )Y5|}|{!zzxx7 ]&q8$% Ly|{{zxw|~@ )`&sv  \x!|j- Ca)v8T ]~|e4  "Pf-}Ŀ8? 6S@  CRs3¼.=   EG\:/D   -EIQnA b#   %=JLVdE,wU7'&%(4BLMR]lzH~~pc\WUVUX`jwJ~umhfehnuGq~}|aƷ9 4> |X  Avħ /ǣ|sbӸքׅƕƄŀÀƂŅ ĺTsF }„Ä&z΁νCl¿07e˰ˀ̂URS^ɀʃ;f$׼X>=AABFIHGFGHGFFD=><;873J[WkЀ˼;f$+ןV>GIIHHIGGHFBAB?>?@?@DED+C=88744E_gʼ;f$,c>DJGGHIF><<7;MOOTWSKMK;457=ABA%?:552=Rz͹:f$5ф@BJHGIG=:Bd~~r`E83559?">=:408O;e$:\9JIGIG;Bhźm`J/258>=:3/6Z4d$[HCKFFI@>tɬSI-147<<;806#a$>GIFGI9\8ȟP?*04:;87=Sƽ$[HHFGF><ɞ_/187/7}$[NEHGFG;ՠI)763-t$o=IGFH:=e,453/o$ߨ>HFFHn$ .5yˍ@GEECM/f$31,Ny$]Yt:GEH7+L+10, R*d=$9GD?9ͷ2.01( ).00112&2ƌƴ/@ECE>^ڀ؀"Љ%1.0*(03556<47ÃĂֹŀ϶DF4XY&0-+AQVUSF515ҿ˯~;ECE8 F̬-,-+6PY[ZM712ϨՀt8EC@Hˀ'u#/,+>NTVK610Фn:DC>MLƽ8)-*0ENTJ610УҀ k:DC=Y׀7~ -+*8FOI610Уj9DD4NŽ=&+)->IE600ѣҀ j9CD1 ݀؀Հ̀)y-*(3BB50/ѣj9BB3π-Ų0(*(+;<300ϾѣҀ j8BB4G¿l,)(370//ͽѣҀ i7AA5ڀր7¿ǟ&()',2--/˻ѣр h7A@6OG!)'(,*+/ɺѣҀ k6@@3р Ā"*&'('(-Ǹѣl3AA1ڀր:è*%'&$#&,ķңԑ8?A. ׀Ԁ8I '&" #+õңҳ==@0 ׀Ѐ̀/y(%#)ɿңЀ ҳ9=>8R ݀ۀ р ǀ ŝ% &úТт^6>9Cހ׀Ѐ"5%$#$ſݤ̀ q0><6݀ۀ΀ Y%##!Ɖ̀̕ ҏ5<>, ݁܀Ԁ̀̀|%#! ̀ μ=:<3_߀܂׀р ǀ ď%$Nx΀ c2<:4߀݁ۀڀ рˀ́5$Byˁ ݳ΁Ӆ1;;-{݂܀ہׁЀы9#4iήЂ ͵>795D܁݀ڂـՕЇ$A#-i ҫЁ u/:;+ڄۀڂ׀7ڱ}ͧ(&Ͽo#+f~ҩ̂ ̮98868܁ۀڂ؀׀ ìˀ!З)&%ǿ#"V{ҩπi-98-kۂـׁ ׿9΀ˀ˪'%(($#ž !Nxҩ ́ ʩ?478*ڂـ؀Ԁ l:̀zYľ "Ntҩ̓ ˀ,9538فׂԂ־"kƓHG!Krҩ΀̀ ſ^+7609؀ׂՀԀ jˀ&Ipҩρţ:156,I׀ Ӏ٢!9Ѐʀ&¿!Gnҩ΄3345+MҁՀԀӀ=Ai#Fmҩ΂́»-134*=ҀԀҀрy 'ǀ#&Ej ҩ ̄x6.44+3Ҁ ۛ%$JˀȀ Hiҩ ́ƽ5*22/"^Ѐс ֶ0) ɀǀĀ HjҩῤƼM*/23&0x΀ ׺<&$GˁǀÀHlҩʻd3*.3.#6n۳>#+"ǀƀ Omҩ+ɀ͈"ɺO1(,/,#)O|ź~.#,ǀ)%[lҩ!ӴuT:,(+,$+-0/, ',]ǀt&\oҩ4229C91,)() eٹ¸{eIA,-.%$$#$**(&4ǀ¶A+]sҩ543ca]_`abcd eecs%hٻývf_W?A?>@:$))NǁĀĭO)(8/7`vҩ76>\Y{tnf_XU;a+hٻ¾n$'&(Ā$(#!1Jeҩ6?>\W{ung`YU]U{ung`YU;c)_ۻɃP'&",â g`#a€22[mҩ6?>]S{ung`YV U|W-/.1a}M )S^x¢:CDDCB+6?;a@ZYXYXY WV}$ ;T]sҩkztoid_ZN^ ;8556789::ͻÀumy=;:85:̻½z  PW :TYlҩjytoid_YN^).1Xztmf_YQ6:ͻʙC: >WYkҩi ztoid_ZN^PS11W}woha[S6:ͻ-3&;VYlҩhy~} ztoid_YN^'$3;11U|vohaZR6:ͻZ *y =VZlҩhtyx ytoid_ZN^D"3612S}vohaZR6:κ¿ɐ[ MX\n ҩgnssrrs roid_ZN^'"3612P}vohaZR6:κ:oA-PU^qҩginmnmnmjd_ZN^'"3613O}voha[R6:κʑJ(;VVbu ҩfdihd_ZN^"3613M|vohaZR6:κF% @WXh{ҩf^cbbcbccbbcbb_ZN^"3614K3}vohb[R6:θʛ g(  "QV\mҩeX^^]^^]^]]^]^]YN^"3604H}~~}vohaZR6:η|  66SW`s ҩeSXN^'"3604F}vxxwwxwxvoha[S6:θSFRGVWdtШaJONOONNO NONOOJ] "3605DupqpqqpqohaZR6:θ2bDVYlՊ^"3605Bnhijijha[R6:η6 cX :V[myTb_]\[]:"36/6@gbcbca[S6:η2^< G[hDK]\[^J "36/6=_[\[\\[[\&ZR6:η< GG VP"36/7ɸ-N    5PV^{Fʸ-q(*HVYeuKʸ+b?-,*- t8mk@6L Dd^```````````````bUSbD j& V8{LČU!ȐW"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ȐX"ƏV!T$ &P~,-gT,t>FHHHHHHHHHHHHHHﮅHζÿEsCqK" b3zCKLMMMMMMMMMMMMM-M]M[̽M]M]M]M]M]M]M]M]M]M]M]L]ఇJ]ڡ{D]j9]b2]j5]t:Xy< %Nz=2[wyz= 2@FHHHHHHHHHHHHHJ;z=  z=~z=|z={z={z={z={z={z={z={z={z<{w;{ڦh3{kisyzzzzzzzzzzzzzzvhJ% {qP>;===============;4%{wG$ |ItK ,[K=e{K#7DHIIIIIIIIIIIIIIDK KKKKKKKKKKK讅IТu@ʜpsy{{{{{{{{{{{{{{ynS.&^cF==??????????????<7* #Jm{dB$ ':DGHHHHHHHHHHHHHHHHHHHHHHHHGB4 ic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP ߂H1& TоLo>0_߂8f"@ E2!s&j@,DJaga~U@_lObsm߂8nޟU" rJ^Yr~')ȓ1?S ԧNsa9HLJ+l߂8lCU%Ϗ}80']Q5UodH+&`%Xwү >l3rXØtw:ڏ!o-)ꕙh#.S7MEX[}ZT$bg .ffUkK\%פ(ٲo#}>$:G?%Na$q(2Q$ KsN(CΚ9#bޞuNe% $䳝#ϵOߍψi\ZX7X6|P|g9<=ay'lrWG9dWJ3Y)>u#8 _qҒɴxhI-YQi7ݟ?;Tß'<"K-N!hyC2@5CHt:jXt7fGזe[$)&qBW(k=L Bre~FZ46G8YސUND$ eHtzOFZ ;|Y  ^ %K$lWXҜhA!9x-FdXo%nփ탷GO>%or@l=8u^3h#Ηp؛< $P>B~U`a[bF~aδ3H<#A){;?[< e 1f.z %54q;|VI=XVM.=xkNfXyϋMEEpZjcoՊWz ґ zwzw&GU-ͿE񓰨Ť)Rܓ^}+D╼@i*Q;^|CI8#+x^uAfߢ ?:쉑mY0/z{1GS8q-c})?axc, -;+i7eQ"˪?YeIg>#5**j>=zbQd=Z$nݟ?;h&fEC(S>"IA0U/۳cJ*^B|Rx]z?&5P(8,}J|e\$X;1a~ѹ٭W BX?Uɋ|k. KHHv}1eys` "~ppw иmW NϟB^owLbDǾa3)~}m L&GAU rW ,AW 8P7vY-cbVDEsOH~LW{Cs)ܟToMl-ƌmۃ L޻z$g #aeNw͋ưMplnI&_8 w^(Vss_'̻V8$Fb-D;-y'^FRw oXic j "D"E?w nWq$:]Ed(gj=[ "/_bS6wvduԴDy> {g˔úl.5]7m o5P#P`>!0'垖,&^K(̂uځ:*8z]^^`_ftɅWz>fuqo‡dxs{(nhc.XѧPy8C 0v%Ws=V7x'_G5I f yQ93{nkauQ])\@[=?&k}CI٬z,, D[]Qs1_WM6{\wQPi`a&p$m}n]gǐ6wqDFA;E?eq r78- Hg|d} r ;RL'=dCK+W>a%f&DNqnEl^#ѓ07ӊšV]'讘/s {lU`s j:NOw`pĠmru{,t2v?޵Ʀ-hm2I/TRu&t-UCvI/AzN6Eb*2Lo[xSgʗopƙABtYy wOVʽ/4&;-I1֣ ]Np0ďʤ숆%;@n3˾ -ZEOz 9!KejbD0.k ^6ol- QT)bW|Z@󽜌M7Q0h0퓲%4uMB R4 .Hh^hpoV;@FD$:o)@BxbKF.eRX4 s!KkT\->Ԉ!t 58XS`eQ^W^|B[uq_g ?1_vxoT@# J*OAYapȁas31NI)3 O1|nLMk Y*H &Gqe7XMlm4dOD9hx/u&=;xfOs臮ŴB9/R}GXqx^%G*GgЙ}!vZM$Buk:8h3 MW-֨IkSu#n;Ҁi&=%l nw>T j+T1%DHR<~ L5I[3bTEW:vo kPM]V UC,J&nIne!weQ2t[Hc\C,Ǜ@a;-M6 공EBO  j`U<(=3۹uqXձQH=zx Q{YV[#أ;hu&L䜈܃F_;mڸF^XO!w'9b\GO{d(3ȿG19\BLG^Q&wqᯱj;E?ʸ_roGd|Qͤ: {;n0`0Y/h !pz+8~PE? ~]I%&_Ӯ tR9Ɍ-ޝă\Ŋ'H<P氄5@W##}m$5Z/Aܟ !pA,^ec0x p!9=_fGB`dlG*!qm|5^ G$Ďĉe$iǕxwRL gMSTJ˭%RԚ5 c DѯpݿV섫4cGG$`o 65}g쇥fYQb>z17p׬|ufS^~[9omk4j 'w͛Xrc81 _9Odz |vw εUfZj]/,@OŽN?vgz&uا6Q9b'UZOSF|ȸ8݂MnvVL0:Ѿ6ѕ[z2~_Ԝ&J9L#@ngW ֿ*p@VZ4ύLegcʜ͘`)U"\VH8SݳBp<~3_ wywnfhS 9W${J[U)]x:RҚ "Z0ƹ Osd̈́7 wۢe1i FLd'v s#k@JK5 [BI UŰNBW9=(}5^gnf+7\din/CS8 9I~]Qpo]4{Iorݥs\TxSol1@w%^֞e<-W& c*m6H=!ϒaoT!چ2r0PuE)h<;v| %pF9)XݲIv= 0xѹIg3 V35Sz[5r}_Mt+|%$n7YsT\Z=r2Pd}␊- ?LKP*r-A~H Jך˄䍡P|X6zY1Q[⃌4,@B,Ipx{U@O?:=hDA37L: r j /V3CJDu#+zgQ4]IBJhzdB/gLd5[qL*V6uPlj 0ecwP֎\6.MW&..DK//,P ?TJ +tVo38NX똖`4-#3Y۶a+,.nܼ? O{:vB_AC !z]=' lmOUKMsNV6?̏5s=,'HF>?i)\=O؟X> ?Q(gtZ{=pp:,m'fnBxS2z ä1v $G(d0d2(쇒iHU(xJ$ MišB1bI\=1Yf(/Lb`!A"*[ nffm|`֋pUdŇ%:lMm5Úgӈב Ȅ 2-4P&`jb @lo]Lp+a5dģ['JwsQ4m^g5 +Vhz'#@F+)sj~6@U9ψ(ZSmMc~l3)))ݍ@\CÇw6WԨRXvl&3jᭁ"l#RQN( UgTƍJovۡnY%7xZva̿f:vP_Q!yt 8\ +97_D$ݸѤ`|訜|@'v'[m0 u mu;//Hs7ί~0޽ˍ0T}bWutpN5y6poh{ڞkU c.wTe Fmm SqÌk=}"d|gw@,ik Ӽe cK[K VpD }$;̊Ƴ{pd@mn̶>A1YqA90Ǩj`2$4S%6O̠\&)ŭ8yב%JnV^Ci43ry)4=5j=WGNy~O 2P1N)V'4RV?X̧ὃ>=E'Zx'VȀL{=[8a5q(1vQo^Rߎ 8P&NTF`\ ߘDh+J^G{񝦂Z^Ce 2Dʮ,)yt??<n LPfaκՍop:x,#ZMjQr*]{CEcT*AG羁Q[$itH H>O<' GԷJ.O>y-^a$F$2Є PޣKB,y;3j~1z.‡9ɴvw"yꄎS(@seelS؅w(@RuiIyʄ_R=omYLet<:c U|oJY ؓSAf4Y-G aT'bHԑ(s' LUJIiLmG;/mm4bF׆9՞uW+%]qS0 KxcvE/|uAtFGg q-M|YN;ݢ蓌Awj9Gy, F2GdUE=YvS,Vv)BKW8qnM F!I{&jZ g_#Ŝ{4OGh5QZD{jSPT[xw@KS=Jbi孳G 6MLA@̷FR!lP#K 7F3} ?JL,DߤCE@ l0DA.AevOJa"XypVrWH}@wU OzxxMth,U<bè$C]bHpd{@klʯ$[6ʊNs˱gg״31 UZ#?cWup;X06d- Fc7/UeI`(szWC@G%MV*f%{߫_A!яw,6[ׂ<퐇I?Z#MH%S?,\PDGE*|MpoXG|eZRlTQRl͌ "q۟u)hւkR֥$PA9xY݇߼R!["6߱w( wAҞ`i[<Gqo;ux;^UexYͶh<ɯQ]ۆQV]1}B3:JӒ MVx̔31;B,&=|vɽ| >UP&sЄ_N"b) }VBM;G< RF4oET.rEM9y,bL\`)B}ia=Im;)’bq4^:A|0R0}P IOl2w 8(Mm8pd~ E= 32O 0i!Ùj)n:?G[ńCW]$p?(} C R,jN1Nvș!KQrLH<"قKn$d'^9UK, ?(0"kI*G\xARZ!zhG,w#*` 1`[$ Vq2-).+nGݳ?K##{+"`..C5?WQD&_,R< `ւŪb]A JLCLܓhfX͸XFoWAdȃG|A \bP@ Tkbx&hc1P>p:iz uD.{7D>?Gw'?AW;B4 WkTjsp5R -yRD$ؾq6.ڬDz G4"GZjBe{UΛ I3U㊥fN(LJ8|٩Zq_4N ٰ+fɠS $pdmjO/gN`!`lЀ1*Q$[Fl::!Z+ Hct? - {j.v&j+}A5#Խ?:ʀGc*lLZekta)|oDBv8x/DR?/,}Lj}_T/99Uܧ#g8{Sʧ缮Z!-=e(Z]Tҕ? K0`M'3Dz8K_x$2@y'8n[)cfZE6o0J̸e! o4F\Ze)G4 P[~Ѷ^*/J{w_!@cPG..B~vd׳>9+h1VB (RBvNOy՚Қ!?&-"Z)>Dʭ&A j#<G^ZÉ:2K3IeąqSWJ' 7,4<ؐ3g҆*ctyVK$NP]>cw2>k/8`7Qx;9 UZT}*үkɼ鬜22yiqx Q /2'hBnͪ_?N3-N gl#l"`B {4%"!_.f{F?Bn)<8HᥕH@E<hG5xs7,!{(A^wt"?\st4-i,٩ 7u9@EaODT@,d;BRzJqp}Ώb̉](ɮ 9KsBLg!iŝ{rkGD6He\{:fۑU\e'5 9 4THluSʾn@I b\p%CߑR] ]g0yo| @qi*_ɡs4p!ERᶹ}Pw 56{ S[oV D-5j{HtAϿ3FUpnMs42 n7휔~дx6S5T,`צ6̮/_> Pý  ֭wE uQ! }Y`rS&c2MfW)#% rZvGH99U(2x,VjtC4.H ?}EN!R~2A J&џ@ix/lN/d/* M/yNڕd)@Ǐƅ;8֪a:M;_kI 7<۔X~b](FyEI~7,)I0.*+%&VOEmu/-ܓQ_V:'M[vx9h,!/Wo3Ǘ"3w3n[|dUifjW:9e ŴD;rvM 6W7.M2.0Mfkkj>?ө`UɁr,[~꽢>52_Y /C˔/JpM^);8"H,/{@"1#ځq)|#h2slKUZ9)%2?]AGJo+KCL|B7GS ! Θ;/:4@N&iB80M&{m`DOU-PA''Swua$X(@(rs+5ژfMb!ڂ~1z G@TGq=ݝlV7Km 9q]Q= D/)f;^,`73l);j1A`Yx.DixFty D+mY!rJNmGگ}^JbɀgߋYIφ7 ZX)yN_FY'һ)jv j`Hܬ0~&oEqU>D$* mVz{='냘iQ9|I  {'TDf\e2SLʵ 35?Ka KЈLfq9m9ehV7=uqPF. t H,#H#5՛f$"dP Vm;.o%ŭ9ju!4祫u١Zo v<| Цt#D؋-;&2Rx*F<RlRDr:hM~. ӍGR\11q~oMQ[* _ sTI 5GUc +vbY@h+"8h:m¨[uяJh"/V&Ya|b$]v>Pqiw ݱBYDU^ez:Esa3_*ujZy/xfK Z7e{ p"B6Fy{O6 *+S`:7$?Ӈ| J]Y[Ͼޞb(~|!j2Njp[}< 94Z )?H*4tJ{E{!w(R2NTj@ѳ%DsQ((g'u+"}h/}h(ݣْO+4]`im;R(2<=Ȩ3?gjtNoAiF^eY%&ѿ$ #bǔ]ONq!B2;ZL?3r4?.&# 'Wxb! }qu]ir YrjTR**ڀ;z`!T*evֈJ8nI_ظe9 %V_GIr<#+^I*}Gc U} TP(Ӗ_Y6jEdyW_Y hi?8eg0KO{2Rڇ^1_O&Yꆥܞ1IQhnt!,;1%$&:MeIbUͬ+_?N{=9D|" %&"Y&264K,MK~ySNtcU 1LT q?] 8L.gSg(5,QY7*z=w{x6'zkZ9CGMH~b.hhJ4 E$=icTgAV|Ura4e4'Y!B8Җ(thcqҧ[wjc֡cU܇e2g^|q/ԻuY+6sc3 CwXXEKyB| 3n `x;'lXeC\TgOg) .UE羨Dқ`rTuTMv@i5O (@D<`n0v ks6T1Vb> ˃`Z?ΠL,ޓZh#m5BY &s;Hڜ N> nK[h@(2g8 UU[h4tRW#~CxG8wt:m.y% eA֨FfmqitP{_ 4 Wѩjٌmj}ey 9~_ ̷6+ K֡kR1rOP>:4YTNbP6%u `ATlcӖJеfjeZ 0Uw|!ݾSÚ;Q6#ԩ\IAm hPd̥2 W?ou) jl2&h\&%#Vo~=oY(|At7ļhJ]Ts'7Fу9N~Dޘj< 9]OPp1#u&ɧR .lcRk ,ԠwBOr#IaskRMpzi+{ žG[K'eёH"򡔦u< *\q;˜Z%Y  4:mTZ^CL#c^q )5~)qߞWvLg]8@[. oG\3gr: 3(pj_5 `<g?2olۭ5{5WŎGq(N=?u7Bgr\;%-{O?2^eZ?*_hj< s;7+CUJpjnшVC1&<}5oPGqoqof)66-Vxo m=F[gl>oZJrB Y ]oyc01Ҵ򃶋> @OÚuMt*ˬI/(/xI,NzEyOŮ9@Hs2lbGvߣr#7uz0E,gr6ߪm TEsSUO"qRs&ܰISa.$B{ݭZeSnj2X-=S6mj/!Eˋu'\8?xѭt,e"{Ohׇ^ݐxw`~trdz^.x}A&Y1˟?.4LFd0JQnW.?⹛51's+=vDDLf;tI xHя.P3ZL/8g m#4!,FhJ.4S͜&&d'1܏l(>tÁg1BuZ{=M Z䪚Gͥt'4uHH$C%ݳfzi!zNb;reG[>t3ȺC!%Lw3i~'u^+v @4`gїh0Vw/ߕ͓Wmb8nvdPJ N$V=oYKsNJܧ $^C@8o5_9%'j*x)Vd>* .Ja=k~TWz`@ #zÿ lϓ9" qP;N ,N8; f}d-YnwaBG$EIfFÇ>h+]" •Jj%்Wͤ^ýި\2gBg: 4&< :j9TP[̖LK9EbҚ j '(bVhxk: r=^8LPgf,_*};6˽_CEji>ݿmK}+z6«e[2Lϐ@B o խ9D,wyzؽX[#S6)o,) جS?o\e!;XS62〗=עy5qjJlw?2Ԏ[:2lf_3'p)qؐC50b`C6[iEǨ&)v&l5. s?-.32^KM.>} ]Gb Lƫ֚\`ۊ;>$5$yi` 8~d"n5I ɜ,x1vVgxf&ՒW\Tuȧ!4&torZ? ~y@Y׏-.T*>RӆFk>`Xi10Ff 9q'fˆXfOt$!?x# `Ջmr ;iK_HYK?M]~H9`X.Tk ܂eG֥u3.|)//|Kpޯsmʆ*`8h5raCMEƧds2cY@K:k 0&\=:B2Ѡ `M2{ׂ;a[b'5KDX6}œMĞ qq \ 3Q%[|z|N <:6FC{[Qx3t1/—A"b e3KYq\Y䎳 Xۜ׀ff;KeCp!N a+BN*gN*"]D|r:4{zhL֏q8ڢx#=/wؒnrsmM,`ي(.EB@tPB ˑNs-y܎bRN='kV&@ء|kvP8j( 霛GQ"0()3AFI1\ M)d :#I/f[.;—^\(2!$:p<gξꯓ Z,o@XŁԒl'>lm2iK KD0MY!VL#]sD(]*ڗԢ|wN`x?.bVQzjc:q3cOgBPB,ّ4wޢX]54'v+e߄v8n5W]kjBA?Iz)>?X@>~4ÙG3e\.,ˍ@˿T3Hc~07FpeIW3xDQH[m4ZO.ؾg +F3jmo DèT_ӣx"X É 'xW_srzI" & F$tKG՞bW*R)[xe`dž7%K S8@~5ֶBkqn^˞I#'`#kkv_')|Y.v_ɬog\MfUoR?vAU '.WTЁ~zlRK'Asp\[c38|X @l`^5Pdս,T#P*txWe1fL+ b/L4l24GYxa4#{ ) d O7[E0AC|b}na$.`=+4⌰K<6l۸[)Dpæ/+ɐ,S A/15eL_qwDB|s̳6NײO~Ld bKDdB6 *{Zmჿ =\Ig {j7< .v#S]{u89 94qWm?c Z% 1Fe\bp3cW1.HM/)#N+H~,4uPr'2 yֈ{&(4dt@5 XWk;оYm~)ۿ<o"+`teAKgOa4ZQYf8QSYpo2p53D dw/FYɁX(a%}- `JBy@oU%B'i\8SMؽ^ kl>ý>^MUowr.sQEܝۣOԳJ9wUt: JyI+Kn4&f=- qYߠˑϧQ ?bW]&r0'ݛ(Z`t`uQLQf8tXvnx,x"?=Z[-+Ѻ:0xDa3$U؞8C}\Mh2Rg6M}lWZG< p;! ýdZ kS /,o/BT[hIi "'bE0b1DG\/XG闫o?=i)0vD3xT{iulՈ\?uʺѹzJBeX=<>3 7ӡm |8\K;/ubo[*[| K+1`_U+#G % D@@h9|c7 =O2R^}l3b]/Cl64]REqo) d?-Å}D0HC7a<>0 wI cr̘GJX_8QtHkH3A]WDJļ~RDETxb*D6]qfo&&]B|'}c\K,[gޒ"vT⫃5Z!t rg&Ϛ E،)&Y5zÛ:x"&|J8 , / {`GxLY~E"S:B&ܑ:wͿ_aO'%R8k@ɺŗ VՃ6B;nF aڼ}f^g\;j+`5 sO mK/7rذMlF zEQȓ/ Znqw<Ffm_^ڜNB4Fta7TRD1BC$$ELkߡW&*Lr +>()5Wu4ffv/LS .8H!H*4aRsm!=siΗvSdWt2>+H#:љeʁ@DThte7",@%xL(G/~/o:kt[-@Fqqid'0#k)6m˩Bܨ9cfd *|>p\ (,z(XqP1N\3]oVԢ[SJ,cYwb+iv9\aj)O<4cL~u+{)-^moPx ͧUQ߹Jd/Q 'Oyu?ED^|2|Syql`rj qRIL;q}tDM4!,vTd<| Fq P_cS@j{\ qv|-a~#쉣W1 FYTz v--2kl-nJ(8EIn+*0E{/l]{x SNZ<Բ#R<[I#^'"HN*MNfTGiC[څ7(.l.h (=nyXI~ Z.TɫBѼIT}8|P2s+cHx 3BF9w;F'7+wiIsk;8[Ɠ1"V NOfz"D䙯<\Nm6žZ͆Pwӟ3Wa}sʔhGN?kCoaF WR:MI ML#yy0`U:*4*9$I%4¹Mp1p-y \TЁ[K&IOo/WkR0 eyђ.ĊC<61Er~Vi/kt }lțM7x2*Y|%=%X;}udBB&"HRvkI.I7>HrK.;g}'$4u3 /iK&`YE|۞pFp HV:nr)ݬXNR꽬S8:0t#\w}aCnr)r7,ا8^\a 7,;VaoE4 Zc|0/}I\lS9:Ny Gɛ`oЮ;dӵxO yN<)^d%F k% +mGSΖ*v'oKĬ wz)Bd> hLDMBG^5XOR_}1niY;%-w8o&gg܏EEil0%l2l t #IOzљ$rc>7;UHsNvP&I 3i"m1&nRm-r*v. HqN>4UGWJ;jbďǵ0Cޓ*g 1±]\ *ݸ ojɃ-GDd(70T">WËhtV2}y{;C;>k,Zt6,pUjgC:upؚшNrܠib6BN*!]4cDix 뵔AJ2\{D,ޖ gn]Y\Y$WeFCEItSȦΫ\]>;Z-Oa ۛ)VǤKsmsjiww]fM.2"LzkD~,4kR>}FKm!%*C$?0;g 7CɘfdJb ;?xO˒5U{r:6r`7 ZYOdg\] 汐cȺ\qϢb''\ިե"ϙ=} )n{꟔ U3'`grVSGzZU>Nfdn0|6ЀRbдj[MRGd_%l^m 5R#I=?xEL4ų s= Dׄ=\Gٍ"0~凛>3hRĻ BRXfL aأp?c%`C$6Վ_~R?us]ЏUҋ[Kw <+`+@BދUݰ? )oA !b O\,rܩ5;N=BŁЙ=V".򵁞"yܶ8".ou<^?Գ*>OoF,b¡4KPh'LAg)yaH,>ݥR[>@xcUEKɺrn J[ 4T++ 7c_=c)*265I,9}~-<껉 /6݃7& _R BOƃƓ#X"\PeOհ~%D#z<_9{]9]wLJ~fa= xݫW*/Ŷm,9 YzfʪDTGO)i&Yb܀WsNt@TM<(ԸoieD]`pFkL,|.}ǾF^ݏRVw"jvd摕 %oZtNZ ]]l׆Z{ ̺ y0u%ٸu#޻#W1ȉwŭimZP)ɮf@t mOe_2p51B]~ ͍eIW?D * S. 7ɽn9$:;퍶#4 wI@Qb Tmc@zPVy%3`_!aXpSH]%#Qe>feӨPf'3J#aC [3 A׿i;0(L&I GHC\\G+,;z&I;qpa3)Jg   l-mΥkUф s[p*S"7!Qv6![TT/H~"LG;"Y=q޾wB "ȏk2DmZlT-h@NaV̕(h a,~'2|"^_\XB'c<(w +*QF 'wRevboԯ9F˃7鶼d&ҟ1X"P]Ԓ̧}/5<0MOgTKV^iCc\b׃V@N};>O|yĹq$]H~5||R*'a_ؾ#sblb32T/X!/+.9>SzWps$q|+t5Ih. m*=$.:Xt=v W4d劵V{J֋DGFzؽMtyϭGD[te6A?xIG`#=Ѐp0w0c5V&dk!v(ڡa%?#K{?k s;]$FJ"/t0+F姵{-Y PC9ԽgG3gVDR{GTuj M@yC=+%ؓZŘٿ~|#u4Cs )[s(я0cC $7I$_']f-G*L~$νOduX[$VkW"I-WV#ҫ|bu0}C(Zxf1^Ö;Lk0JMN;nuˍ6-܉1hj8zL>G"CΰO[5Wb}r_ۄ:1G,^('WX)w:`H7'<}je3֟m}gڄ:'uZvlhu -rx(E4tBGXV_o Tk T[aA.Y;r>ڊas[ѥr*ELa4 C!K.!Fe!Ch0$7$gBBBO+,{ÆƑ;y"FCe}]hg4,mOZwK#i1qM.LܲҺK#'@Z2WIޟA%OfM$.~  )M6 F=%OmȐu)o^|W͎_d%eC~ˀ8qB}xY)Hl-7"͖ĪvE/UsH];*œmkփԠL6hQ_uxA 'ҳ:?,5|tVɧ>e >/pPѼjoC6X3́w{4-Ԙú)3:Wn&mthL;~va*b\;!*llo˭@*nVǾ 8CyLbћ z  $#QL/~7H?ns/} J@@G2- {LH(1E{7ժDfA|M *˽mrT}e["ٙtK#~PrW o )^ `[{PN Ud ƮXʼl\p"6$FԖSK^Y(psH4)Ƙ YͦNu J6a;j&~_EU t UAzSI›ycW|.bmo6[czwF7VP451Vj̼>R7|O"MWV"@)f|XFgWx+y}wA' r攲n`l ܿ IW,*hܖ^z!JUm_'n.Ԑ9`!o&(8D11"e8,R[zjЫnx;ɘʽ_m/hl$0:h sh`ץ͢4󇀥#mK@Lq>w:h&A)5{ dS\UN`c$9PŨ6{hl!)Trʿs t;OnpT cD% ~EsxF^.y^t_Ŵnn#|1*IQN0y'ג ;a@u@էc A8Jp ξ !6sYd5+04k֯6䥔/;J)4ozo1Hq+gpp 6𹎏- NGIB>5=MK#R0@`hN0~$K%Ljǥ B,[DS"iuCƨ0pSX1'Ϲ{d<~jik5u;;-orI0xڟߋ͌Oz.x i8t"/E(C1:2LH %O4]?`Iv$0s"0VD+Ac{jp藥ym=~Ƨu7EI;`2BdZɯMD}: wDRKa;#rx;1)?fm3jvt)W)2Dbmat}&:'G#\X`dъ?pщ @MQ#ǎqxI xJ}S=od&mdQS^.4/k3GR`.z뮊%a^kLwOn3DAuBj *e}_kEqQ+ o=YslKW~y};X>qwPbD';勯p8sek7!25zfȢ&|()@YA!rłX"~ћ&Wm]%)nT Q/z&1ẢS}&̒$]O ՑZtKhP@vb>f-HUIdnw/V3@UaFP-lA4ZK 45X;߃BPzfLC5L&(ĈQ#yYѴIZ6\Y+RN,/<{H 枅={lq,k d򸬕C0Na@C+Ae%/>@K;ѭD>t4Ӷs  Ck>%UEhMs (.[8Qxu|t>#T8>tz "6;ip|ߟQ͉`-xu3MΡ8~p7XvKE4%^{>‹=@Dg]0+q9oߴ) kN&~ܗqCì6tC -,b|\͈ZkyW!P<)揁 ;a@s!'8SQ d.$Re*nfeA&8/4KVv6vL{?d'$;31ҙѳ7#W=$Ҭ&abI(P:@SqT.^$װfv6/o !7eԘTY ܰ/~6Տ39>:Bz ܺj-2ഊ*xel}*|Q!bM)5\>?MkN ,9mL/+TEWLM _ՒNJRF٥Emnxuތ 1gQ~pJ¶>f/]z8FQ?I@TH5Kti S5 Wc}A P1zZNfvq8t$! DP0*,J8~ z_TU dw* `˰Anr*NT{av]1]f'X.[:-uHѾ  ޒӑETmK+ ՚,wN UON^gdܝp XXb2gg,#Cn2LB54'/9&4 Mx+%<.Һ -Y L8#vpr4ȯ&w(%N,6 L,XxTz^/jE0mMݝC5MG+ mTl[UD)(><[;jh]fan>ɇd}v=YRST>=tM?HxP'llFY Q= +}-B$^]F˽<J9V&ɵoƈ>6B>" Qז oo26ydYՃkdRD[,Q@=S6VLB"6@Mbmf?CBþq÷c%/3A.{g}3NqjgkIvUk],Ӫ ~T +sKxIjfT~Rf ¦dk&Hp5H5SQ$kz^},Fz`7wO^~\XHQٕV sBǒ3X#=ntH0zk XD+129"Ȫ2́ѷv~k8tZ1WhFd3_?;"~:[£[]$sQA(f.v#ѶY+íL;)A6W.l]D \ʒ펪q`:Ɩ^׮BFGd1T9V+T(]t`PTܨ<9>%-I1;UFbnuv܏xݲYj" Ԧ(IF&l?\uo ,g8j #Eܙ<f"p8:#5'lE9INif^mFUyw qϨ{*3h ^^s s H=bZQ%G A{8JR)հ@!j(`q= QJ e?66wGjk- ؚ5/ВVS\Bh/x?Ύ[HU-w/Ǒ8#Ͱ)ʹf0O.S*W$gm:Z983jߣXa`폎fQ$u]pO? _mݷ/Fj}~ .N5;'Κ$c5gRns{zsd5aMne3o 5!7 gL!!OyTzF^V 1 ?N(>1$ݱ~,޴[1 $(MoWV].#܋ɘ\ظS𩗣n|!jIsSZRSzLW#`j砏kfpDɳz +/ʏ~30eWȋ, HIԕ~u?sSfP^3ΉM_Ђ}:3zHn}0} ;=DPr%Z3 ?|0/71 X \4ynET[&I)~òU蔵as{4A:[ }):6[*d_ݔ,P~ϽQ)?'u`!KX i7wcI9Wnx^*58z~ bLW^p}B4 d^Rc3prȧl wrp,gڦpVbP#_w7N(SbfXO9< HN?gS9st7-aUiXV6S{N(|?a:ou#&ywsԅsM:g]Sl]~I4Ӌ 3PH3A'ҫW$_E8^Z|U&pGZR辙O> w: @75:j<1/,!oG"MpgdZ{ t"}&]īGd(!J`-xT|7~k5)Y# Um+(# )qGV&76i\^9A_2=BiD'qB+3]`ZfgnrrǮ^qKܬRChmSX/Zc깿s3H), ZbzX[ҫ,q| ؎<.rD 21E65FDH1ZX<ՅEu9A@1w H_)Tu4':~e#L[4q7SΧ酀Z9DlgӮ@?@7 J-L4aq ')t.l2.N峓]<5,GE$ ^~ej\KIA TjgnJS, B<>$hRT7򟺎/P`<cwѼK۸vw/ѥ#M Fn}»mxcۤmPDBMbd|^-g0XTep ܡCnQ:>Rj?`k{tbAQ<J<[I-+8h–M;vFt-$#4'?Ė^էcggd3m4m"-Ȟ =Jn,q쎉ȵo1%M"|aTr^R [ D;tJR2VE9Pòةnwp'z@.\LCVW$aOM2YE4kGAs9q,h ln!SM1H2#MlZʦC i抦lDH陝"j۝rnIfr0qF:J&KK/#g0Lȱ3m[,H[xmrCJIr7o12#9a-Zn)ګՁ5B~DIjm *%-:j5"4F$[:l/nu{?&ӆt FtN12*㖡6r "+(H 7^_ۻpԢsZ.۲Re.#)鵠wM\ij&z,XߋbX-ۿ8wzROES(˽[n+AR{ffCýݻ`USY,db$^ KH>4̄z>Xs5̧S+pTR{ vk%``  \9!Zf?|5`rK"$q/C0L [ aoǎzW<f>m҈g*ɻ'Б|~͚# "ܖ+i܅vo#+EQZqPOi/j"tb_T:M.t[kv 3wNL}`*XIW]%4#E hXGJVd6Ig4e% [ ,Eܕ@2κĄy=+zR%VM9 b1;}Qx^irؠu ozF԰5g\0QawڕgG/&~K$o;P9a nZ{ lmb-:aXSZJM`sotPk%Pt}irs܍"+:w.g\`(#RJ UU_ ٸPWqIh$CNP3\xv-SGl7pg ܙdrPQdN)N+ 0}9&ĀrBial̜) },a_XxAy"+ []/I87;`j9i|h I:g0r-QtpNmlԭ_08+i##;hG$X_`5tl&I o{nvO9i{m,h JB'ɇ=LNTugp =WHdF.2i5ֹvզ҃ӓ/TaΡ$e?݋挫PSh[7'Rc}3lu.mc,άc1ꡁo-(jESqߴl6"Id^ř ϤJvݭݡ%/8qjH8x@kJb阨 _" f۰DNfyT/y[†xˌjߋl1FBB_;*A 8mSJ٭1D Sb(my4do@s2'B`yצNNsXz;9<+V=qW BtxO`7؜Sf˶GGc ʐUT"Zgw(X `5y.j‘Q xj~b& ;Ğ/^ !1P~yK\)2_paFY\qejICGK$gRX"$9@hȗxVȘu}]vi3f#z631lh/WΠߢC3Y?|6V5 JX\ l^f<#4S֘R1C'{?cɠ/{"vʧ6v}8ZGm׼ (OI $$Cc-߅xLP}/8u(qÖ]oGP@#]xbZ[`RT'ȷ.QkПʙg"EM;FRH2YWrS_~׏zEL@O x>_@JjC(C~ ׸qZ#wbyh 9qRJjJ =' ȯ.57n^dL<+~JgW,G6By)UUUqu \4PF+8IFZWﻎpNoi inRsRȳezh>2KEPϩ.'*м>jqro^T95s ݫ  5V{39o=el9@uxVAU]T/掌jH;Is(8MT3rn~Cv!Tݝ.P|8Gjc+TTL|,LجX_Lrג'|؈.ʆ)n;3A7P+MuP1ސj6mm~eOk,wl@r7fce3!@)&:ٜڎTB!h̡j(R`32yc ['=γ)C ,c8?^5z*}u_ )pg刬/n;5x ݄HUJr 7GJ mgTc#=g=yٵwoR5h^82Z,&rٹ$|ʛte<:Q#mj]wujBʽgor,AF-AŸz/;@Msc'+@l * jQ08##]FEj.nt=r ^U,fUcCg%n~5>IPجeAtxZWDD|v0S 70j y ]WM E3)B{7kz{(C N)m@VK^k7) ^"T,H%)4KoB ,L%ȅ*KGJ`!wz̏[.js{m1$c)%gbX>Wq`OEt3*!qQc(ܠkGPX . ;̑- _ԼOz.&\fvR+]~㲂<]ѨΤY7FXzwUԣqn xSL5/>aH9!yGɓg]y&WO` Q5D2Qw:_=ےȚ٣Xv$&Mipl>tdb  6/wVb@i8ﲪ X6M9}kmaWkxOpaIfMHG_wp5:ms}sCed¯&d3C/ġ2k[AQ_-wI'RCz{:Mm3)/[,C;j]2wMP#d|t 8D:Tʜ=遣)=Qrd`'/PqNԃq65Bm$Q 6lȍ!gC=PEe  b$N"R~[IyIے@΂Oz,} qr?Hk6>vT>N[mc orFpa2TU.5E5F{ őtRC/F3FnT 1yf7x.Z4+: fmڏjK.(u-T{ˁqqq {]X̒?!@/{Ts6+W\l9jgl֟0p[#{rbf$%V}k.+N u758PDdr=2 d!;.!ۦuLϖic_f0Μ.0#J;|t#JWؿ<>$%e}c%G@yCE*}Qօlܜm ;J$G= 3?j~-i:ZTЦ{SSu>R͜}@4͗X@'Q q7-'7v*Fd!)xvc𛸈xP Er?[GT/y{.pSL7&ޑԠec4_ 1jΚjsFUE`tXSV#B2Gc ~WT\}4ā=X0X>l*+M )fS@'o0Xġ Hܟmf ཪiLΛ%.-B1xW߽!jѯ JC{`h-?ɑztެ#E(F8 Q6#T.'Z e MI[>CKvgyy&$\Y3H֣|]);y{pr=h~`{VN$fE X(ພwέ)7.TOQ9AӱjH9A˲RrN5'J%-xncCH@S}ךR{ZbQ!6bGee:2$`[wb?p/C{*Q&Cߣ :}w~mJc9%3pX.@alYڒ Ƀ%p)Pu,-tt]/]>ǂ@.iT2|Boҥ d3[xuW[Px3kðK@MD{:=ށn?_+se-ùE0@cB'ֵflk~6|%x9` ]You؄ r~>@ssCÂՒ_6@eP-m1I2 ш[)AI9R+}UuK )ƻ_j`U9РG=4lIJ3rѕ./5<ɴp-e&{w =8' mh׺|;<ٚ?w#R(Bv߾f^wXPa#SmlL/ a%9Agi{0ek2{vξm ).^~k&D{Rz1GpA"۱f @X BR)I֯u[WcON=ӌB ŝYR}J+? G{~k"!DM(։1/dv,lr*/XA j>=tM 섙QJs{1{K(EȒ]?/A{؜2S E=3׷n jUGYAY m-2tcyR`«e^8o6Q}P+],r͸C5R B:JLGEPjL"@<n}V6A٪)neݵN7 XIJelvo 1K”DSgr[R*8?]*kyzcC!y3(}".Ωz ,W\A}"ƽBkq*ID@&;Z{Zr7S`G9C"Pه%I;Q\f[7j֣{;4=-!V)qۑ)a} qcvyv@BV%`;_lRSSHEε~,D"{'yb3HT~ A/Ș #y偓 )#v/TkʇKgiF2V;| BuLbQWu5ZJI~a\su)_0 9x0 .-ȡKiP'\xdrkwj^B֧vK Њ֋udAX1td2ihtKh$BI-"rNIS_M,QF:0`xpqyDjD v  pcdq]hQ 1#wG&`]/=sZ;;&8=)'t/AT H'Es5a)9ER^g4ɷlZ A9aFGCCl*{nPvhmYG4/8z]!WaB {R y;\<Tj14dn$껷}է&~{%xjGncu0DȻv bJz0h3,c?I~'3FR`(hJ $VuزD&wG_;,#i ?aA~eIp`kW]Y 3b;H+gKB&{3$X#؊ww(ߴS%ӮL,_eʅ~m]GϪk;\(?6NM,PV`I͘Lnznq;ᡍx۬b&xp ֯$ W+O/U9;&$[5. mЌDɷyYG?^8 \*oSՈG'\"pD( >`+M ,0Qo@I0uCqmZn+e:ʺa?x -9a濐:zu{Lһ(XFH΁LCӿDP2՟eq.H碆T[q(/QfvcTn1*6KAHU|Dz<5/u>Ԧ5R{>. 7 Σi=Rxu&vWoXƐ5a"$nGx h|+0s&.m ! x֧lpiHޠ3!Dh8Vr[srh*faQlnU'˼K3c죱ŔnT;-9ŵa brIAY%# pZh o}@$ѰwDoD1z L$kIƻD/eО,b^$Mx+mRDs_~{6[w)R@xIǷ=ޛC@Rh.~o:n!;L" )k&A{Dx8w N4mp4C hjɧ3a4OCx‰C`שRNcy 6I-_?~Gvr}"LŃRպK|oxR' ql\t êy#e~pK{fѡZx~$C]%-5G8?G"{f5Ů5`֍s4$i0bd#!1kU%ЄJY=hD`JY*ς+gyWn"}^=.<+m@LV9.7H-dUbZvTQ,ctHz"!mXf x v㥭x/ dٝ6♓׼ t <۴?ޭ0~ OM{Zm3L޷̸;p>{HVL2K*W1sۤΦOl(4TyZҟ>Fu1A D#P`Uh@ Iڋ#N(M?5hZm6N;B"'먬+=8%_\7ry/77֯A!rig2j&^gc9~ Տ3Lu, _U2"eNz/i&='i)Dj$ |H:wbT* D2t+ qhX=ZPsd1 S P]O0TvՒ̂¿zPs_'l5V)׎ ;MsP ߗ#vEWbX کac.dOL5ɽ-\jB;,'mjDxsʚgR9Z3XEu[nXس-6QGRNF}Mͭ7kŬztZW ̜L_s^Ai yU9n=r9{T7fjX?D )/P`|ELfw}V-gU7xPᇚ*DR&ovխq:L/ϟ$/}A _!٩z|ž㍶$#|,Y갂X7Q3s+0Z&T'`!Vn45+đO3*W}MЗ!A4)xS+W0Jz(gM56asDWTkFꈐfoa0O ͼjc]I=GzκR|jR]ln`o.]_}:&sa!˯=4ECڞv&Zv7FA+ı஢ !VU-Z;GEފR [ʁt>HuW QS%\h)DsnZπr!(@G!X-H}CW&0Fr)ƴ9Drծ'ݚFBn>@XQFٔ81"$#jE`{XD8#2Vq=Y&>3.P ?} U $Y}orh'M9N/sDfB mdlU0g 5DH|z˔OWzCwoe>i;2G'"B_a!&:jy-i ]D)k>A؅Py֌y{@A/p*\{݀xwM?b}C3z-}xQ|;FD@r%OH#,:scK eV@եHó$1 ]Q"uXD.zS}V}K bΖVjnm:&z!m)c(xKN[Cj.p-ߏȊ1ۖ@҉K8X|٪^6HAàɴ`!թ?+z5Qg# O`'&3>IY.Y:ۮ/1`>$(>~_o[c Ef)jf@l:9Ӕ`XIC׃֐Ȟf"gOi6PzH+p`^,4^J(b;`E6M(#1vp$j٩O1iTB1V"t$.칧5RIB鵵RLpu==}LՋwpӼw#ƯdK[DmpPg'g:WPxDWr? rH/tl8õ'=#Iv~[T0W9 ΖNn9AY+\gGI qgOivn@ryxUY-ALuA;/" ժ"75/4Ϳ\ɞc[QU"Z=7|j`]UH% IQ yM_VuAUm*ttTˊNdm6c+ ޼d:(:UXHTz2b4!j?'pJI9>VD.H8 8 [dLPem,7~WTMNuz}b:$\of-_eg @&"Y0%)m+( O*\UYP.a^]wd^zBOk0dԻTy/Fg~i1-!@|̡+eOtC x r̆3 _P6[zᦧڬ/!Sjw[Z 'e6zk԰EU%`PIO6M"ၓݿf@yxJy\Wqiٻl zbD/]AEay[O_g˔\LƢ3$SP4`ed# Y:6P`C7r*%^ EYSkWO`!KF$a~za/9 ?:~e#L J,)z{VL.VwI{f]ˁ&?F|"4BGNmZ<ð3j2h`X_ʃs=XvDE&Sg92n7p +30)"%1gerpl٧Sk5דLͽߌНԉ8*~hl쵄jmEm3o1i>^D,5}&.-Fzf9RVqJk2i4!bhqMWZf͐ahw߻VGŪ .4Қp*O\ /!u(}OmMy@6#\rYpk8'IN^&6 a0,'"fɕp,Tekŧ`BM=91z3$ż*ݹ w| OBJg^R}e{BԬT!aBc `akkc:莦]W+~|AXk4J:;ƿGqeyc|ZWh<< )璦BEao^rCDL}N>2%SLkc-ȰV%gsE nԤ;VO@Dsz( |bCo&8o&8Y. (C d)Jtg[\p %w,{+dxId`&Of }Uә2dg/Z/co[N3ƻiB6AtiWA4DnB\ eTIq*~k+aXHjQۧ?2|(ԕ^VGqyShc> h_#'t*b~#jTR`N>pƁEfS9LԣXRy{q wo*eu6 r8IoȱJJIIȘ4^x!<^h_'P շ ei"9Dx/ҟbŎWp}LpߒBy*#]sgOd\BHQ8!`zt᛽fN!یǸUs=m|kdɳ/JvmPQ=y #cX rx&eX_#Im` =y{}=?>} ͍MGRgqevcrYTai@sQ&CC*Z/f6<1 c_ьNiPʋ%vqCu[r 2Ɣӣ27 хNymNZioKu1 80qV=, e'>'Cw;(sDYe|өMMQo!Z&~8Uvp=2a^-se8y y8bUOaF5;,]pNK"oʉ}S_)ؚ:@ĵI}"^H \akq=ZNf/kyR?}#(k֡"COO+Z_ͣDc.D Vz UՓ{C0p`g;9*=6nr f}6U:4Nd<Srݛ&ZmCT&f0jby3Tz*M cl;:Bl^]L ]n. ]g*x)"U1Ь"\A?kRriIK)r R |;9\'2|/b '֥}aZ }'L6դΫZq\4z5Wt9wClo_Iϴ$N&?Kdz@04<9X75|9Q{v9ɗpcjI 8ѿd[uXC֍kltP# C 8VΉQ/cys)% X Sc|J+C5:Mz=܉^Lezcru`' ֧&ȆvI Ipf7> z>sSDÊ=p㚎l2 чMrQ`jdkZ^$`uDOnm/#F2@UsL8 ɟmt\,J9ǵbb!F57o'mnW:Er"ShgKWzJ.A7kEx87@Szb*hux݆iI-Z<Pv;H_b99c]0>N 2g+U -='jD1 $z(쪭0hY no u_DcFVw?F6 =#W雓',3Z?ym\lSػi)CJW8l*2_y6)<ϧǓZ4G*/؂aUŹ\5߀kX-{Ǟ2vmiȕq{[ l'U.Z`vW<K| d=qR87ge댼G")^[QgAK"" R(bo8BX(?,DRƨ0RˬuT}YCcE+?).z@hd|'ǧ\޻&G?BacJN ݧ$X*6K?~rk'\P̪bZicOYr|6 KX033VCMO-I mn/iK]|ɛ+gjsK*OaM^GgU{Z]wr2Oo7VU5u즕#g`6",-TiOE)&"]8|[ y]1Lxp>Mf^{84Jl5RY-=u;Y(`iVUlu|}x lx LVuee}s7{_R ӹ/\g>$=O ` ([)^)u#Iq_Ҷ_T}WWc] ($IA7Ŀ82Gс&Gv+ TSrjSW~@tsڤuB1Z @몽V߆~YK#z%C qO0ôz #:mYh77S!Ӛ݊s9s9s9h /B57{sP]x %,ނ"<{_SkBQzK="Kg|&dJ@/^9U6K Q.Sm?Rδ>iB?e֚NnMDe'9s9s9sB5B|FRr ѨhӫWRVCpjk`|%:3ˆQZ#ec~C҃7Z䘿`yŪҶ#'7I#lxY]_[joBlfvw{l6ЋoM~gR`UUUUUUUUUUUN߷`zTT&RbUhsLM ek&UY_뮽75=KWC̻zly2[bZQSb3O뷊L !^cbuX[f07 cKōb{](ߨ4IR+{q‹mp@8Kg:F%\qY,؏#Z(|E*Ns6 Gs9t.aШ0_@/\Sʟ $kE߯pGxM0 ! L$Bt= Ry" $'wNQo h#!N)a1;DV@W"Ј@# xZ! f&,c .*s){!pvUU, TKtq2MݣU+*D_h-ޘ-Pvx_bo }eҽDžg8JIq KC&sl!_5Cdd8vC':J.Gfу*~y̤nPB|^nx: OJr[9e)Tt 6zZ) )r`1qP@c@҄^u(4ȹWA |&fW#NȊ4G9ۗXL&f\,㴣钷6 1\g-h έFjV34+/_9q A4tqPrDVj`ɖ"\<%&%vDܒ:VWX#& 1p27A]\uç>N\+v3b֮"Us|J*鷚U$JIyԼ'364C/k\ž0A@S4b4>0sON`F1dn5NB;^ j@il-TS}z_ޑI\´/*r$[3T2ҚMjѼދOR[H /Mqs󄊆K2&W̃Hb/q*yB h•cg2S$}>W3.$`aܒl-4Lbf*zW jrz\g3pܿ?|K}_8DGvwͦSj9XE` 0VҠe+IW-LSAF@',TV7O2W83)TKgۍ>|qoGZ9Yb] 4#^"M.TU jMW4eBR Țq75@É7[a:{ʿ Nk&JYPZO~ǻeqb(&h [Aϋؖy( Q?ϻA7ԆD)r .K$HYE%$ c=f@ҧN^c,&`5ްXXwG>g$L`/釢5hC)!\bz{Sr(PySSBr 6=q,'Ysa`:HUC{q墶wǧg>%("Pj٭PDΫ.*gJ:CZ]P@CءQ,7dpAJ89@eS PޫNAֶcCQNv~zZ7>Vb4P~5DL%NlV ρޝVWCIGɡFY%a9Oʓs8^6ssPo._J,Ց8sh?L>/7NN V! `N aTFej8NLU'u){04oIw&~l:S!=CO){Z;3nRbKSx&yYj.XvI@s=?_>ERaq]*bU:N@ M,u ʷXC  ƌѳ i$oa@;&)w8bNbm`f+*3?QLqNǼ݀R|(EQmxe2] ]ͪq- ҽf 39oe~b耞!QhQ1# އu$[1H;-7Ę>Oies/1xYg>k;|„/~1b CKI`ſ(`S?꧚Đ1T@b/vrVa`7pgB5%ٱVmz :Dax.%< h-!oSI0 !>94LZ[N[XqZ~dC1wɜR* ^` @tIK?FlTt j5/ׁ rrڠ)Bvd*eT+08g {d;|~lyrIAw'fh6C)E-r7ۂ/zXi@l0Y01WX;X2hsڰ1mt %BgJ-zۥP~!^v^kx_u`z^yUG;_(fd\SO1>9\ qMkĘo}w[ QɀJyVz1Auiεc3䨻*oM첩+|>4]L#8k-g@&!$FE:d2i7A_Ol8++'# |jWNUEJVs6uM2ns{9e;TV[F-ɷ" Oև}F L%|KZHז 7 *sGa3_B}ٯ[ބ/E_(d j-|[†@F{t12YrL*q Vmbj=;O *e[tߞG+Js׋/7lx<|˿ dQqRz5XlF?,PÄpL~4*,Q'P &sItsr%9~`x\zk&A8efJgA^q$-1j\UHICS-e4{}X8N25&ǂC9܇"[r]ⱅhK:05z+=3SœEW]ቤ= +-^ao)zgrW2M[X x~5Ҕ QP{D| 0{+gO gG>S2Iҭt Ym_2< \of4ؚDTrvavdn0𕈺K \hq>E5D;nht˴*g JCW!fw^eaEkhT `ֹ&2A9 ʱb&p9{N䜺SIT&Ӕe!ǧ*r Sc ãхk UM(wƅTXdh2!+Q;#p؉|,vJК@MGL.E, AYjWe^xuz^hq, VGc7e̮hV-WTִtO^{_3[vA)ӥrEGgt)@^`K {%RSaxOϕs /[\9q* z+ 0!;8 .X( {8y<ՅtӱrztLЀ xh 2-'5 aɡ+0*qۣyjе佹Uc'|fG\,2HO>?9W?N"!r=MeYGH~o[zpBb1 VRsUzy< XB*'Mc'g.UK@q2x4#{ [hWk` )TeWQ{~-]x`솳k#Iؙ6 d{< 4I<:ru\_G}m5 P2,X#؊wwP~I0hjܻD|OͿ(s[gKC^6v3kc^EL7v}݄(kӚshLz"cڼ N*%{7?C၂2S TPϲ?:Ə*>^21`UrE=03<5|rsW1:{-EDjfeL-]ܵA3|36lz$GNa!;F 5 E#9Vƥ̯ԚvBĠɪQ(0{m f+Qt1{>ԣy`.x1}De+sG<^ 6kI!h&1jEDE[n- G(A FtM$nDOv\ h"MJ{nuGxЕ"Ėt0\nzZurM-_9Vwk! tt*KS GVڶ5xGsqSQ5 /8Qqnm5~~oT" ^r|wZix_ǀhffZv[::aqIN@ j)aa [37Ѹ $cPZVc]"B/k#Y z‘.9]y$ˊxBro7FvDFsR3fpcm$g5FӮMIe^Y%*P@ \ y;)˃eRI&MVrQ? ep\0&^|iE_۔!?a IT+;PP `׮fw@qn bZ2_rˡgs˝B(K[D;y}b3rlvz~}"] eW4ML:ǢYOZS>dz^gc9~ rpd  "M3v`+"O]Z+vwCڕ^kйѮ@DVV(6a?+S-RU?C1XfT K7~u[0*[36i;V~ "/ O $7.q| 9t7>Y1֑EaEb +`8-_ӌ"-xӲL'8Y0ߩG+ZЗg1٫BOh-\Qߚa`y&t.~Sr7ACuaj?M_Ձ:{xSxöO|X)^egQ嬴3_y9Jk؊osSP[+1L s"km}b5_W)E-U"^ B 9WXafEROo f&XahP*m]C((T:ljLx qX52Viņ Q3,jw,qZ\D zĭKsӿAoUw?R/?S.`G2#_-9۵O;÷,y ;^ְCr(Wp-no"olŐdAW;m %4>F{!p> xtI*xvOmK8 ObtLu%N&|X.[ {eVqQ?^`q,Q=cZC6 W7]//vAksgƫ2O:c洏Y&ߘfd4rn/.@7&26[,!G&9Ca4LbpԪ(cyNC.aJK ;-&tr'{v0kHb3nTdZЮ#0Z\XʍUK ;+SmhX$tp˝ȋn*? ZFÔ.FpI"7_Q jk1Qs,N;wDhEU(ő-QYAJ1KJgj+[at%w0ozώeM,?Xy"y65a=o84$Veih!ۺ-(enTu+ ^R:/wTG o$W/&Q;)B6ZZN\2e(* ]oZQYmXt.Q4p\ 5X%ҷ+}?A?3!- q6ldpPߣi _qsŸHq3RHHlE (OHh.g j:Cw~b]uvnp E1?ӎ|NI#Pы_p~lqu-`?4z}k xj,^W|Dp_8^ "U!tދLxcQ F% T)@ ҭ؉0ٜ )J"Q^'5;#ַL Yme/ʌj!-3= ߋO4m:.A`JjU!ON:Pk%Z:Fg,<ӧ^U] ,Rod(=+4&̚&Ap ) :]xuw:9|TdždLwQW?u EUT ">kSpgmodeler-0.9.2/main/res/Resources/pgmodeler_dbm.icns000066400000000000000000003301771360462764600226760ustar00rootroot00000000000000icnsis32 lrk͖rih]uc]ɹpެZğYŶ_iPXƹvHgFD~w00}Ydȩ֧6P,3zͪ஍7=<Q*H€3ba0lrkүctũZtɹrP}eF̆ɲ`|PZ ܁݀ހ[ށ[Ȥgdfkprq¿Ā[ڽ|P)9HF9-+6t[ھ~B:˺zM=[۾b"ƾ~:~[ʄ81oUmC'9A?J[qeDDC<2Gq[< [n׫veC"$ekJ([j୲v:Yh= '[g⤝v00fH ,HILϻ[fuvi2&\FR[fаGAQ&B[fO L[fa60',\[fª[f[bXRq{{nM*##%|PZ ܀݀ހ[فށ[̀ À[ǫk9GTUOMZ~ǿ[ǥY=ǭZD[ɀ'>}[fRž|>[Կ`s¼Hp[տdyſt9[վ{a+x[ּBƶw5v[ֺa`Ʋwg(p[fӴ;`};J[f{2/"f[f屛}[q[fʳ[f[bXRq{{nM*##%|PZ ܀݀ހ[ށ[±ϹĀ[ېCKXZUTe[w@ѸbG[ԥ,ӟBz[sTό(J[jwK1خ[n~DžΪ[Љfè([ͱGͬ=[lgŸɱFy[~ȺX_|»Ev[{}vbX<£x;[x۱zWʿeTk}q0[tڮqrYǺYJysM>C[qڮTSOø9ja#}vn[nИwufdAz)arb[jsWBf%fkha[gnjZzU{$q|ffg[fJLUL1u[fέF{MK[fȏ==)k[fd~[f˵[f[bXRq{{nM*##%l8mkgQR@'58888888888888888885'  ih32ހmE ߀}Cۀ܊|D݃ނ߁|Dށ|D ɱ{ zyxw|ׁ|C׵}{mE/%#'.8CLRSRƾ|C&ص}U2NXTE/+BǾ|Cٶ~|C LʽY/D|Cٶ{R\05|C}ڸs!!þ/6w݀|C&{שY d<;>q|C&iچXZB1@7 '-+(/^|C&gچVWT% p}v|=$+*'.]|C&dۅTUSJ {F|y<")(%,]}C&aێWVVUJ$;hj,n~yu3"(&$+]}C&_mG9& ]A=tvo$ "&$!)]}C&\rHFC?;"gR[a;pb"$" (]}C&YpFECA?;^A|QCG!!&]}C&WpDBA?=;5 Exf1K@$.FGFEHc}C&TpDB@?=:73ZwjSL+JΜ}C QڴiTQF51ipli> P}C&Oƫ}gI2\nkb2 P}C&L嬮jF" Pli[$ O}C&J媞jD2ifZ!!O}CG婐jA Geb4EUV b}C&Fy~eB :_\8m}C&F|klmkHUVR5 _Ļ}C&FX6RO6 Sĺ}C&FZ$ -$ ]}C&FX"!l}C&Fp@@>946Ad~}C&F}C!F}CF}CE}BFwɄȔhCGKOOSYZSPOIA%!YYހmE ߀}Cۀ܊|D܀݂ނ߁|Dڀۀށ|D̀À ׁ|Cw`MKSbyļ|C&r#2O[WH4$!5aż|CZ Mʵ`4F~|C&m]ɼ64}|C}•-!65w߀|C&{̾fO|C&x½ þf$|C&vþ$Z|C&sýÿT$t|C&qüU|C&nú$y:|C&lùN=Ļ43|C&iøų:MD%|C&g÷R#~L|C&d÷?$ÚOL}C&aڼW$Eux1A$}C&_~nd\TcK>lOL.1}C&\ǀhN_ze[aKF}C&YwiO}IqQ|RX^b}CWknofO}IU:LA."&}C&T^SUTL~Jspg9U}C QwPOONv7'T 9º}C&OƫMyC 1u}C&Lțwj}0 8u¿}C&Jǚ:A~(I}C&GǛ%`G U}C&F/OP M}C&F͎|}~T&~}Pl¹}C&FϵO}S\¸}C&F涣]C7 'm}C&F嶤^#4j}CF渝w~ }}C&FȜ}C!F}CF}CE}BFwɄȔhCGKOOSYZSPOIA%!YYހmE ߀}Cۀ܊|D܀݂ނ߁|Dڀށ|DЀʸׁ|C׹jUS\lŽ|C&ܘ/4Q^[K7'%;mƽ|CwMh9!G~|C&֒ ^̢<5~|C}IPVXYXWVUUTNZWX݈vJLK Ձu}{{nG!%5BNTUTSMZWT݋vJLKՀ֙t}}yU $('" !6HQN[WT݄vJLKԁ ֙t}}n4 0_žnR4  6TVT݇vJLKՀ ֙t}|c[ȽpF# ?TvJLK ր ֙s}|YHŀ»e<9TރvJLKր יs~}}` tzM!}TއvJLKրיs|}|m7 ZkTߊvJLKՀDךsz{x8k}$kT߄vJLKրךry{_ 87+rT߆vJLK ׀CךqtwG #!pUvJLKؙvuu+9?}0ix}~~tU vJLKOˤhRf )IRUVVT[{ vJLKMٲwutsk_DEMgmnlkgyvuuts vJLK ~~٫`TWVZ7?6xre`v~|zxrtwvJLK}}٬_\gfef0Qe_\tcWv~}zxsnXvJLKf||~ڬ_]gfec#*-psbSv~|zxvrmRvJLKf{{}ڬ_\feda c SxpaSu~}zxvtqmRvJLKfz{}ڬ_[fdd` (+jk`Tu~|zxvtrqmRvJLKfyz{ڬ_Zecc_ XTc^Sv}~|zxvtrpomRvJLKyy{ڬ_Zdcb_ րI~6YZRv|~|zxvtrpnnmRvJLKfwxz۬_Zcba^ =MUQuz~|zxvtrpnlnmRvJLKwwy۬_Ycaa`*ՀрHd :NPtx|zxvtrpnljmmRvJLKfvvx۬_Yba``4|%GMswzxutqpnliglmRvJLKuuw۬_Xa`_`@ ΀K;>IruxvsromkigekmRvJLKfttv۬_Xa_^^M wW 5EqqsrqpponmllqnRvJLKOssuۭ_W_^^]UKm&>jpml mbUvJLKOrsuܭ_W_^]\[''x8RYQL YvJLKqqsܭ_V^]\\[= ŀ227ISU ]gvJLKRpqsܭ_V^\[[ZOLdSD*123220/..-La}vJLKfoorܭ_U]\[ZZX)wLT&-//.--,,+**)LXcvJLKooqܭ_U\[ZYYXE LHa^I~~^$,..--,,+**)(KU[vJLKmnpܮ_T[ZYXXWT% 1@vx}|e"*-,++*))('KUZvJLKmmoܮ_T[YYXWWVG!0LIc"$c~|{g ),++*))(''KUZvJLKQklnݮ_SZXXWWVUS38r~|zyk(+,+*)(''&KUZvJLKNkkmݮ_SYXWWVUUSM">7}|yxl'+*))(''&%KUZvJLKNjjlݮ_RXWWVUUTSQG5gJ~|zxwl&*)(('& $KUZwJLKNiikݮ_RXWVUUTSRQNB x }~|zywvh%)((''&%$$KUZwJLKfhhjݮ_RWVUUTSSRQOL? E*=}{yxvua%()((''&%%$#KU[wJLK ggiݮ`NQPO:NNMKH=(H-}|zxvtt^ %('&&%%$##JU[wJLK ffiްj^YXRWXXWZR?5  'G^cJ i~|zywussU$'(''&%$$##"JU[wJLK eeh־g_ZMYFC<2$ = sut~|zywusqrH%''&%%$$#"!!JU[wJLK ddgņPȹ\YHIE@:3,$#|AAy|ywutrpp7 $&&%%$##"!! JU[wJLKfccfŻ_YHIHFC?;62/,**72F{wvtrqok$ $&&%$##""! JU[wJLKfbbeVYHIHGFEC@>;9775IP_I Wxtsqona$%%$$#"!! JU[wJLKMaadQYGHGFFEDCBA@?>=6N| O/ZuqonnM $##"!! JU[wJLKf``cPXGHGFFEDCBBA@?>=/ Sj ![rnll/!$$##"!! JU[wJLK__bPXF0EEDCBBA@@?>=:)J[_nl_ "#"!! JU[wJLKV^^aPXEFEEDCCBA@@?>>=;7"@g ~&glB"##"!!  IU[wJLK ]]` PXE/DCCBA@@??>=<;94 .r~~x) ]Md HU\wJLK \]_߀ހPXDCBBA@@??=<<;;:73#]}|{{g!+BF6C? *=ABA@??VU\wJLK [\^ۃPXDDCBBA@??>>=<;;:9862$ @v{ywxm> JB\UWX K_wJLK Z[]׀ׁPXCCBAA@@>>==<;;:998752' G{wvtutgP JR wJLK XY[ŻņPXBAA@@??>='<;8766543/OxtrqpnlkjhghH LT~wJLK XXZÇŶO`[ZY[O86654 &qtrponlkjighH   MUnwJLK VWYԸukjkfNZYNIGRX7654!#`tqpnmlkihggI   MUhwJLK VVXțvjijmkkgdccdeeh`UW754!( Stponlljihgd=   MUhwJLKUUW³8m}zvkh[W6434- Eqonmmkiigg_/ MUhwJLKTTVր=ܪoĽscSW5430=oommkjihggX  MUhwJLK RSUހ%nr`MW4331mnlkjihgffL MUhwJLK RRT߀)nr_LW43*!gnlkjihffd@  MUhwJLK QQS߀;mr_LV31Znjiihfeec5LUiwJLK PPR.ms_LV3+>miihgfddb3 LU iwJLK OOQm!r_LV4!`jhgfedcb6  LU iwJLK NNPl s_LV3/igfedbabG  )/34543SU iwJLK MMPlr_LV18gedcba`\ ,KPUYYZ\N jwJLKLLOހ ls_LV15fca``__R9IJ]^_Xs}nji jczwJLKLLOހks_LV0,ca`_^]]R ANuy wJLKLLOހkx-o_LV0\_]]\[YY0 >Nx¿}ӂҀ wJLKLLOހlij,k`MV/%L^[ZYXXWT5 +Gu¿}lwJLK LLO߀ŏpYS-TOQW.(+[YXWVVTTUH9oydwJLK LLO߀ǔncd)ifV-)OXVUTTSQPRH ,fybwJLK LLO߀־+U-)#+WTSRRQPONK &^ycwJLK LLO߀݁ڀ+U,('@TQPPONMN; %ZycwJLK LLO߀+U,('! IQNNMLM@([ycwJLK LLO߀/U+'&%KNMMG2+_ycwJLK LLO߀U+&&%"99) 1gycwJLK LLO߀U*&%$# ':pycwJLK LLO߀ U)%$$"! 1EuycwJLK LLO߀+T($##"!  ;NyycwJLK LLO߀!T'#""! AQwwdwJLK LLO߀ZFFEDCA=97 :=@AUTYwqd__`[pwJLKLLOހwgZWXWVUSRQRSUWWXKV|{{| }wJLKLLOހῆ_UTTUVW\tǀƂwJLKLLOހԴ wJLKLLOހրՀւ؀wJLKLLOހwJLK LLOwJLK LLOwJLJ LLOwJLH KLO߀wJLD KLO߀wJLCKLOwJKBKLOwJKBKLLkJKBILKd×ĭPLK0>JLKMQRPKLKEAJLKLKE ,BGGFEDDBO] NBDDEFFD8fepo}|ᒬŬ B~}{zyxvutsrponmkjhgfecba`^]\[YXWVUSRQPNMLS~}|{yxwvtsrqpnmlkihgfdca`_^\[ZYWVUTSQPONLKJKLLJSxXKLKWKLMqJLLuJLKрҁӁԀՁւׂ؂كڄۈܒ݇uJLK ҁӁԀՁցׂ؂كڄۅܜ݂uJLKҁӁԀՁւׁ؂قڃۆܡuJLKсӁԀՁցׂ؁قڃۄ܉ݑއuJLKҀӁԀՁցׂ؁قڃۃ܇ݘބuJLK ӁԁՀցׁ؂قځۃ܆ݠހuJLK ӀԁՀցׂ؁فڂۃ܅݈ގ߉uJLKӀԁՀցׁ؁قڂۂ܄݆ޙ߃uJLKҁԀՀցׁ؂فځۃ܃݅ޞ߁uJLKӀԀՁրׁ؁ڀقڂۃ܄݂ހߒuJLK Ԁփׁ؂ʄƇNJՉ߈uJLKԀƽ݋vJLKӁխ߁vJLKӀ'ծonބvJLK Հ)ծ}n`:$  ';Rii¾W݈vJLK Հծ^'!4Nqi¾S݋vJLKՀծq' !&))$ #Hui¿S݄vJLKԁ ծE  0avW9 G|h¾S݇vJLKՀ ֮)]̺zL&  /GSvJLK ր ֮wIՀ͹nB8SރvJLKր ֮6 vìU" |SއvJLKր֮) ǀ«ejSߊvJLKՀD֮Jl(iS߄vJLKր֮881pS߆vJLK ׀Cׯ_ (!nTvJLK׀׮9:@/guz{{|qT vJLKOӵiv 6eqtvwog vJLKT˿~ Op{ vJLK ~~ʼVrA#FtzvJLK}}ʺ[Qhoyj[vJLKf||~ʺB0 LvqgUvJLKfz{}ʺ>.;gUvJLKyz{ʺ>LivgUvJLKyy{˺>ILfUvJLKwxz˺>!LH&p{dUvJLK wwy˺S݀Iy VrcUvJLKvvx˺f܀J 6g_UvJLKuuw˺ ߀LF[[UvJLKttv˺}ـKiLUUvJLKssu˺+Pրց25J zWvJLK rsu˺O)ր5%&X{{z |yvJLK qqs˺ ~ Ҁ.<+u vJLK pqs˺"QҀ3wcRa ~vJLK oor˺ UπFť[g[dvJLK ooq˺Qπ3joXv P}\vJLKmnp̺P р2ÞG~ Ix [vJLKmmo̺$ρ1TSw)+x Gt [vJLK kln̺ o <̀3Ar\vJLKkkm̺?KD>f 3L\uĂhwJLK RRT߀=ç|)T:O^whwJLK QQS߀ ç|UuECRc{hwJLK PPRـ'ç|PA(HUihwJLK OOQ,Ÿç|tI3KYnhwJLK NNPŸ҂ ç|V<` >Obz łhwJLK MMPž΁ ç|GL&?Pl zjwJLKLLOހž˄ç|GH r&OcXhjk_ksc_ ]zwJLKLLOހžDžĨ|S9t ;rtx wJLKLLOހ-|rAAw}ӂҀ wJLKLLOހ,| h|I_t{lwJLK LLO߀Ψsmna6;k('en¿wcwJLK LLO߀ǔncd)gho~}jLe¾vbwJLK LLO߀־:~}}|tA^vcwJLK LLO߀݁ڀ+ͶX \~}|{{z}YAZ¿vcwJLK LLO߀+е(m~{{zz|d#GZwcwJLK LLO߀ѵ'n(q}|{pJ>L_¾wcwJLK LLO߀/ѵV$WV< RUfwcwJLK LLO߀ѵM  CbgowcwJLK LLO߀ѵX2HUzzuwcwJLK LLO߀ѵ"nA%"2EQ]oxwcwJLK LLO߀ѵl_YXZ`l|vtdwJLK LLO߀л[upc_[pwJLKLLOހҼ}Y{|}wJLKLLOހċdZ[\[[`tǀƂwJLKLLOހԴ wJLKLLOހրՀւ؀wJLKLLOހwJLK LLOwJLK LLOwJLJ LLOwJLH KLO߀wJLD KLO߀wJLCKLOwJKBKLOwJKBKLLkJKBILKd×ĭPLK0>JLKMQRPKLKEAJLKLKE ,BGGFEDDBO] NBDDEFFD8fepo}|ᒬŬ B~}{zyxvutsrponmkjhgfecba`^]\[YXWVUSRQPNMLS~}|{yxwvtsrqpnmlkihgfdca`_^\[ZYWVUTSQPONLKJKLLJSxXKLKWKLMqJLLuJLKрҁӁԀՁւׂ؂كڄۈܒ݇uJLK ҁӁԀՁցׂ؂كڄۅܜ݂uJLKҁӁԀՁւׁ؂قڃۆܡuJLKсӁԀՁցׂ؁قڃۄ܉ݑއuJLKҀӁԀՁցׂ؁قڃۃ܇ݘބuJLK ӁԁՀցׁ؂قځۃ܆ݠހuJLK ӀԁՀցׂ؁فڂۃ܅݈ގ߉uJLKӀԁՀցׁ؁قڂۂ܄݆ޙ߃uJLKҁԀՀցׁ؂فځۃ܃݅ޞ߁uJLKӀԀՁրׁ؅قڂۃ܄݂ހߒuJLK ԀՁրׁ؂τ͂ΉσՉ߈uJLKԀ˄̙̫̃݋vJLKӁτ́ѽʁɃȁlj߁vJLKӀ)ȭ«́soބvJLK Հ*Νvi@'  !+B[ùmW݈vJLK Հ|2 !#:W}lS݋vJLKՀ֘5  "'++&! 'OlS݄vJLKԁ \  2dɾ}]="OlÿS݇vJLKՀ ܯ7 _ ƨR( 3IÿTvJLK ր ܞ"5KǦxH!8TރvJLKր ݫ 6 xӻ^&!}TއvJLKր67 ԼpkTߊvJLKՀDdoѝ,jT߄vJLKրڪ8:ѭ6qT߆vJLK ׀C~ ϭ-!oTvJLK׀K9B͠/gv{||~sU vJLKı4̄ /46788ì΄ vJLKf Y +:=<9:ijvJLKf~~~Cʲ'&RXT@7yǹ}vJLK}}dmL} ?UUB4pȳ_vJLK||~ILǼ7JQ@3lDzXvJLK{{}D JȆ 7K?2lƲXvJLK z{}ɀDHĻ4B<2lŲXvJLK yz{ɀDGw 471lIJXvJLKyy{D!@ì!2/lòXvJLKwxzD"JR+,k²XvJLK wwyЀ\CÊ  )iXvJLKvvxqF%%fXvJLKuuwь GP bXvJLKttvЪDy]ŵYvJLK ssuπ0U/PZvJLKrsuX-1*&^ vJLKqqsЌ 1F0…ϰvJLKpqsε%W߀ހڀ'ȅo`n ƪvJLK oor΀_݀܁ڀ*մ˝gxh ơevJLKooq͡W܁ڀ/u}e\Ɲ]vJLK mnp̀Y߀ڀ/ԭMɞ¾ S Ɲ\vJLK mmo̓!'݀1]\Ɔ/2 QƝ\vJLK klǹ̀| A܀׀DӣƹÿJƞ\vJLKkkmɼSIڀҀ'D"Eƞ\vJLK jjlǀDZG>Ӏ)Ԁ\E|ƞ\wJLKiiḱ;ĦA'ԧ K{ƞ\wJLK hhjƀ?R TԸ4L M~ ƞ]wJLK ggiƀǁQºl&Xҩ7 Sƞ]wJLK ffiÆ:ľV# 0Wu|\ Z ƞ]wJLKeeh̨{c[ZVȾc= ƀ"o_ƞ]wJLK ddgޮbWUTSTS9VVyŽ|gWF@?@,W\S)e ƞ]wJLKfccfްZpztmf`YRLBW~ý~\ FDd66jƞ]wJLKTbbeްY}tj`WGTtQ^n_J}Fq ƞ]wJLKaad߰Y~{rh_VFSoȀ.8i+O/xRyƞ]wJLK``c߰Yx{ri_VFSoȁǀƀ+# o!I#^ƞ]wJLK__b߰Yr{rh_VFSoǂƁ&½ d#8g ƞ]wJLK ^^a߰Yl{rh_VFSoƂ,rW~9g Lp ƞ]wJLK ]]`߰Ye}| zrh_VFSoÃ3ÿm?; ]z'#[| Ş^wJLK \]_߰Z_trph_VFSoÃƁŀĀy#0+AE6hcAf͟^wJLK [\^߰ZXjig_VFSoǀƁł) Z\ #t!Xs awJLK Z[]߰ZR`_ ]VFSoƀā#½-g{ZIEJd@ DdJ]^_ ]RnwJLK ZZ\߰ZLWVTGSoƁłĀ5G'a,Ztf||zzyxwvutslwJLK XY[߰ZBHCToÃÀ8=tr QgƐg{|voib[Tsj}wJLK XXZ߯bTSVUmʈ9v6xE`}ȑg}}vng_Vt_nwJLK VWYɔpPFECW|{ojkjh9ņs 8[tɑgz}vng_Vt[hwJLK VVXɜwkijjknZ;63234A66ʿř}a3Wmɑhx}umg_Vs[hwJLKUUW³8~tjaW@3}˿å0gC[mɑhompmg_Vs[hwJLK QQS߀1>|~tjaW@3}˾bS$M^sɑhnfhihf_Vs[hwJLK PPR=u%~tjaW@3}!`O.Scyɑil_a_Vs[hwJLK OOQJLKMQRPKLKEAJLKLKE ,BGGFEDDBO] NBDDEFFD8fepo}|ᒬŬt8mk@*f 4 `P y!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&()*+*t > @VQw0 $&(.6666666666666666666666666666666666666666666666666666666666666666666666666666666.(&$   %-------------------------------------------------------------------------------$  &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&      ic08z jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP 9߂He P|ˢ+LmF4]^U%`TLUcXFfXQL ᰎċcJTsOgpWQ*k_k߂(e b՚.|kVų.=59#Uwγlw*nAޕ7yfB>XrAi*U*n.osG\eaTْ>ؐU\TB܃$q1X`ԗs炨{r] TKWߙg(4 ,%N7) s~Z G k0CtH߉Q9 ,hD"a?1d5j+i]?՟?:x6U1L/HlzIeJRN86|zWeg\oZ>YJBڀ,ҷ2ErnrЍJ8Lmŏ u}- WZ$;L FQ s qXU` a钶1NL9o3o Ef=:3VٵqUro5q۞N5η~m.z0,Xr%=IY#ik=D'G_4T syeo^dwۉnSg֯}dqr9fxX"z4xmk1]\k6C 3dvk\,9yK^sag*g(B棻K'2QO# Ck{8Ch(ߍ(kz+u!k+dJxaE)11i'"917&ZYrz&%4_2,?*h~Y>}u.ej{5D qң2ulD^ֽkϗ?sۙYw0O9-_xM˱U/ٟ?:uJO 8WѨ0~ۤ6"& Qn`K՜0gNV V*XơK&~r?7γ%6Rr-X\_<[cx *`/. PgG6O/>GTHF p"OY9M, -.zS"!K^d%cP fJR@n,'a)U˥%C;U-mɂ[cDk1V-P{9ՙ!**d:tHrY-(@Ti-˾6iożdVusJ$+KrQ/{mlڰ1ԷoLxMC >lD07Q+vr?kbà ~HXfVucwDZP3좝 BO*Y;rjvضDgh\v~NDOmx3P¡miٓTisE HLu?b*V_]e-L۟?:t0>cȚ\o-o$2xИȁgL-#b@:%hbCV`ϷIjDVѫDѮn,&w1jpl-Ј4\C.K"OҶ+Ϳe[OT# ɼ%WJC݃ԉ&MzkV?[z8Y D*^(…H)%b<]K.zU| YQhڏHmDy+ʰo7s6RGQpg0#%6 y0 *YA͜kr]+(ׁ >-ˁjV`jQPj]h"ZJ4iK?v8=x=@S|[Hܜ<ʹg*CP,-vj -r<PZm/TO'Iꉧc"pq%i/dOhi(a"s.G[&*21KV$$0y30ztPA}7TJˠ (j._(%I4 nŀk) 拳?tR&e\8ޘA\<--9nIPM;-P~^8W_͵ ?t ZJq\z S nl;sTaziztVX:׿*Sn-jV=0Fmreߘ$V vw:r2Ү%5[ke0ʆm3,;t-O2~Bǂy_V=r yXƙe` wXEcgL] ㌗AxCHDX]œHf>$NN3:Labt&R!7$KFAZX6AG䣆qD3ST.mC@fYyW. /܌TNҏClj[2@U I#$[xE4 _{Jma-0F|8 %߱&kI:-7Wr[s14E d. KC+EF{KSP+K^FY Bf`"p0vuU5\ʢL怋bF]R^ݢgIH':RSZFR T8xժa- |{Ґga|N8 ѢzIfN@<^Poۚ! i $G.qn\bX|MR/'W`Y*51\e]e P@4FHgd*o(=$2pKxKNXwntqS|w;[OA_E?=)'?T2my";U^_o b8' fsm)TrG Y' '3Mo`pK;ƉKaA^bd>a_#AYԺ7_^Kf~4i~LΡj'm,'La4|ʿ+ tWA(Bc ߟJsz~{lKY_N:\H;7"fbZ-^&uxJvD9?`!2 ~P7flNDCI w8|׬x{T] D^ޢ[D>œ \pv&>)5zТX,iJRNɮ]6_uCALJ{.hD/; ]Cu|u2hSjMg5!R Z 6/qCs%XW{"_20 WUAS>]-F-^J)|Ryީu WTphf_Ml~\آ N}Vlg#h37y8$`}[|[o=O rux|܀I{֟ M&T:|)s_vaM.s\ I=d:j(`@d2nt5%[OH,:ɯxDJz]r6[} mĶ$-5nQZ."NҕeUF/_9_j jWMmW:q[JxBarq!Qk+!#*szpA.MII, I)=tGnS_j["#uBEt]ۃu";MdXakIpzsQtrxc-=(P`1SA 6sC[^ ѢGwY",+~maMlQ8:䀠]4 e"]L_/)j<~  *Vƶ{$v,SukQH }4lz~@$3%>&4l'>՞KwoVNrK}Uq+9\yDeA%QUK=uY9K9NUEuk!8 e<۬<2%|=4a"cZ@m$'o"m|ry-hUa3wi/e fP >S=乆19`օߙ2?̻/E2~pg3)`bv,:A=/[m`(,C QWV8MЬi25/Ij:XX3 J6 [g,\6vT%UW.wd.I1k}U+KV$%4#:n\&6po)_ <+ x׶mճ"3~ev%v$hexĀsJ MiN =ȕhgl׫@B̃q= 3hmpɦȞ߃yF)pX h947e I+C.V5s-L.IgQy`ey `ƾ㪤݈/?S!B35MfZ8>(Bf`$ѭ(\ON#HcCeG~iAENsNFZ{ U+Yɳw<)3 Cv4ە~8+f䘺ƨJ'͏V0 "vbׅINP]Ћ 91Ww#~URR7~g8t3<$@Cߴ?p{8Y0;*4Ruh}XYp% *əAD .G6q ֏ryݭc{tf%lE rdNf\ϨwTCoǷC }ATT gip: {e5 *Eè0)ЛѼXma'AG!%Ja= t!uJ|JAE$?dFK :ôU;͔FHrђ)WՕ*dr2N,*ѥ-gj>T @ِ4(nsOYuʹ׀OE#̚ռ+P6ķޅjIL"NAw!5y7)#+¥7 3#0,}FQ=_{0u\05om< TH go|9 |Z;}>E!sѿ_.i5nqgNxþ t>n012(E}G7lY6}w}ߵ=@f#PTS x篚ˌ[£sX]wAxF7jī]ڴ+-#>,BGZ"KVgV٧J#VD47pe-5|Zvr(p*#Ѳn^z;k|!7]M9`X"rcJfn3YTk&䜎cGNW|]Ψwnډw@<=}FI8r#Թ@O6B6+Mfet(e֯ /E+g0J@6Ǫх\'i!UM )@KH-1@O㦅Lot98SFv_L0p8mqYT27M e%@d=H,LVؑ?%r\h0qJlBg`3bG66}^dȟ|' 2"s&3% +̆-,vYiAA9. RHAk҅)oS K }d*ѕrLlrSVDN 'EЉ9 :47Vq"U1?kɒy\ruLo=zu;T z>gihMڎl+/Poe3wБWjBJxU/*pIB2-nj|X]0,aiOmu;A#4D@}̉.7QiaL`!meĬޖzL;2αԿF\FPТE/<.܍"P%)>]NLb> ݥV[퐼x,Pc %3Miyu1p%'JpZ<}~L HHab:Qx "O6uվdZrY p-74qU??:@@{ZA'l0ppB_M&Tu58P#y'9H "R0b9x<]%1-(!r}h$ߖ:KKL3!͍Jn&ߖ頼qABB)do?e:!c|;oK%EOTۧƳl.1~]sVO[֒]$2j)YȃB>V=乆1֜YN7mﳻ )_m:#}r9˕eņ\:&oK+"DկVA]@8?TyHԈ{@i9Ht>ٍeaz` W޸NMbd7GpK{.I x ϚR˯2@ϐd|&\md=t*߇bG[ŔQiB͛ ChPDsmx^N HGX R'b:Ve"E*- i+2Q<>Ϻv$ vj:DPB&8aި/ y'; KC :5ɐọ[駱>% ZWz kMU*qxDS!8.j+\ŨH6%"}ePEK(F Tr$u駦}4KKHn(00-KC7=y{C;v>mJ-BB'¼T(Z B(nlNWj&NPO GhмNtP:e,ZLc[ZIKG{LRqC|J'*]nV%L )OV l<;UMyfR\qL/;"51?《cjWD {xaU^+3y*GJ'9j p䛊 %BϿE ^hټfPI<=wi ͈ cԃ7K%w<50;qьm·JaSdi!]e;9߿:?́%V9 %{|G/D7vo`'&l#&1# s NOD\B'$# CI5IVxo ]dC%Q6mwcÉ[ÚЎzoi07>IV۔3 l0f`&oLE"zȠ}| Jjѧ/SlՃq?Ŧۑ\y-#dCjH|U;R굨(g6ؿ>a;]!Em2Wr7ձμ%*lt~--sn`&3ix,KsN sk@>՜M"r8J, *^%06wt6[%EYmRMߡnh]'hK(qb ė҃ 7z?\D[D$s1C X~,x^?-UNėĺҜ@ uNXKZ?.$d  @+Q J \zKք<+ZDpI O6!m4CYA1!-8) ]:)"|ZtSĴՋ A7{R[{'N]$m6 \T?V!Y#,|Qm"u+ԡ[kBi29V$ۓ޿.rWY' s?hR#U)k[L[Uo^ sʧ+K <] -DP҆v$DUǡrNyڍyS]8k0@wsQΑPKʓxM؛`'Hh17඀PkpߘW?X*#<5H!kooޛTVʞw*@D*GncqM;BB5Ug~:N YQ!S6qQ_3㸛m(:r%wVAt @ҧ[t qvQ@3sW/;z5mMp 8yR=p8ZW9®ĄW#V "kbC2$) "$鳢ϣVSi*:J%KͤyROk:,suڑJ]oWĹ#v@T\*IHU7ˆ,rAc[Gn3$fjW_ORtKnPr a?y RFKWK ipnPEh=Q Þt3<ccF^8XO{ǍS(8=_6A86.uBf4%yD78c^|+-q$#rʌSȠEX okqSX~#S`Jjv~X}]!Yw f b y;OKP~@09͉)a}+[̿r4X/,cõb[v AoFt,Lʐ1+MњY:/Y_m$yQc$zP`.pF:[2Re L4B㖅i-p5l)+ΊjsOh\(6_{M`uTꢆ`t/[gp`aGdm-{Le&K(;!ڂI%Z͸܄c[T5Dlk Zf)< 7kCZ#ad'S;Igk3)FCjVw}'k{ɍ !Bx"H[d^xM$љ>˹DxsL3d )M򟎺&}R~>:TD!VqlHY͋;`  #lL.A3Kui؂~z<乆1D7J))uNk#n N)ٰLn/? ͥ J|0;4e&2Wl؏+0&/c17>sͳ,Vвeiϵ0idΝ8'TQI,$[_*18|R;~ȴҼUԎ8 2ϩϋԇI^cKĮl}e2k2<(uNsӽnfF&r\i[@ #_t*!(NX8%7Д>L>tQ1u{ h.c=Z ` ^h uc阏8=ikXwK &g`J5JJ:{r=RJc?n$w"1ߧ*g{˻ɢFdNTX?6f92@cN NLh~>r'O4ͅ"1RGJ͏%>$Rϲ2۝T; HS7MO`R(N@1J0l5H7M;4x]}%ہZʁ]%Q$XGY,jxjF$Bwl''ѷk$-)mr2Y#CƑ#x Tc=A S4 SPEڽy{=oȔoUquʇEM,ZWr)d1h9ϨJP! O3l*W(Fʨ#e3֝s[CءKI};)[ixs޸"L8;η93. Y(EW?6Geid'lg2'XjG19cV䬽,`zνMM6j6V..@ψ1ntRRzԶjr11AF+pNBڼ&GDI oˇ֥+*!7w۫p8J୰fS鈩X"4Jd$RqeDblKIDtabk ~p)`2ȴ,l+!ЉN U=7b0\OE=&f? JbhKWzũQ*ů֯8DLNBDZVuR襼'!ߴ$$6}D2%sy2qSz : Z֮U@ ]G)e# ?'Zxh JvV]]9JX=dT&02Nr=6-r [>‘!%&,xi_r$6lR NgTWDn2[xqYxhz[`l9 ى(}F-n/f^B!-uR/ofJ8&hd_twCka"PLC-g9R`2җ|{@Sΐ|#J24q\m>..juNAův5=5$./ViJT)\s8FA+}F9 L&P̖f.Dly^+x]|K<5~K~}?Da>+WAd֍&7jQ@r D}cޙAPG[AS9ڏ(΢P83BcBV(DaN$8n8Jw{4#trQ Kɷ㪅P>K p#A+J6EqK TxޗCw*Cɯ{c/w IKI!nm/ESeG؁T_j|{)K՜(q=ݹEP1GJ羀EoY(h:ޙv|VV3vC](@U8|nb2;K^Y_ŗ%R]^ Mh ,쮦.sJU l{U1VpK}kZ'r+q*AVE M?Z* %L(Sz,r榙5v|r,1c0,Stmb t[7E2u+a?pL)uK2CoWegsO~nDuLEN L&˧m2du\u'7U ]ؽtSq՞GN,F5ҮNBm,fCլz ˥yccAke/BV+:(; yTf`(2rt,xon441XvIӹa(zBF~7nnw=Y1:sNR/Qص6>5B\F3/ g0КqϜ+ "nSuN\ lh1.1bU0X]FT-|mϡ,q6m]j%u5"OFv-yN0|)ڤxLCxf̢*'d%0gKBadvۆ:G!@1LHJՔĨ*^$ C$'R^Y.uQLg`#Fa\p_4cHν犌 BGYG9cu]Q7l5Vy%TfSI.Rѧ1ٜWo!؝W%OCP\I#ɋ԰VWMFQ!:7esܧ0O=@Ɛ)KR3i(7EpDYRm1ƭL q涄_)$iq 0L`qtl~-hq;?™pET LdZZ /1=}~PUӍe!0{)j Mjv0sD|+ʊX#tװ@e1Ĩ)BxiДݘ!I9)הI|E?;7>g R %3 bQ%ǯ Y̑=xG} iIŸxIJӥǶ5e:V{t_1G52-ª(z֔)6$)ph{*=Mh'¢,0^X!w*#_P eT6ˆka̙v0!a-!Z*Bgx2ywC~\( Y( #mkCrDW@CKt[6j Ne?@2cAR;_}UM,LۃQ[]&<, ibܵ1IGQZ93$$A Qx(DVӏ6,hebTb]<ꏛdžVEg6YcMn>q[ ]Ӕwl I;8üdmRc+}L.&7GRv{oy) Pz0@jvj,Ŝqߌ6AsE}ӌu>Ah=!`(Cxdv͘MnϬQU!T@GswXXlZ- C Q}^P?/]WFMFlj|)4M;Vj * qGub;u;1aB l k p2 M'|M J V/J~ @pY%Sg-},GQ)2!d0vb:Ou~ kohme%X9XimjwMEYgJک"~G8YJ XQX(xDo.rfYN&`;{KAmz5pÎC !in3PtFfٿZZr1J}^.*Gi_>5]?un XB9KJbfl\TTsP/7K3!UMߣd$]C.Gnfsk O Mo|b&!&}ckVunD ms*ʩX8^ "fWio[ =>qK4>H4ɘƭeԁS],Wz,Xs)ëa綟fmUQ,vXrdX*Lԧe"5tτA |=I<OlmXDQrR?gT&+-noq=t @PmE c$z ƞB͜f&Nw?erIkIW7?Zʚ+ty+)Y,xŹbRE_1,B\TFݳfFXVX-wY͟A.QipQ+]{Ǹ`M$6ā0⎃X='ISl 6׃\Ò_ոp<̴tk ˡD}=L>,Hnm'^t_w8Бb -[D4"sl9P&{;A]`*f0B}9-P~4LHRoH17oA;#.^ f <$t6\g;rS)`6L(NtΧe eHW,(:%t+ϋՅqw ƀ<DS;=z'ۓ\$1*k!ejco1bD rL+Imq5>К(\2MEvF$(LZnh9IS#2hPH#7H#}4b,xlUR˘-OLT㙼HFSkV&/ͩd@lvr?U20<؄viG؟-yQW.a'58:6>ep$x|R2*~.o [2 :e\ f h2MDNt y/s7j;N Yw}$Uu*Ք IEY4öC(QOXwE(sN:)!ŵpkN}wR  Bygy 2kBva[E RxƿUIi(QurVJ8N@?G&CPLF-H*ˠ,.MNERMI^a{.+j~G̼5k׷_jJ6@d{nqgSw|wȔC =As8^?)1#3 !PUՒQܳͷKnYX?v"܌ @GxuH ǷB@aRk穯fW/0/&5fãCpOdQ DMn_[ B{F"Hĥ\YCUҩ~H/i`g̲)jj"@$ yR#؏@~Sy6*^h1ϣΩo{. ]zH0{ *n`]anov@Xev2Qu*Vnj$nqIz|#׍H@j@^N[=a:Rayjoy9i3)(83}lNis5 `8|.rIH_% Ri>((B=ij+eǤbuf{EiV5({ez v6DdhRmxP}L'R~yչ g-Hd?;띧w~  4*ɦ7Vdks Dx3LZk5H&x$OZZ=E͢Ye U%> hIMߡ}5mTQ~~+̸=$b?5DkaPuV-5c!V7{D%J_3 J&nKVWK̕J`I{eHq.NyӳF# hUfjd4;L#u4ju9?2Kp eQO`^yGN[Ɛ7SDO/7$+?к_P> 㜭G 0^?l5A>Cڈسe櫰"3yZt1BqbzR\lFv^[JqT| XwiO=pSؼ]G-ǐÂG~H!ͤ^;O)[x;kra1:HnҠh7lxb$'OZx~2p  #|FR&l~^ NC}U0 Vʲ<=qҝM;lK"@b.0Kov@Yc$B$\$ b!"-Xm-)IG;Qw@գ2m @?$?~[y-01uOP!@Znt#T0+q\HS]ODVkљ\[7aQXK5A=pK]z( F:4DƓ#z~ CM ޗV:Q^x4a_ F+9dB7̫ME͞+w`<чXE6$,<O{yh<+eMmr?Z+ElķCE`i; /c8 U_B%DL17 :_ԟD߂7 ,G`Y廈'Fo4G~@gǟgS9 0L&8`ê@z!i= y74"SM dh{Nb ,>!$IijuFNo~0j4'zHXy/+;dsR9F~3+<=EͿ;6_Z `?"P =U32P?X-q SgR<C5!N6^ }{5-RWa_%zaDG6Q|X ejPQ\'h>e'Dw&@E=J91gtu٨l!ӂfHe+uIZvo]Хp&ɕnQG-/jǺ"S#Փ=> Cn5yǰqd>'0hq2T`v ! Sm1e i>N5<5ҡ: <& :UtaٷuVOcp6z1V,OnCLZ2II"fskbtƭ3kNr;=s40Ai!}HPsTƐ 膿>,CX4inv^?ZxݼbFP1ß㌳r?!`.`6%CA\vC*@؝PwB.=Wt}?ac1O&oG!YhFA;tZ^_!C3PS,q+OBC5yI{Wi#cX4gH87%.;=Ϝ+RL4ڢd}6+J .c J0oF褶$ʻ]i7+W3*H|9㒥̬,4_N (N::L|Z:7R` D>&|A7{k]P' Eĥ a"ʋɇ A<Bt3 VϱYlu}5*ZP;stB/6gBbXz $"[|^Keo3rF?&/ꚥ[Ajdf:8 ut0k+-mg"i_nvW~,QTʍ.K@n GB3 #jp? +6{-wv H9'J юRx+iz7Q:BNˈNb,]ZU](wչO?Lk,{'NO+œ~[bFtj:=лԟEdac{܏kwM'> #ytli#v(JyIKr*>}z[He BI{3T{w*4Ffo="[o5*r890$mdF:28mg{wː|+yACL0zqgĐp/۩5^3L@y3=^Ж{b`"fg ["M+r0sp>Y,;қoY4 R"3Xyounfk_3~gA ? LVsJ;'#*P xG"DBgM^1\D% ʚFťU&u~ɖAx9n.G x&0M=Z(rGOlLj=)XE 5YvV(k*۞4޻Мc9U a#mJ4ayva E{]7@pj@ܝ$^`}-GJ$~ w&&BbQ8a'. ҆肀#_Z{9{s"Λ,e| *&ҵ>sXC j]K3To~Ž{Qu2!R|k465t]~ߍI5khcWF ͓ Ƅ&d l$5 fp7$[ *o2XRb2A2&u9)i}ϯBVXi(GjJ(_ZqGŐMּ3z$V~2Z݌ ۄ Ӽy TNrSRL>RQ&}!)q\7^ !;&ZZА*~u3=Jǃ&ߕNQv'Y5>J@]샺r+>4[w Z.aG/qi8Ӓ+M7{(6}u[qc2-nl['plzSmezeA0淼8YOdѴ{]֒[W 6s| ~je ^ѰC}s\Z| R@`G;,u&1p @Z8.eJ˻&Po`隰X[z<)Z]"Kf8NH ٨t('IzѶ3ߡ#;`u;6u*FK,iMð79` 8FҌ0 h'扂8l8ZY`sC$poQi*<^WDQQ1CJA^$VMc4:Th`c)/75cdk'v5Sx>h$Ukaf|hihQp'oró?oxؕu{p#}]/VWIRS;;u.P֗`|Ų_m ZsOE@NT[,y_ic]|HF.pu D~OD+\/%'E \/#}lPTMptwp%:8*=δuS=~5-4sfyG2Dv r1>ã$1_cQoWc%]Sd1 =r}_4Tz5{}嵭#^[b:["#}>J$eU+JpEm~2hۄ?<잜"]"q62 H}R-;)-=Fo|U% S׷x$q&-"{vRٯjCw/+HW:r=4߻ C(h= V9I- t-ЀC(WRYH l/#Sȇ$8: ə.Ǯɘ~x45= 4IN e d&oņSӡۀ-}p1 FnefvI#b-^ԏHiy;??88F_Sւ}wVZ$=_=Rƕme#%].r1)9l_2A Ѡ1PW.dm^јUR(4@`Ѵ%:Nq `8cOT*66Ե!8"6rwֱ$xWr|oUXo=6 [#|(POM{| m!w7#oK ԳAסƢ)aHJh&+D)~T)Rz6YL{`>Ҙg: $&IlX`hWrE31<];O Ov" ЈJ% !W1Tn2T MgvZ}|:Z|Q5: Q~#69~Y#"|!2t|{/"7\u|+A 7D|ͨd2ÞL+!gŹ9 %'߬03%,s/z-FiKa-_lJ*=?@䚍Pz}@(8ys):kCfD c"o1 gk /3oWBS߽V|>>o* QoÙe-\neg (x+v\a 3ո,`vʰ:X<)*U=p6#хб҇l` ?66rGnr,Ȝ>?Qf竆³Xp<δd8Q`;b>OR$77KY r}ħ ͠ƚd5 Pi\MNlu8ҴpQTDl֊f?Lv4%yuYܟFj9㒓) eJcȀku{Ze%ZZ0.>k5$sZ8? 9 ᴢNv_"esDXdtO P)zZd=e[(Ec.\YcTc#iCO(92bc:K1.`fyL,hcsrխT] `j> N!%oayfNԗ4#1qP\#*W# g&t'2zBC D-0H$JT q 9OZwmmNd}V!W,eЌn)bH1&+'a`Bì4n_`f.^|vTYxɅ8EjQf&;/[2ڪ*qf?JO~b ?VĈ[b1SNח:T$*ѣ |6V]:р<54&jVD0Օ9 [ܱiGPdiuH;=PdyuN=a\{$F#g ,__PUև3 `Ыĥ/I=C mhNskax }wR  FNIOQz߄S DaʸLG#NrDwfG4R)9x}-ډ}(O"hI`/zKet%0cHا^8,HV*h&EmOQKKg^J/Ǧ)> EX+?cjY{# i#nxC^ۂn &@r= 3ͺpvfM:!z@D"?TX<5n(S\V*Ak@IVq\O?)oB&U/a=W\[U>H5?d-+p͇ I``ҝFVh6j`pc TYk E{muwSvp2jյ?}IS}x6m LZ0T {98r gl%(#Xwt=^{.P(D j$#wgg?{b`*+G(0F*DR5EKrX}XMFG`y.n,eP,i=, CbuJ&ij֬T[6nbI ]#71גʴE#h>soT6-Y3-XxbUYx(/QaQ e2@Irw&՞apC,@;3㱸59'h/5P̘5~=~== [z;,9w6փ#kQH $ք U =>] E.> 0c!^kLB"j9$>}.sjj9tMmB J(.rVߧMg,lY? B>™a1Zi UtUw nDPoM`F6~[Pyt%4e3%yL#HllytkMqRb^}D#Jر 60/lK4)޾4<@az!=[n.2Nͣ(~\mnv -U6{2B} 1c.Y;^[' V5RόznͩmL eQ݉Kʸ;:R t?` |HhO s-LO8E֓UU2^L%V:1$DQЃ=jd2*3?Rm.Fvp>`*&..qUiġMӷ0lH/ɪ68a ?趁R"#IUGdg(410 Zq#E.nEي=n0q>:YOkv Ѝ1 +Gycnh܋Othr{fRP`E6Ill>jf^­pەO24ݎ8 /c!AtNָ/;ˏ ʴ~ ƛ %y fxcUA\Xrv5pQpZ ;6qb}7Ǒ@U'D.<ȫyh@>W>y$:1ߜ[^败c=V6E tQ%WG-I( l6)d&_Cҟ^KK??v?X4T@ ׸ld*Uz NdG iĞ5ϲTnƮRn{+r)?ZZ?G Ӱ(91d6FloN,=o`vIEROIsI~ Eo:-),ly:[aHaD]N*ke.-Q͌3%ŞZmh+x.;mwzesqVeY1hniQ䅍8`c(pOkO7spvOb;z-ۅu=9RɌ8C3h}az%gցl>"MC, e &L Kv|RcZ7͌{9ЂO&[!ڡ]̘H&\nǿa2VV!"pia*&ʧm85'-3jݯb@#͜wvYa}螤ʋ>A<ݲ 2&sN}h^lhtl1mZ+WE$⊸_p?k|^t:UW-zKs+b,&@=⒅N$f<LJl@Uϑ߇Qshkc-RWj90$".u?oѽ^HY\GDyu_8{^F ։L:o@t#4+9昒-Ȓ{rHx QŋGJǁ"W] O/gbMs ڶ0oz"-&5sRE,Sk1=E죳-&;EZѦ(`v| h=ΚKYV7+KH}_CC}Ih6lZ_T{D}Z-%]An~=3(ŧE8Bq:PWmvF!0w-Ѻ&Rs2%b|wW6L?`1Τj'ifb)!YEHz ;_h-.[Mv|bt~Qh:*q>;*5k, ﹭H_wVwG}If+?j.:4z1坹_,'vV 9;bGU̦=iN;VA/6p7nXLǪF1h5R<̣q[ ON|_]:K3el[sp7h4 zZ9C@МutoarXGMM:fĶ3^^T;p84]~7Epzj,$W{pz=2P4JQDVTџb@n[ ^y- W&2P0ct:^=p 箩כTUR;ә7^c\hWW`E=rk@U0.(-qϞw O3ܩ,}T$EՠNƔ-\UJUֻuuMt3x+9lFхUۢw @tDS*K_#/vʤ,C^cG'Pcc;ŝD٭WF6,cIm?EP QXЬCy]gV=Pևƒ}'.Әj9@iol AɱQEjWP`"gDd@ s̮I#1#DKF}@"VW?1z|w&8[֝֫?M-\X<]iQSDή^K#hR3MJJ7FG^*'uvm* TN5{ᓡ{pǟ+jaNjGM "0CPyu!A(UuMC?/3sqYI7_Vy;}f#/uI%O}UD uY#E\T{M*= p(TUD32¬┭ĥ 9U"Jwf dǵ;_|fP Z9Ώf%b_"rx NSk&6d^'ځsk+ۉ9~ڽV_S>>a؅^yi$i^:߇@Zt?SՁ2 f@VT"Q k#Ip.֘s h~| D|x>rfTI ۑTE!l3?b n]'cplonKvE8jhXvbc:fTU]"FII`k- R&ou_óON?oz]u{|Y}]4_VWJRS;;u.PĜ /O1s%94 3H󺄬@"ήwD(k}ؤ &=ϯJ4QpͶ"wWx  </CG!B"5WQmdIBkeG+8OI4Ab._ '~&gi30'_GVEz$qe!E+ ]/D)ӥ4)_PaHt%擏ԓ(,y;{d+zv}";BmHu(%{>c#Oc65hF!׊'3( !=q/f̥wAX㌊ )j])l䧣\#x}:N`׸fvKTpOAfݟN͛~UoČk`pNNA/@_pQuPWX^y&j}5XQmcBȺǹpA-GPl: A*cL[˪:ǛáxKap{>X y^lЎ2!BJ#{~#eC՝t2Ͻ |2cA6bΤOD_U<# ~B*  XoR2s7L1by% %KHΝ1ۅM{e,wn!gE+[TTb Q4rM7VC'O͐ v^"P%7GJ*1[mS8FlZ[΁M%o׏ZDR^]Kh~JDơeUQV a;S.3ť~aB T.eKf6`4[tӮ7;/x̍9{`reνz+ Qa?kG=|@E3x\C:2`tSzeLx/͗IFyP1C(.t< KI_5eDmÜrRoԎ ,; B=˹Ȉtg:i._S:vh |]oܤ{㩾v_Y#4V)wP'4k&x_z~\;~Gk4IŽ"`l#}Ė;4Q]iÉ<;/whQ8) UL.'kNzFSylnIa'x`qu{xn9e6')ZirhG #_sZ)ԷIc:y`ib)ߞA΂;(2WL;DxP:):֙{.,g!{}rZS!\2荜/ꘫ8ǣdBFmQ7%7 SCk.S1\~@:mmc]Y7ƚwwߨQ 2B,|=(J"-#qpEu}W~ݬui\l9vwghȘ1P!&L5UQ5A^iқH􏞱 {d{OLǡ^}#y#LjN@`~g:@1"ب=>uR2^K x%8$'ӯXq7˟,O:y Ap ty]j^Ò6ٓJ)?IZ "{:xQPkͤ z`[`&Vs]; ^{Z]z \9#Ճ#slOmyG(N*q(*-x]1cT5ɽJz׶HdU `RBoHڤ`|c${P%@^<|/+Y2e$8kPk iN_s/b,#PXx֭t>~M]Z/${M:o@"eB,8'f#\G@&նXC?H06 4Ve+%5t#<=~H-LDYAIU*%C8?T̮#0e$KAxZ(Py;\q|noEt9XTJ-v=bŌqod|}wR 8gD /?wO t} #,hsS{gϤu.e=^ɘf-pxAo5?GVTԎmܯ>⁐Hg9K+zD.VTVs݅LT ^T$5 JhqPc%z?ˤt/n#| j+Z|P@InsX9"ڭZuz+HUk+chϓDίP,N%:!.כFu]- t jUݸe]u 'qW<.dkO\+EǍz`;1y"3=&+,bCHrRM5j?_<(1|R^,4:KN2Sͽﭺ4+`х*ЫA !t $܈O7>.QDW rvïf#'@SnD.?]dbPI>oOyy+C%`~뇽~{lc|tzw֪@ YghumCY&[Uq)]dVeʉnL&)6'Jhmxz\ Et q[6ꖊ^XzU-̉F(f3'v $(Or_y?V1NJXFZ ^95[AFx>Pc[ա'L C -ֈ!] Jp3١S"ўּWބ,B;5vU KqAlTa$@f6 _Y#f/y>zē#'!_jtx;irlc %s( Q|8)pdy]C(\X<' -,G;h͠FcS,Q]t-yp孍yV2OMŒwD(a5}G-o]|}w8ƌ4N$^q~]HQ͉D9z&Kp!Q2v]-0)b"δZwJ}3˙߁J@ao!oQ* j@u`N)7jmR#E!Gbl+\sɠř,??8D2R"@ae9"oYKaFBzv<ssqflTw~a$nҒՀ]WJxLCR٠{K:TE.WsэJ/R2OGUJPd Up_6z Һ<<)6"ۓ^xDmqWK2[tHj=kcK{*'~GE&5q=44)|jIoma`gϥf+G=<rTV+{^^\V}VIﰬ\bږP }/6XIZzֲODt"'O ?ݔܪ+|Əy-nYÚh_M*YQ:OK h@RŎw1xkT`qqR_.ݙrb$̈8vRn:RKvZ?̧#w 0;_.&E!\' &9ĺ.Y \b Ҝt&u|VUʌ[\97ؓt,T/v ) 08<é^ο羳:͚@$l"p b]q<#!Ԝ |'/uk&tg ~v9=.!3@|뼅M5P`, =َQl軘6|f@9[ylia{Ͽc3Wmvus#!u♐-b2_JȾb7-PA^U݁FG3Re+Z"|ͷ{!{ ܩwzu l6aH9\!,/%;Vu;(z^)wGI9&FY'g΁F`2V2C/% Pl@1{_RM+a[ȁQ[]9tJn#ł>kp+?eqr"Dyvi& o8dO'Wn#mhM[QݏgiUsw2>8ϩU'kT;~vZ5"Wd!fBDw43N,^lcSlk:XIo tKEr&`|$:`{74 P# ʙ]{|j2T `@[Z) !.2hr^WD',wՄ=jO\V.?ܗJeN k:80wq&E7“sX 7dnlFUB̀Xt[IA nD>`SֵŘ<C=}k9P*5i$ Dd<8w&>.g~8gJ_pj@Hؓ/pR@Q91ՒM@[KMUVY (1}@:: D!%ЃtV1^3SZfʋl9@BqWatz<[\{j;QY9XOq SI?ɗZ%bRsw(_yac1Fo'\א{Ra2GV:V>ELE.*t&ΉBsQ &RI8.u[_ᵓ (mXr];]Jd $rq 8Kvn0V[Bna;B!:p1' 0ftLR7wbHr%.gP.l(T!PpIn+x[pi*?}5amCx'wmũSS H+_39d8 tZ`1bߐ:*Y7 (=JN}_ntJłr>{*Rkrߕ 7>će;uQ(v+_ QRKz^>vG.r.&(V22B6 \ȥ^^bF30_r[O^>GF uU\% WTDiI,As #'؎8 ǦԓĸݙLiklt-"=:h.OI)QN/i`;04^s}'%zNgş^jiNÁ<00Z?V.<[,OwLB@I IL@Ze36rس6]LG@x]DAg&y@̱g-w/=e1w|:MB/TZ'rNv=5z*Vd9WGKՐQ2< JQBdÌ%9Š/:f d#%ύMVyƗC}ܖx|=MfT1(!*}OrpuYQ%9Z14sQ\w9Lyx2roawx~\F d!/hy:܁o8V`I^0&N[-VB5+ +,DNڒ@S ˎ%sN Xr7f##GבZ/JUm?+1){H‰MacVq v¼ޓ%VC.cw60@:d̦InKz _!U Y:8$E+4dkmlCSXh28L- k4ecdFY+B.~H 9i:{ GNX qӢ"K=& )z c'`TD;XvvG' _ v#;O@mΟrTQŶhpispγ0+oGUd;86ˌ| rWAM'f%(_( jRa;tpa&V^,?qmduOiSWw4`yyvVg+߫Z"xWK 6g6@'j#t~oq&wJ ~xL>D$U+>wku$2H-#ԭщ0xyٚa7_0uOD}$*0T i=czIrűY4XEoǨb##[4AmLF&M3bd5܉4N!WePɻ 9ŎNJ5脈徟M!:'DSjr8 q WQQ˨! "\vz)遐DKD'Rag_4_1  Ꝏ|L$EqWgK R틋\vp'sL4 ^l?[C9`MYjQvsk ?3Y!;يi*Y`wZOṯٰop-nםZ3Sqf2nǢoNgˆ 0r/o*<" j[l4fV ^Vnu259ӹij4<=\YMR:+z)]xqWXaYI"o4~:|HKf=^]ݩT2:-R^tH0zZΝn=] h_?zUu(u,&:4zuyb߭0h-@J^Th`fGMrL5Vḟ3n~V2.(}E$Ëyr:R_-i8ԭyp!^F @Hߥ s~R~"dVb+ odч:/er^~"ڃBtv~ݏv]a-ai1N#CV uUv-IXVu ürT:?j2~_Q/'BΛQ0&P^Иfbif]3ř'(oooΫwr [oo?-vgCpeeN"yZNaK`nbl:ۯoo7D_7|7|7"yyyyyyyyyyyyPC2H& ,j0dc٦ 패 ,[u|7|>L<^[U`o7|7|7)a%}JNx,_oOr6 QP<<*w8a8Ƣ+]¶oo=Ap6i`6 al6mpGrXtf=p;al6 aJ^7SG2l HY[6Y MYtE9!vVTwS ¥*n{=UHa'SI-AmY5Rh5"n4U LPX-LqpKNS:Ѭˁ-#@w{>MnZBWM#./S^wy2 V5U 3n3cJ^JZW==Z+0x bkN¨xj ɦq8SrkS/j 4G]=7-g/q 9{0pgmodeler-0.9.2/main/res/windows_ico.ico000066400000000000000000012615361360462764600202710ustar00rootroot00000000000000 ( V (~ 00 %(  NN h^(     """""""""""""""""""""""""""""""""""""""""""""""""""!  $+2579:::::::::::::::::::::::::::::::::::::::::::::::::9864.%  (6BKRTUWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWUSNG<0#  &8JZfnsuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvutpj_RA1$ /F\pxhTA2'! ! E>3- )> U o zeRD94201222222222222222222222222222210.*$ Aa}tcVMKJKMMNNNNNNNNNNNNNNNNNNNNNNNNNNNLJGA9/# 8B7ר2ͦ1Ԣ0۟/ᝉ/盇.왆.--.................-,,..--,,,,+,,,,+,,,---.-,---....7nc(riedfhklllllllllllllllllllllllllllllid\PA0! 8:g|z{|}~~~~~~}}||{zyxwvvuuuuvwwxzz{|}}~~~{`q*yy}vgS>* 86|q`dcccccccccccccccccccccbabbѿaν`̼_ʹ^ƶ\ô[ZYXXXXXWXYY²Zĵ[ȷ]ʹ^̼_Ͼ`aaaabadxisd# zcI187w_@ABBBBBBBCCBBBBCCCCCCBBBBAA@>=<:8767555566788:<=>>@BBBA?íKkfuf$nR7 87wdD5,,,,++,++,,+++***))((()'&&%#!!}zwtrrqqqrtwz} !"###"):ðPnfo` jii[[]]^`^^a^_a]^`\\_[[]ZZ\ZZ\YZ\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\YY\WWZddfEEGtW:#87wcE0#""!!!! ! |vqm|iygweudtcuducveyg}jnqv{7Omgl]'ɚ^_axZ=$ 87wcE0%%%########!!"!"|umygrbm]jZhYfWeWeVeWfWgYhZk\o`tdzhmsy8Nlgl^"ȖSSUyZ=% 87wcE0%$$$$#$$#""#!!! v~lvfvep`i[eWcUaR^Q \N \O XL WK YN \P _Q bTfWk[qaxgls{4Lkek^"ʗUUWz\>% 87wcE1%$$$$$$#"#"#""!! |soryiNDI?F< C9 B8 @8 A8 D<B:ZM aT YL SG UH XK \N _Q cU j[qaxfnv}2Ih˿dk\"ʗUUWz\>% 87wcE1&%$$$$##$$"""!! !z|~l\P2+ 1+        &" &! ;3 SG WJ SG RF VI [N _Q dV k[ sb{jr{0GŹeƺci[!ʕUUWz\>% 87wcE1%%&%%%#$$#""#"!! ~~SH1+         ! 6. LB VJ SF RF WK [N _R gW o^xgp{,B`_fX!˕UUWz\>% 87wcE1%%%%%$$$####""" }m81      1* LB QE MC SG XK ]P cUl\ udp(=[ZbT!˓UUWz\>% 87wcE1&%%$%$$%$$$#!!" RI5/    D: YL QF QE VJ [N bT j[tf%|8UV]R ͒UUWz\>% 87wcE1%%&%%$$%%$$"""! C<      .' E< SG NC UI ZL `Rj]!}q3ORYNΏUUWz\>% 87wcD2'%&&%%$$%$###" A:        I> SG NB UH YMaUth/ILTHЋUUWz\>% 87wcD2'''&%%&%$$$##" ?6       I> QF OD VJZOk`+{CGNDӈUUWz\>% 87wcD2&&'&&&&&$$$#" :2   2'6+1'.+2   G= RF NDUKdZ){s?BH>ՄUUWz\>% 87wcD3'''&&%%%%$##!!OF      ;/!tG~RqCzldSF7+ ,#&$)      E< TH PF_U&sl;w>C:~UUWz\>% 87wcD3(''&&&&$$$$#!\P    *'*vbPUxKwHxKv@~H]vJpc;/$    PEPGZQ$mg7yq;@7{z{UUWz\>% 87wcD3((''&&&&%$#!"pb      %#&zg~GuJxKyLxKxMuJsFwIv@Tf?M>.'!      *%VMUM#hb5sl7=4 vvwUUWz\>% 87wcD3((('''%%%%#"s"   "t`w?yMzMyLyMyLxLxKzKxJxLsGxILsNF9*    G@VM"d^4ng5:2 rqsUUWz\>% 87wcD3(((''''%%##"H>  kW{E{PzNzN{LzLzMzLyLyKyKyKxJwJuJtGNkR-'#  0+\S#aZ2kc470 oopUUWz\>% 87wcD2)(((('&'&$#o` t_OJzP{O|O{N{NzM{M{LzMyLyLyLxLyKxKxJsIvCyLH;.  TL"aZ2ha36. mmnUUWz\>% y17wcD3()())'&&%©&zk   =4+WwO|P{P{O|O{O|NzN{NzLzLzMyLzMxLxLxKyKwKrE\N?0 62f`3f_25. llmUUWz\>% nc' 7wcD3(())(&&&$%^T 0' dxM~Q}Q|P|Q|P{O|P|NzO{M{M{M{MzLzMzMyKxLyJxKuE~OB6+ '#oh6c]15. kklUUWz\>% KB6wcD3))((''&&Ī'vg  +%"zP{O}R}Q~P~P}Q}P|P|O{P|N|N|OzMzM{LzMzLyLyMyLxKxLwA}j0-1  $"g`4e^25. kjkUUWz\>%  /*6wcD3)**(((&%'dV sc[S~S~RR~R}R~P}P|P}Q}P{P{P|O|N{N{N{M{M{MzLzMyMyLuIQE7%  =:&mf43, kklUUWz\>%  !!"""""""""""""""""""""""""""" ( 5xcD4)**((('ȭ'h[ 1+$]|SS~TS~SS}Q}Q~Q}Q~P}P}P|P{O|O|N{N{NzM{MzLzMyMxMyGq`-*/   A?'mg55. mmnUUWz\>%  (0579::::::::::::::::::::::::::::9>$5xcD4*)))(('è*cW)'*}MVUUT~TSRR~S~R}Q~Q}P}P|P|P|O{P{N|NzN{MzM{LzMwI\B7-  C?(ph55. oopUUWz\>%  #/=HOTVWXXXXXXXXXXXXXXXXXXXXXXXXXXWW ZA4ycD4***(('ɯ(\Q 5+ X~UVUTUTU~T~SS~S~R~R}Q}Q}Q}Q}Q|P|P{O|O{O{NzNyMyKPB4$  DA)tl780 rqsUUWz\>%  /BSakqtvvvvvvvvvvvvvvvvvvvvvvvvvvvvu wb3zcD4++*))(ĩ(aT 81-{|QXVVVUUTUUT~TT~R~R~R~R}Q~Q}P}Q}Q|P{O|O|N{OwGhD:4  GD*zr:;3 vvwUUWz\>%  &;Qgy~3{cD4+++)(($;6 QD7ZVXWWWVUUUTTUT~T~SR~R~R}Q~R~Q}P}Q|P|P|PzOOp\L   KH-x>?7zz{UUWz\>%  +D^w2{cD5++**(ʯ*]Q<55~PZYXXWWVWUVVTTUTT~TSR~R}R}Q~P}Q}Q|QxJe>5- NL0CD:րUUWz\>%  +Gc2|cD5++**)(UKPB7^XZYXYXXXWWVVVUUUTTT~S~SS~R~Q~P~QyM[PA5    30JDMBӅUUWz\>% O5-$gE.W-V-V-U-U-V-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-U-V)nI/|cD5,*+)д,VM /+,oVZYZZXXYXXWXXVVVUUUUSUT~SS}RzKp70) 72PKSHъUUWzZ=% P5A,'nI-V9n>y=w>w>w>w>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>x>w9m+rK/}cD5,*+*г,UL PC9cY[[Z[YZXXYYXWWWVUUVTUUV~T{SVdSD  aW*SRXMΎUUWxZ=% O5D-'oJ-U:su)~SGxXːSUŠUĊTĊSÊSÊTÊTŠTŠSÊTÊTĊSÊTŠTŠTÊT‰TŠTÊTÊTÊTŠUĊTÊSÊTÊTÊTĊRŊ6b3b:r9m*rK/}cD5-,,)>8  2-+}e^__`__]]]\\\][\[[ZZYXbMA:    WK 4Jjdk\"˗[[]xgUE:41/0111111111111111111111111111110.+'! O5D-'oJ-U:q>v)~RHy[˒U‹WČWČWċVČVČVËVÌVċVċVċWČWČWČVċWċWČWÌVÌVČVČWČXČVċWČVċWČU‹Sĉ6b3b:r9m*rK/}cD5,,,)D< D9-şr]a`a``__^^]]]]\\\[[ZZS 4.pal!5Lkek\"̗[[]yk]QJHHIJKLLLLLLLLLLLLLLLLLLLLLLLLLLLLJHD=4) O5D-'oJ-U:q>v)}QK{_̕YĎZƏZŎZŎZŏZŏZŎZƎZŎZŎZƎZŎ[ƏZŏZŎZŎZŏZƎZŏZŎZŎZŏZŎZƎZŎZŏXĎUËRĉ6b3b:r9m*rK/}cD5-,Է/bW$  \M?k^```a````_^]]]\\]\[[Vxr  71i[xgo{ 5Kjej["Η[[]sha^_cghkjkkkkkkkkkkkkkkkkkkkkkkkkkkkie_UI8(O5D-'oJ-U:q>v(}QM|cΖ]Ə]ǐ^Ǒ^Ǒ]ǐ^Ɛ^Ɛ]ǒ^ǒ]Ǒ]Ǒ^ǐ]ǐ]ǐ]Ɛ^Ɛ^Ɛ^Ǒ^Ǒ^Ƒ^ǐ^ǐ^ǐ^ǐ^Ǒ\ŏXŌUËSĊ6b3b:r9m*rK/}cD6.,۾1KD#"*yf[baabaa`aa``_^^_]]]]]\ZbWX  6/]PeVl\{jw4Ji̿ei[ ДXXZ~uprw|zn]H3  O5D-'oJ-U:q>v(|QP~fК`ƒaȓaǔaǔaȓbȓbɔaɔaǓaȔbɔaǓaǓaȓaȓaɓbȓbɔbɔaɓaȓaȓaȓaȓ`ƒ[ŐXČVċSĊ6b3b:r9m*rK/}cD6-,پ1QI.*'rWebbacbb`aa```^^_^^\][^RGD82THXL\OhYtdp{2FǻeȻcgY(ԙhgh                                        nV=& O5D-'oJ-U:q>v&|QRjѝcǕeɖeɕdɕdʖdɖdɖeʕeɕdȕdɕeȕfȕdɕdɖdɖdɖeɖeɕdɖdɕdɖeɕcɔ`ǒ\ŏXčUËSŊ6b3b:r9m*rK/}cD7/-ٽ1QI0)"qQhcbbbcbaa`a``^^^^^\]][aVX  =4VJRGYLaSl]yhr~.B`^j^ &  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!&{`D+ O5D-'oJ-U:q>v&|PTnҠgȖhʗhɘhɘhʗhʗhɗhɗhʘhɘhʗh˘iʘhʘgʗhʗhʗgɗhɘgʘhʗhʘgɖcȔ_ǒ\ŏYčVËSĊ6b3b:r9m*rK/}cD7/,۾1RH 3,&wXgddcbdcbbaa`aaa_^_^^]\pX!?7[MNCUJ[NdUo^whs)>[Tt(dXgZj\j\l^m^n_n_o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`o`m^zl!SK.:9*s-w-w-v,u+r+p)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o)o(m2z$OmeG- O5D-'oJ-U:q>v&|PWrӡjəl˚l˚k˚l˚l˚k̚l̚l˚l˚l˚l˚k˚l˚k̚l̚l˚k̙l˚k˚l˚j˙gʗcȔ_Ǒ\ŐXčU‹SĊ6b3b:r9m*rK/}cD7/-۾2RI  60)}_ecdedddcccbaa`aaa``_^\f D;UJ QEWJ\OdVl^vh&|7UaT]÷aȻb̿dfgggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhk]v/BX_l0u iJ/O5D-'oJ-U:q?v%|OZvդl˚o͝o̝o͝o͜n̝n̝o˜o̝o͝p͝o̜n͜o͝o͝o͜o̜p̜o͝p̝m̛j˙gʗdȔ`ƒ\ŏXčUËSĉ6b3b:r9m*rK/}cD7/-ٽ2SJ1+#vTideeeddddcccbaa``a``_^dD?A $ MBRFQFVK\ObUj]#|p1CTW\aƺe˿hjkmmmnnnnnnnnnnnnnnnnnnnnnnnnnnnoj|pyk%TINCSHXL^QdWm^wgox*Fmtxk$=TlfJlfgffggffgfgfffgffgfggfgec`][YSQk'm jL1O5D-'oJ-U:q@wyKsٴ۷۷۷ڷڷ۷۷ڷڶٴر֮խӪ~ҧ{ҥwУtϡqΞn̜j˚gʗcȔ_ǒ\ŐYčUÊRĊ6b3b:r9m*rK/}cD833210ϵ2sf&822oilmlkkjjjhhhhhggffeeedddfX{n^Q  @8 TISGRFWK[ObUk\uemv,Fmtxk$=TlfJphiiijjjiiiiiiiijiiiiiihec`]ZYSQk'm jL1O5D-'oJ-U:q@wyKuڸܹܸܹܹܹܺܺڸڶٳرׯլԪ~ӧ{ѥxУtϡq͞n̜j˚gʗcȕ`ǒ\ƏXČUËSĉ6b3b:r9m*rK/}cD8232220/PF" ^SQximlllklkjjiihhhgggffeedcgXxl[$"$ =5G=THRFTJZMaSh[qb|ju~,Fmtxk$=TlfKskllllllllllllllllllllkhfc`][YSQj'm jL1O5D-'oJ-U:q@xyKwڹݼܼܻݻݼݼݺܸ۵ٳر֮լԩӨ{ѦxѤtϠqΞn͜j˙gɗcɔ`ǒ\ƐXŎUËRĉ6b3b:r9m*rK/}cC9222211Թ4sf& " tbtkmmllllkljjihihghgffedeef]g|b5/-  # KAPEQFSIYL_RfXpazjt~+Fmtxk$=TlfJvnnnoonnnoooooononoonmkhec`][YSQk'm jL1O5D-'oJ-U:qAxyJzܼ߾޾޿߿޽޽ݻ۸ڶٳر֮լԪ~ҧ{ѥwУuϡq͞m̜j˙gʗcȕ`ǒ\ŐXčUËSĉ6b3b:r9m*rK/}cC9©3©32222Ŭ2,94   inlmmmlmkljjiiiihhhggffeddfbgwTB82 :3SGOERGXL^QeVo_zis|+Fmtxk$=TleKypqqqqqqrqrrrrrqqqrqonjhec`]ZXSQk'm jL1O5D-'oJ-U:qAxxJ}ݿ߿ݽݻܸڵٳױ֮լԩҧ{ѤwѣtϡqΟn͜j˚gʗdȕ_ǒ\ƏXčUËRĊ6b3b:r9m*rK/}cD8ª3©233221պ4+ '#%xnmmmlmlllkjjiihhhhhggfedeecemgYR   @8SHSGRFWJ\PdWn^yhr{,Fmtxk$=TleL}suttutttttuuuuttttsqnkhec`^[XSQk'm jL1O5D-'oJ-U:qAxxI޿޽޻ܹڶٳױ֮լԩ~ҧ{Ѥwѣtϡp͟m̜j˙gʗcɔ`ƒ\ŏXčUËRÉ6b3b:r9m+qJ/}cC9333©223«206w)" #_UWponnmllmmklkkjjiihihggffeeeeYƥsf C:C:RGQFVK\OdUn^xfq},Fmtxk$=TleLuwwxwwwwwwwwxwwxxvsqnkhec`][YRQk'm jL19'1%iH,U:qAxxI޿޽ݻܸڶٴر׮լө~Ҧ{ѥxѤtϠq͞n͜j˙gɗdȔ`ƒ\ŏXčUċSĊ6b3b:r9m+qJ/|cC9ª3©433ª2©332Ŭ2,3. tcLrmonnmmmmmllkjijihighggfeede]iyZ)%' F= RFQFVJ\OdUl]whq|,Fmtxk$=TleMxyyyzyyzyyyzyyyyxvsqnkgdba^ZYSQk'm jL1* #dD,U:qAxxH޽ݻܹڶٴױ֮Ԭө~ҧ{ѥxѤtϡqΞl̛j˚gʗcɔ_ǒ\ƏXčVÌSĉ6b3b:r9m+rK/|cC:ª43ª3©43ª2¨3226+kXvloomnnmllmkkjijihhihhgfeededdiKCEG>RFQFVJ[ObVl\wfrz,Fmtxk$=TleMz{{{|{{}{{{|{|{zxvsqnkhec`]ZXSQk'm jL1  ![<",T:qAxxHã޿ݼݻܹڶٳױ֯լԪ~ҧ{ѥxУuϡqΞl͜j̙gɗcȕ`ǒ\ŐXĎUËRĊ6b3b:r9m+sK/|cC9ª543ª3©2232ª31ֺ3w*~mwooonmnlllmlkjijihhhhhgfefeddehdSB  I> RGQFUJ[ObUk\ufpz,Fmtxk$=TldM|~~~}{yvspnjhec`][YRQk'm jL1  H0),~T:rAxxHŦ߿߽ݺܸ۵ڳر׮֬ԩ|ӥzҤuУrΟmΝk̛h˘dɖ`ȓ]ǐZŎVČTŋ6b3b:r9m,tL0|cC95©54444ª2¨232ɯ2-<7 spqoonmmmlmlkkkjihiihhhfffedearxdT J? QGQFVI[NbTl]uep|!,Fmtxk$=TldM~{xurqnkgdc`]ZXSQk'm jL1  !!!!!!!!!!!!!!!!!!!!!!!!!!!!""7&6,}S:rAxxHܾ۽ۺڷٶشֲկӬҪҨ~Хzϣx͠u̞q˞nɛkəgǗdǔaŒ]ÏZÍVSQ5a3b:r9m,tM0|cC9ª544ª4ª4433ª2¨22ж4/94rrpqoponnmmlmmlkjjiiiiigggffde`om%"&LA QFRFUIYMbTk]wfq} -Fmtxk$=TldN|{xuspnjgfc`][YSQk'm jL1 $,1588:::::::::::::::::::::::::::9:9)I+{R;r>u(TPse]]\[Y~X}V}V{UzS{RxQxPxNvMuLuKtIsHrFqFpDoCoAn@m?l=k7ODRFUIZNaUl^yhs~ -Fmtxk$=TlcO|zwuspnkhec`]ZXSQk'm jL1 &8IYfnruuuuuuuuuuuuuuuuuuuuuuuuuuuuuur z*wOBI>QFQFWK]QgYrcny -Fmtxk$=TlcP~|xusqmjhdb`][YSQk'm jL1$<Xt1|cC;ê7ê7«6ª6ª6ª55«5©44ª4©44©422̲4-oussqrppqoponnmlmmllljiihhhhgfgeecfaX]G> QGSGXL_RhZtdp| !-Fmtxk$=TlbQ~{yvspnjhec`]ZXSQk'm jL1.-43321010101010000/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0//.65 " 8ﴡ@======================================?7zdC;«7ë6«66ª5ª5ê6ë644©54©3©33©32˲3-wusrrqqppqqnonmmmmkkkjjihihhgggfdcjvls  G=RGSHXL`Sl\wfs!-Entxk$=TlbQ~|xuspnkhec`]ZYSQk'm jK0,,'&gf{y|z|z|{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{{yA@:o}yzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzxۆ`D;ë6ê7«666ª555©5«4«4©33ª4©34©30̲:F KBCsusssqpqpppoonmmlmmkkkjhhiihhgffdfghK  G>QGPDUIZMcUn_{jw -Emtxk$=TlbQ~|xtrpnjhec`]ZYSQk'm iJ/,,#"vtmkRPZXYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWNLDC8ykϽ[^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ѿ_лVF:ª8«8«6ª7«7ê6ª66ª4ª4ª5©54ª4ª44ª330̳78! lXrtssrqqqqppooonmmlllkkjjhhihhfffeee~iO E<RGQEVJ\OfXsbny!-Emtxk$=TlbQ|zxvspmjhfc`][YSQk'n gJ/ ,,#"xvb_76;:;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9;9:8EC7ycFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGC;«7ë7ª7«6ª7ª7«6«55«6ª55ª45ª4©332213r,  ytttsrrqqpqqoonnmlmkkkjiihhihggeedgshm  @8RHRFWK_Rj\vfr~ -Dmtxk$=TlaR~|yvsqnkhec`]ZXSQj(o dG- ,,#"wvca1098@=>=?=?=><>=><>=>=>=?=>=>=>=>=>=>=>=>=>4397EC7ydA@BAAA@@@@AA@@@????????>>>>>>>>=====>>=<==:ë8«7«7ê7«7ê6ª67«75ª5«6ª4ª44432310/@;"[OLouutstsrqqqqponnnnmmlljjkjihhhggefdf^UY J@RGSGYNbUn^zjv,Dltyk%=TlaR~{wuspnkhec`]ZYSQk(q z_C+ ,,#"wvca0/B@NKLJLJLJLJLJLJLJLJLJLJLJLJLJLILJLJLJLJLJLJLJLILJLJLJLJLJLILJOL5496EC7ydA@ǰBŮBįAůAŮBĮAĮ@Į@í@í@ĭ?ĭ?ĭ>Į?í?Į?Ĭ?î=í>Ĭ>î=ĭ=ì<ì<ì<ë<ì;ì;ë;ì;¬;ì;«:¬:¬99¬9«:«9ì9ë9«8ë8ë8ë7ê7ê6ë6«6«6ª6ª6ª6ª5ª5433421..+|stuussrrqpqqqooommmmlkkjjiiihhgfeddMFI61MCRFVI[OeXrcnz,Cmsxj$Į>ŭ?Ů>Į=ĭ>ĭ>Ĭ=ĭ=ĭ<Į<í<Ĭ;í<ì;Ĭ;ì:í;Ĭ:ë:ì:Ĭ:Ĭ9ī8ë9¬8ë9¬8ë7ë8ë7«7ª7ª7ª7«6«6ª654©44410/-+'ND!gYOuwuttutsrrrpqqpppnnmlllllkjihihggfedc825 @8RGQEXL_Ri[vfr,Clrwj#( ,,#"wvca/.FDUSTRSQSQSQSQSRSRSQTQTQTQSQTRSRSQSRSQTQSQTQSQSQSQSQSRSQSQTRPNPM5496EC7ydAAȲCưBƯAƯBƯBưAưAƯAŮAŮ@Ư@Ů@ů@ů@Ů?Ů?Ů@ŭ>Ů?Ů=Ů=ĭ>ĭ=ŭ=Į=ĭ<ì=Ĭ=ĭ<Ĭ<ĭ<í;Ĭ;ĭ;ī:ì:ì9¬:¬9ì8Ĭ9ë9ì8«8«7ë7ë7ª7«7«7ª7«6«6ª4454320-*(}$JC@83pxwvututtsrrqpqqqponmmlllkkjjhhhhgfeeg F=VKRGZNcVn^|kx+Bksxj$;RliM\XXXXXXWWWWVVVUUUUUTTTSSSSSRRRQSm*u mW?* ,,#"wvca/.HFYWWTWUWUWTWUWUWTWUWUWUXUWUWUWVWUWVXTXUWUXUWUWTWUWUXTWUWUTQQOPN5496EC7ydAAɱDƯCưCůCůAƯBƯBůAįAƮAƯ@ů@Ʈ@ů?į@Į?Ů>ů?ĭ?Į?Ů?ĭ=ĭ>Į=ŭ<Ĭ=ŭ<Į<ì;ĭ<ĭ<ì;ĭ:ĭ:Ĭ;í:ì:Ĭ9ì:ì:ë9ī8ë9ì8ë8ì7«8ª7ê6ª7ë6ª65554310.+)%F?! 0,1rzwvuututtsrsrppqqponnmnmjihhffgfffgfi|k  %!H>RGVJ^QhYudp}*@jrxi$;Rlmtpppppppqqqqqqqqqqrrrrrrrrrrrssssv*u qZC,,,#"wvda.-JH]ZZY[XZX[X[XZXZX[X[X[X[Y[X[XZX[YZX[YZYZYZYZX[XZX[XZXZYWUTQQNPN5496EC7ydAAȲDƯCưBůBŰCůBƮAŮBůAƯBŮAů@ŮAŮ@Ư?Ʈ@ů?į>ů?ŭ?Ů>Ů>Ů=ĭ>Į>Į<Ů=Į=ĭ<ĭ=í<ĭ<ì:ì<ĭ;Ĭ;ī:Ĭ9ì:ī9ì:¬:«8ë8ë8ì8ì8ª8«7ë7ª76655310-*){$!! 93-r|xwvvuuttttrrqqppqpnkkhgqutssrrqojddcnaQ> A9VK QFYMaUm]ziw(>irwi$8Ni(o zbI2,,#"wvda.-LK`^]\^[^[]\]\^[^[]\][^\^\]]^\^[][^[]\^\]\^\^[][^[^\^\[XWTTQQNPN5496EC7yd@BȳDƯBưCƯCưBưBƯBƯAƯBůBůAůAůAŮ@Ư@Į@ů?Ů>ů?ŭ>ĭ>Ů>Į?Į=ŭ=Į>Į=í=ĭ=í<ĭ<ĭ<Ĭ;Ĭ<ĭ;Ĭ;ì;ë:ī:Ĭ9ì9Ĭ:ī9ë9¬8ë9«8¬7ì8«76ª655321.+({$&$j]Wyzyxxvvuuuttsstrqpnlpyâu£gYO;2*>6.=4,<5-;3,<4,<3*NC:qaVspnbaNGM$"LBTHUI\OfWscq~&=iqwi$&H[bmnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmme: jO5 ,,#"wvda.-NLcaa_a_a_a_b_b_a_a_a_b_a`a`b_a_a_a`a_a_a`a_a_a_b_a`_\[XXUTQPOPM5496EC7yd@BɳEưCưCưCǰBƯBůBŰBưBƮAŮAƯAŮAį@Ů@ů@Į@Ʈ?Ʈ?Į?ĭ?Ů>ŭ>Ů?Į>ŭ=ĭ<ĭ<ĭ=ĭ<Į=ŭ<Ĭ;ĭ;í;ĭ;ĭ:ĭ;ì;Ĭ:ë:ë9í9ì9«8¬9ī9ī8¬87764520.+(x$)&! (" t|yyxxwvvuuttutsrnrʨzåzib>4)E=3<5/2/3    !92+A8/E:-jgm%!G=TIWLaTm^zix%<˽gqwg# )K@"B"C"C"D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D"C'J-qT9" ,,#"wvdb-,POheecececececececdcdcececececdcececebebececdcecebb`^\ZYWUSQQNPN5496EC7ydAADzDůDưDưBưBƯCƯBƯBŰBŰBƮBƮAůAůAů@ů@ůAį?Ů?Ů?Ů?ĭ?Ů>ŭ>Ů>ĭ=Ů<Ů=Ů=Į=ĭ=ĭ<ĭ<Į<Ĭ<í;ĭ;Ĭ;ĭ;Ĭ;¬:ì:Ĭ:ì9ì:«9ë8«88876530.+(u%(&! "!"j~zyxxxxwwvvuuuuqqɪygF<0B;7##'    0*'z^bn[ ?8XLTG\OfXsdr{%:Ȼehx$bW"jZeO hShRiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSiSgQt]L>wX<% ,,#"wvdb-,QPjihgififhfhfigifhfhghghgighghghfifhfhfifighghfecb`^\[YWUSRPOPM5496EC7yd@BȲEưCưCưCůBƯBưCŰCƮBƯBŰBƯBƯ@ů@ƯAŮ@ů@Ů@į@Ů?Ů@Ů?Į?Į?ĭ>ŭ>Ů?Į=î>ĭ<ĭ=ĭ=ĭ<ĭ<ĭ<Ĭ;Ĭ;ĭ;Ĭ;í:ì:Ĭ:ì:ì:ì9ì9«9«7ª875531.+)|m$('"! JB;zi|{zyyyxxxwwvvtpyjLB<*''  )%"qsJDG)$K@SHWL`Um^}kv#8`uUƹ_Ǻ_ǽbɽbɽbɽbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȼbȽc̼Y}p,z[<% ,,#"wvdb-+TRnmkjljljlililjljljljlkljliljljljljljljljmikjigecb`^\[YWUSQQNPM5496EC7yd@CȱEƯDǰDưDƯCưBưCƯCưBƯBƯBƯAƯAů@ƯAŮAŮ@ů@Ʈ?Ů@Ů@Ů?Ů?Ů?Ů?Ů?ĭ>Ů=ĭ=Ů<ĭ=ĭ=ĭ=ĭ=ĭ<ĭ<í;í:ĭ<Ĭ;Ĭ;Ĭ:ì:ì:ì9«8«8«876641/+z'MD".+ "! " !%se\tƩ{{|{|{yyxyxxwrzuYOK(%' dWQbn >7WKTH\PgYweo 7SȾlimmnopppppppppppppppppppppppppppppppppql|mzj%{\>% ,,#"wvdb,+UUrpomomomomononomononomomolonononomononompmmkigecb`^][YWUTQPNQM5496EC7yd@BȲFƯDǰCƱCƱDưDưBưBƯBƯCưBůAůBƯBƯAůAŮ@ƯAƯ@Ư@Ů@Ů?Ů?Į?Į?Ů?Į?ŭ>ĭ>Į=ĭ=ĭ=ĭ<ĭ=ŭ<ì;Ĭ<ĭ;í;í;Ĭ;ĭ:Ĭ;ì;ë9«8997752/,}'HA# #"   "!! >82~j§|}|}{{zzzyyyztʪoA;<  #!$bjcSG/+OESHYMbUp`yj~8DKO°QŲRƳSǴSȵTȵTȵTȵTȵTȵTȵTȵUȵUȵUȵUȵUȵUȵUȵUȵTȵTȵTȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUȵUDzOrsxh"|]?% ,,#"wvdb,+WVutrqrprprqrqrqrqrqrqrqrprqrqrqrqrprqrqrqpmljigecb`^\[YWUTQQNPM5496EC7yd@CɳEǰDǰCǰDǰEŰCŰCǰCǯCƯCưCưCƯBŰBƮBůAưAƮ@ŮAƮAů@ů@Ů@Ů?Ů@Ů?ĭ>Į>Į>ŭ>Į=ĭ=Į<ĭ=Į=í<Ĭ;Ĭ;Ĭ;í;ĭ;ì;Ĭ;ë:ë9«998653/,)G@" ! "!     !  g[Vnɭ}~~~}|}|||{zyyvȩqZ)%'   //0./0)())()++,-,,efr =5VJUJ]Qj\ugt036:<===>>>>>>>>=>>>>>>>>>===============?Bnsxh"{]?% ,,#"wvdb,*ZXyxvtvtvtvtvtvuvuvsvtvuutvtvtvtvtvtvtvusqpnmkhgecb`^\[XXUTQQNPN5496EC7yd@CȲEưDƱEǰDǰDưCưCƯDưCưCƯBƯCưCŰBůBƮBƯAŮ@ůAŮAƯAů?ƯAŮ?Ů?į?Ʈ?Ů?ŭ>ŭ>ĭ>Ů=Ů>ĭ=ĭ=ŭ<Į<¬<í=Ĭ<í;í;Ĭ;ë:«::8852/,|n'1."" !!!! !  !    #!!#yc¨~|}}|||{zx£}xb !   &&&abbfkesl#"# 4.UHRH[OeXqcp~ $''()()))))))'((''(''&&&&&&%%%%%%$%$#%0Gorxh"{]?% ,,#"wvdb+*\[}{yxyxyxyxzxzxyxyxyxzxywywzxzxzxyxzwvurqpnmkhgecb`^\ZXXUTRQNPN5496EC7yd@CɳGưEƱEǰEưDƱDƱEŰEŰDưCƯBǰCưBƯBůAƯBůAƯBƮBƯ@Ư@Ů?ƯAƯ?Ů@Į@ů@į?Į?Ů?ĭ?Ů?Ů=ĭ>ĭ=ĭ<ĭ=ĭ=ĭ=í;ì<ĭ;ì;«:::8530-q)%$! $"! !   ! !   !835}gֹ~~}|}}|zvC7VKWK`Sm^}kz ! *Hnsxh"{]?% ,,#"wveb+*^]}{}{}{}|~|~|}|}|}|}|}{}||||{}{}|zxussrpnliifedb`_\ZYWTTRQNPM5496EC7yd@DʳFưEDZFƱEDZDDZEƱDDZDƯCůCưDƯBůBǰBƯAƯCŰAƯBƯBƮ@Ʈ@ůAŮ@ƯAŮ?Į@Ů@Į>į?Ů?Į?ŭ>Ů=Ů=î>ŭ>ĭ<ĭ<ī<ì=ŭ<Ĭ;«:«:97740/v*+)"!('"!!!!!! !  !#!" !cYRqͰ~}}}||{Ǧ|h[T%"#" jjj%$% fXUhihbsU$" 5/YMTH]PhZwft !"""#"#""""!!!! ! ,Hnsxh"{]?% ,,#"wveb+)`^~~~~~~~~~~}|yxvttrooljhfedb`_][YWTTQQNPN5496EC7yd@CɳFưEǰFưFDZDǰEƱDǰCưDŰDƯCůDǯCǰBƯBưCưCůAŰAƯAŮAůBƮ@į@ů?ůAƮ@Ů?Į@Ů>Ů?Ů>ŭ>Į=Į>ŭ>Į<î=í<ĭ=ì<«;«::97610y,/-#!'%" !!!!!"!" !! ! !$##{j[ĩ~~||n5/& !!"(&(JIJ!mlihg̦x6.# C:VJYMdWqbp !""""""#!!!!!!  ,Hnsxh"{]?% ,,#"wvec*)ba|{zxuttqonlkhgecb`^][YWUSRQNPN5496EC7yd@CȳGưFƱEǰFǰEƱDưEưDƱEǰDƯCưDǯCŰBŰBưBƯCůAůAŮAůAưAƯAį@ů@ůAŮ?Ů@Į@Ů?ů>į?ĭ>ĭ>Ů>ĭ>ĭ=Ů<Į<ĭ<í;¬;ª;:8620z-1-#"'&"!!"!" !! "!!! !"!"#"!!ylZҴ~~~{sc/+,-,.[[\ {mliiihhcuk! " 1,ZNUI`Sn^~l{!!"#""""##!!!!! !  ,Hnsxh"{]?% ,,#"wvec*)dc}{yxwtsqomljigecb`^\[XWTSRQOQM5496EC7yd@DȳGưFDZEDzEƱEǰEDZDưDDZEǰEưDưCƯCưDƯCưBƯBƯCƯCůBưBưAůAƮBů@Ʈ@ů?ŭ?Ů?Ů@ů@Į?ĭ>ŭ>ŭ>Į=Ů>ŭ=ĭ=í<ì<«;;9622z//-$"'&$ """"#"!#!!"! !!!!"!# 405veֻ~~|̭fZR ! "[[[  -)&oiiiib˪@:8 4.WKTI]Qi[yhv!##""##"#""!! ! ! ,Hnsxh"{]?% ,,#"wvec*(ee||zxvtsqpnlkigecb`_]ZXWTTQPNQN5496EC7yd@DʳGDZFưGƱFDZEǰEDZFǰEưDưDǰEƱDưCŰDǯCǰCưBůCŰCưBưBůBƯBƮBƮAƮ@Ư@Ʈ@Ů?Ů?Ů@Ů?ŭ>Į>ŭ>Ů>Ů>Ů>í<í<¬<;:843v0.,%"('#! """#!""!!""!"! "#"# !!"GAExеzշJA7  324^^^!!"!ghlljiii`n^U!$ F=VJZNeYsdr "##"##$""""!"! ! ,Gosxh"{]?% ,,#"wvec)(hg}|yxvttqomljhgecb`_\ZYWUSRPMPM5496EC7yd@DʳHDZFƱGDZGƱEƱEǰFưFDZDDZDưDưEưDŰDưDǰCƯDưBưBŰCƯBưAƯBƯAŮBů@Ʈ@Ư@ůAŮ@Ů?Į?Į@Ů?Ů>Ů?Į=Į=ì<¬<;:96412.&!*($"!##"#""""!"!!#!!"###!K@<˱{ָG@8 !  ``afff""$#gSpnllkkjihr0+' 71[NUKbUo`~n|"""########"""!!! ! ,Gosxh"{]?% ,,#"wvec)(ji}{yxvttqomljigecb`^\[XWUSRPNPM5496EC7yd@DɴHDZGDZFDZFDZGDZGưFưFDZFưEǰEƱDǰDưCưDƯCưDǰDƯDŰBŰBƯBŮAƯAůAƯAůAůAŮAį@Ů@ů?Ů@Ů?Į?Ů?ŭ>ì=ì==<9742KE'""#&%$#"###$""$""##"#!""$$$ RH@qɱ|ԷKC;    FFFooo#"#m_U|nmllmlkjgƢqOD:-)UIUJ^Rl]{jx !"###$"#"#""""!!! !  -Hnsxh"{]?% ,,#"wvec)'lk}|ywvusqpmljhgecb`_\ZXWUTQQNPN5496EC7yd@EʴJȲGDZGDZGDzGƲGDZEDzEƱFǰEƱEưEǰEưDưDưDǰCưDƯCưBƯCůBůBƯBƯAůAŰBŮ@Ʈ@ƯAů@ƯAį?Ů@Ů?Ů@ĭ>Ĭ=«<=;862PG) %$"%$#$##$#"##"##"$""#%$$   \QIɱ~ϲ_SKxxx$#$dVLwmnnmmmlkkjgwc'$$*%LAUJ\PhZwgu!"###$$#"##""""!!! ! ,Gosxh"{]?% ,,#"wvec('nm}{yxwtsqpmmjigecb`^][XWUTQPNPM5496EC7yd@E˳IDZGȱFȱGǰGDZFDzFDzEDzEDZFDZEDZEDZEưEƱDǰDƯDưCưBưCưCƯCƯBưBƯBƯBƮAƯAů@Ư@Ů@ů@Ů?Ů?į?Į>Ĭ>ì>=<972SK)"!%%$$%#$%"$$#%##%##$""$%$%! !ZPIìƪ~pg(&,$%$$$%]QDxoppnnmlllkjg¡{;50  D;VJYMeVrcq"####$$$##"##"""!!!  -Gosxh"{]?% ,,#"wvec(&oo}{ywwusqomljigecb`^\[YWTTRQNPM5496EC7yd@EʳIƱHȱHDZGȰGȰGDZFǰFǰGDZEưEƱEDZEǰEǰDDZEǰCǰDƱDƯCƯCưCŰCůBůAůBŮAŮAĮAĮ?ĭ?ĭ?ĭ>ĭ>í>ĭ>«?>;:75[S+%%$%%$%$$$$#$$#%$"%#"$%$% "WNGŮép402!!# hii''(ZNAǨ}nqpqopnmmllkimdVG -(]PUJbTn`~m| "##$#$$#$##"""#"!"!!! ! -Gosxh"{]?% ,,#"wvfc'&rq||yxutsrpnlkhgecb`^\[YWUSQPNPN5496EC7yd@EʴJDzHDZHDZGȲGDZGDZFDZGDZFDZEDzFDZFưEDZEDZFǰEưDƱDǰDưCưBƯBŮBĮAĮAĭBĮ@îAí@ìAì@ì?ì?ì?ë>«>=<;86084'%(&&$$%$$$##%##%##$%$&!!$ XOGư«ª©y:4.! "!"(&(XK@̫prrqpppnmllllki~b2-'-(RHUJ^Qk]zkx!"#$$$$$$$#"##"#"""!!!! -Gosxh"{]?% ,,#"wvfc'&ts|{yxwtsroolkigecb`^\[YWUTQQOPN5496EC7yd@EʳJDZIȲHDzHȲGȲGDZHDzFDZFưGƱFDZEǰEDZDDZFƱDưEůCůCůCƯBĮCíBíBíB¬A@@@?>>>?==<;:7341($*)&&#%%#%$$%%$$$$$%%%###YOHƯ쬫ªغ_UL!#"# LLL>>?TH>Ϯotsrrpqpomnmmmmgz3-( #!F=WK\Ph[xhu ##%$%%%$$$#$$""""!"!!   -Gosxh"{]?% ,,#"wvfc'%vu||yxvttqomljigecb`_][YWUTRPNPN5496EC8yd@EʵIȱHȲHDZHDZGȲHȱGȱFDZFDZGDzFDZEǰFƱEůDưEưDůCůDĭC¬BB¬B@A@@?>>>==<<;;964F@*%$%('&%$&%$%$$&$$&%#%%$&##" !$VLJʳíëë쬪©~=9<  '%'```vvv#!"G@<аouusrrpqqoonmmmliǢuKC;  C:WKZNeWtdr!#$$$$$$%%$##$#"#""!!" !!   -Gosxh"{]?% ,,#"wvfd'%ww|{yxwtsroolkigecb`^\[XWUSQPNPN5496DC8yd@FʵJȱGdzIȲHȱIDzHDzGDzHȱHȱGƲGưFǰEƯDŮEůDíC­D¬CCAA?@?==<;;::9998863GB*""&&%&&&&%%&%$&%%%%$&%$%'&& VMQ˵ììíìë«ì«©ūTLE" ""#mnm{{{&&&;65èovttussqpqpooommmmgs2/2 0*_RVKcVpbo} #$%$$%%%$$$$###"#!""" "!   -Gosxh"{]?% ,,#"wvfd&%yy|{yxwtsqpnmkhfecb`^\[XXUSRPNPM5496DC8yd@FʵKȲIȲIDZHDzHȱGȱGȲHDZGűGűFŰFįEîEíDDCBB@?>=;;9987666555332MH+##''&''&&%$&&%&&%&%$&%$%)()@;?ͶŮĮîĭíí¬ìì««è726! ""!! LKLtst %%%/*)oxvuuttsrrpqqonnmllme81) 0*YLVKaUm_}l| "#$%%%%$%%$$###""#"!"!! !  .Gosxh"{]?% ,,#"wvfd%$~|~|zxvutrqonkjhfdca`]\ZWVSQPOPN5496DC8xd@FʵJȱJDzIDzHȳIDzHưFǰFDZEưEįFíEEDCBA?>=<:976533210000~/}.|-x-96(!!'('(%&&%%'&$&%%&%%&'&'!!#"zj׿ůĮůįîĭìĬí¬ë쫪ϴfYK#"##!"'&%vaxxwvvututsrrpppponmmg?81 ?8YN^Rk]{jz "#$%%%%%%%%$$#$##"#"""" !!  .Gosxh"{]?% ,,#"wvfd&$|{|zyxvsrronkkhgeca`^][ZWVTRPOMOM5496DB!9xd@F˴KDzIȲIDZIDZGƱHƱHŰFĮFĮF¬EDCBA>=<877431~0{/y.v-u+s+r*p*p*~p)}o){l)s(*('()'('&('%'&%'&%'&%''&''''zkȨƱŰůůĮŮįîíííìì쬫ª©ͲdYS   fZVȫvyxwwwuuutsrqpqoonnmkĢtQF=A9XK\Ph[xhw"#%&%%%&%&%%$####"##""""!!!!! .Gosxh"{]?% ,,#"wvdb,+WWtsonmmkkkiihgfeddcbaa__^]\[ZZXYWWWUSSRSQPOOMNLLJIHHFFEECCAB@A@4397CB"9xd@FʴKȲJDzIDzHǰGưGįGîGECCB@><98642}0x/t,r,}n*yl)vi'tg're&pc%ob&ob$na$ma#l_#re#MG&.+''%(('''&'&&('&'&&'&&')(){mgйŰŰƯƯŰůĮŮůŮíĭì­ììì««©vIA<B:5Ħvzyxxwvvutttsrrpqpoommk{o1.35.\OYMfYuet"#%&&%&&%%%$%#$$$####""!!!! ! !.Gosxh"{]?% 21#"xvb_76988686868697979797979797979797979797:8:8:8:8:8:8:8:8:8:8:8:8;9;9;9:8DB"9xd@G˴LDzIDzHưHİGîGFDDBA?;:742{0v/p+yn+wi)sf(pc'nb&l_$i^#g\"fZ!dY cX!cX bW bW aV `U .,($$*''(('('&('&('&''&'*()VMIʵưƲƲƱůƯưưůĮĮįĭíĬí¬ëì««XNKA;6Ũw{zyyxywwvuttsrrrqpponmmfA8-1,]PWLeWscr!"$%%&&&%&%%$$$$$##"""""""!! !! !.Fosxh"{]?% 21#"vtmjRP[YZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWYWZXOMCB!8xd@FɳJDZIƱJįH­FECB@><964{1w0~q.yl+uh(pc&m`$j\$f[#dY#^S ]S!\Q![P YN XOXNXMWMTL_T'')$$**()'&)'&('&(('('&()(*!!";7:ҽıDzDZƲƲƱűŰưƯŰįĮŮĮíĬìíìëë«©ǭtgd  ICCw}|{zyyyxxwvuttssqqpqoooktC;3 /*[NWKcVpap~!$%&&&'&'%%%&%$$$#$#####!"!!!!! !.Fosxh"{]?% 21'&gezy|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z|z{y@>!8yd>FɳLįH®HHFD@><:63y1s.zn,uh)pc(k_&dZ#`V"ZP#VL"WM!SI ''+%%+%%+%%*$%+$%+$%*'&+$?;!0.('')(')'())(()'(''()()'&&*(,}ĤįȲȲdzƲDZƱDZưƯưưƯůĮůĭĮĭì­ìë묪ȭQHJ&$#'$$"!!'$%)&'fXKαy}|}|{zxxxxwvvutttrqrpqqoj}G=5 ;4\P`Sn_~m|"#%&&&'&&%&&%$$%$$$#####"#""!!!!".Fosxh"{]?% 434321100/0/0/0/0////./....-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.---54 #8xc?FDZK¬IGEB?=:75x1q.xj+qe(i^&eZ%bX#QI%%%-**,))-)(+*)+)),,+,)*+**+))******+**))(+*(+*))))*()*((*(')('((()'()''(/-- z˰®ɵɳȳdzȳDzƲƲƲƱưưƯƯưĮŮĮĮîĬ­­ì«¬«~~|}}{{zyxxxwwututssrqqoplƥyJ@4 <5[O_Rl^{kz!$%''%'''&'&%&%%%%$$##$"#""!"!! "/Fosxh"{]?%  -HeÛ5xc>EîJFDA>;75x1~p.vj+nc)pc&UM'$%.0.,++-,+,-*-++,+*,+*++),++,+*++)++),*)**)+)***)*)(+))**()))*((*('))())(((()(&)+)* "UNIкDzȳɴɴdzdzȳDzDZƱƲDZűůưŰƯįįůîĭìí­ëë«©~~|}|{zzyyywwvvttttrrqqpnsqaU $<5YM]Qk]ziy!#%''&&('''&%&$%$$%#$#$#""#"!""!"/Fosxh"{]?% B?@>⭚=骘<;;;;::::::::::::::::::::::::::::::1,^QZOj[xgw!#%''''(&&'&&&&%%%$%$$#$###""!!""/Fosxh"{]?% ($76ʼ_yrsssssssssssssssssssssssssssssssssrrpͼ^;AD@<7}4r1s+aW+1/./,/.-.----,.-,-,,.-,.,+.,,-,,-,+-,+--,--,-++-*)+))+""$ $ )%'#! !%%')(*+)+*(*))*))))'*((),*+!yneɴʷɵʶɵɴȳȳɴȲȲDzDzƲDZDzƲƱŰƯưůĮůĮîĭì­ì¬ìª©~}|}{{zzyyxwvuuutssrpqpmtJ@7 0,_QZNgZvfv $%&'''''(&''&%%%&%%%#$#$$""#""!"/Fosxh"{]?% &#61muп^dccccccccccccccccccccccccccccccbbbaν`˼`ųS<=@:6y4}p+]U+740,+0.-/-,.-,/.-.-,.-,-,,--,.,,.-+..,..-/,,,&') 502{plzͻͺͺ̹İVLO##&''(+)+*(+()))(*((),,-skκǴʵʶʶʴʴɴɴȳȲDzȲDzDZDZƲƱŰưưůŮůĮĮíĭ쬬¬ªª~}}}{|zyyyxwvutttsrrqporKA6 0,^PYNfYueu $%'(''''''&&'&&%%%$$%$#$##"##""#/Fosxh"{]?% &#60plFIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHGGFCC8:;}51nb/65/+,//..--..-/.-/.-.--.--/--/.,.--./-./-0%&)!MFIvñλλͺѽҽѾѿҾҾн̸λA<=$$&*++)(*))*)()))*+**!ϰðʶɶʶʵʵȳȳɴȳȳȳdzƱDzƲƱŰưưŰĮŮůĮíĭíìì¬ê©~}|}|{{yxyxxvvuuttsqqouMC8 1+^PYMfYtes $%''(()(('''&'&'&&%%$$$$$#$##"#$/Fosxh"{]?% &#61on?DJIIIIIIHHHHHHGHGGGGGGGFGGFFFEEEDCB@?<785xl/=:/++00./--/-.0/.0/-0/-//./.-/.-././1/1,-."#&/*,shϿ˺λѿоμμνμλλͻμѽʸҾmba(','')**+)(*)()+)+&'(-*-zŨdzʶɶɵʵɵɴȳɴȴdzȲȳDzƲƲƲűƯůưįŮůĮíĬí¬ì쬪~~}|||{zyxxwwvuttssrqnzPE: (%OF[OdWsdt $%'((((((('('&'%&%%%%$$$$#$####$/Fosxh"{]?% &#61oo=LϺYʶT˷TʶTʶU˷TʶSʶT˶TʶSʵSʵSʵRɶR˵RʵRɵRʵRɴQɵQɵQɵPɴPɴPȴPȵPɳNɳNdzMDzNűLïKJHFA=9w3UO0640-,1,,0/.0//0//0../..0/.0..//.0203+*,#"%GAB{ʷĮ«ϾноϽнмϼϼνμμͻͺλмѾ|pe.*-'&(+*+)(*)(*-,-f\\íɶʷʶɶʶɵɵɴȴɳɴɴdzȳDzƲƱDzưŰůƯƯůůĮííí¬ìëëª}~}|{{zyyywvuutttsrnäPF; :4]QcVscq $&(()'(((('''&&'''&%%%%$%%#$$###0Fosxh"{]?% &#61oo;1//4003213213212202102103103988"WRNð˶ððïï®®î­í®­ҿпѾоϿϾонϼϼϽʸĪ646"-+-.,.d[Z̷˸˸̹˷˶˷ʷ˷ʶʵʶɵʴȳɳȳDzȳdzDzDZƲưưưƯůůĮĮĭ¬ì«ì¬ª~}|}{{yyxyxwvutrxyh[&$(:3\P_Sm_}m}!$&(**)**)))((()'''''''&&%%%%$%%% 0Fosxh"{]?% &#61oo85/''2313424222213202213213213868!!%d^Z˻ͷDz¯ııűİİïïïî®­î®­¬­ѿѿоппомнϼϽ̺Ưs644+),+*++++%$)yo˰ȴ͸̸̹̹˷ʶ˷˶ʵʶɵɴɴȳȴȲDzȲDzƱDZŰƯưůŮįŮîĬí­«¬¬ª~~}||{{yyxxwvvutvtg/,02._R_Rn_~m|!%&(**)++**))))(()(((''&&&&&%%%%& 0Fosxh"{]?% &#61oo%%(.-.#$%LEHʸ͸˸˹̸̹˷˷ʶ˶ʶʵɵʵɳɳɳdzDzȳƲDZƲűưŰůůůŮíĭĬ«¬¬©~~|}z{{yyxxwvswre-+/2,aT`Toao~!$(**))+******)())(((''&&&'&&%&&% 1Fosxh"{]?% &#61ooмкıȵƳƳƴƳƳƳųƲƱűűűŰıűİðïî®®­­­­пѿϿоϿоɸ϶qf_112-,."ticδǵ̹ͺ͸̸̹˹˷˶˷˶ʶɶʶɶɴȳȳdzDzȳDzƱŲưŰƯůįįĮíĭí쬬~|}|{zzxyyxvuyna*(-1-bUaTqbq"&)*++*+,,*+**)()(()((''''&&&%&&&!1Fosxh"{]?% &#61oo:=+*+'')E@@ê˸ιͺͺ̹͹̸̸˷ʸ˶˷˶ʶʶʵɴɴȳDzDzȳDzDzƱűŰůŰůįïìí­ëë««©©}|}|{zyxxxu|weY$"'3.cVcVsds#&)+*+++,+++**)**)*)()(('((&&&&&'!1Fosxh"{]?% &#61oo7~Į̹ͻλͺ͹ͺ̺͸̸̹˷̷˷ʷʵʵʵʵɳȳɴȳDzƲƱDZƱŰƯưůůůíĭǥf\QsfYpeXj_Spǡŭ~~}}||{zyxvǨ]QD!<5_TfYwfu!%'**,+,,-,,,,+*+**)*)*()()(((&'&(#1Fosxh"{]?% &#61oo:986575476475465565466467792-2õɷ̺̺˹˹˸˸ʸʸ˸ʹʸ˸˹ʷʷɸɷȶȶɶȵȵȴǵȴǴǴƴŲųƳŲűİűŰİð®îî­¬­ѿʹ׾v!&h`^ӻȸϽϻμλͺκͺ̹͹̹̹˷˶˶ʶɶʵʶʴɴȳȳdzȲȲDzDzűƯƯƮŮį­odW,*+(&')&')'( =95xŬ~~|}|zyyuɪVLA""" <6cVi[xiy!%(),--,,,,-,++,**++****((()(('(((#2Fosxh"{]?% &#61oo;9;98668758757657657657979++.ldbѿ˺ͼͼ̻̼̼̻̼̻̺̺̺̺˹˹˹˹˸˸ʹ˸ʸʸɸɷɶȵɶɴǴȵȴǴdzƲŲųűŰűűŰİï®ïî­­ֿ̺JFD¬κϽνμϻͻͻ̺̹͹̸͹˹˸˷˷ʶɶɶʴɴɴɳȳdzDzƱDZƱưůĮɲMHA)()#$&%$&%#%$#%$$$$#%%%& !.,+ygƭ~~||{zyvŧSJ@#""     =7dXj^}l|#'*+-.-....,--,++,*++*))**)()())()$2Fosxh"{]?% &#61oo:=ͼ˻νμνͼͼͼμμͼ̼̻˻˻˺̺̻̺˹˹˹ʸ˹ʸ˹ɷɷɶɶɵȵǴȵȵǴȴƳdzƲƱűŰİıİİïî®í­¬ѿĭUMM))+}Ȱ̺нϽϽϽϻͻͺ͹͹ͺ̸̹˸˹˷ʶʷʵʶʶɴɴɴȳDzdzDzƱưưä]UN .,,%$%%%%%$&%$&%$%$#%$#$%#% "2/-wfǰ~~|||{wTI?"#"    >7fZm`n}#')+--..----,-,,++,,**+*)))**()(')$3Fosxh"{]?% &#61oo#"" !   !>8hYoaq#(+,-.-...--.-,,,+,,+*+*****)()))($3Fosxh"|]?% &#61oo̼ͼξξϾϿοϽννννͽͽννͼͼμͼ̻̻˺̺̺̺˸ʹʸ˹ʹ˷ɷɷȶɷȵȵȴǴǴdzųŲƲƱıİııį¯îíпưB=?QMGʹоонмϼμϻͼͻ͹̹̹͹̹̹˷˷ʷ˶ʵʵɵʴɴȳdzȲDzDzDzrg[)()&%'%%&%%&%%%%$&'%'!-*+lԺ«~}||{z~QI=#"#  !  !*'QFfXrcs %)*-...//..-.--,,,,,++++**)*))))()%3Eorxh"{\>% &#61oo9=ʵноϾннμϼλͻμͺ͹ͺ̹̹˸̸ʶ˷ʶʵʶʴɴȴȳȲdzƲDZ®¤i_V,++%&'&%'&$&%%&&&'!***|kֻª~~|}|yKD?#"#  !!" "83gYcWugu!%(,-...//-/.---,,,,+,++,+***)**()*$3Foryh"z[>$ &#61oo$#$ "!!"!"! !"!!#;5i[j^}n |$'+-.00//////...-.,,-,,,,,++*++*))+&3Eoq}l#iM3&#61oo?@@AAAAAAAAAAAAAAAAABABBBCCCCCCD@=nqr%t r[E0&#61oo9<ͿϿϿϾϾνͽνͼͼͼ˺˺̺˹ʸ˹˸ʸȷȶȵȵǵǵǴǴƴƲƲıİŰݯ®î­ѿѾпϾнϽϽϼλͻκ͹ͺ͹̸̸̹ʷʷʶʶʵʴɴȴdzDzȳDZƱDzƱưƮŮįïíìí묩~ʮm`W""'""!$"##!##!"""#$$#B@0|FzIWblu{؁ڂۃ܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄܄ۄވgw*t kP8$ &#61oo;Rӿc̺]ͺ_λ^ͻ]ͻ]λ^λ]κ]ͺ]κ]ͺ\κ\̸[ʶZϻZR..:>==;:<;9<;:;;8<99;98:668ϿϾξνμͼͼͽͼ̻˺̺˺ʸ˸ʸʸɷȶɶɵǴȴǴƴƴŲűııűİïïî­­ѿпѾпонϼνϼμͻͺ̹ͺ͹̹˸˸˷˷ʶʶʵɴɴɳȳdzdzDzDzƱƯƯįĮŮĭíĬì««ª}ѳIC;'%%#""""##!##!#$##$40\P^Rn`"}n'{+.2223333333333333333333333333333333332;9<::;;9<9:<:9<<:;669̿ϿοϾ;νμμͼͻ˺˺˹ʹʸ˹ʸɷɷȶɵȴǵǴdzdzƳƱŰİűİï¯î­ѿѿѿопоϾмμϼλͻͺͺ͹̸̸̸̷ʶ˷ʶɶʵɴɴȴȲȲDZDZDzŰůưŮŮůĮĭíìë«}çJC=&%&"#$""$"##"""$#$ nR8" &#61oo;Rdͺ_ͺ_ͺ^κ^λ]λ]κ^ͻ]ι^κ]λ\͹[˷ZмZT/0:>>=<;=;;<;9<::<;9<;:;;;<968̿пξϾϽξμν̼̻̻̻̺˹ʹ˹ʸʷɷȵɶȵǴǴǴƴƲƲűİ۰¯®­­ҿпѿпϾϾмϼνλλλ̹͹͹̸̸̹˷ʷʶɵʶʵȳɴɴȲdzƲDZƱŰƯŰįůĮìĬ¬ììªxA<7&$%####"##"$###$#$                                          sU8" &#61oo;Rdͻ_λ_ͻ^ͻ_λ_κ]κ]λ^ͺ]κ]ͺ\ͺ\˷[ϼZT55<>=<<;<;;=<9<<:<;9;::=:9;NEDϿϿξϾξͼͽͻ̻̺˻̺˺ʸ˹˸ʸȷɵɵȴȴȵǵųŲűŰıİï®îí­ҿпѿϿоннϽϼϻͻͻ͹̹͹̸̸˷ʶ˷ʶʵʵʴȳɳɳdzDzDZƲƯƯŰİůįíĬíëì©|f920"%#%$"$#"#""$##$#"# %$:+O4!6#ڟ{]w[befgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhf”px[EuV9" &#61oo;Rӿeλ_ϼ_λ^Ϻ_Ϻ_λ^λ^λ^κ^κ^κ^̹\ʷ[ͺ[S11;?==;:<<;=<:<::=;:<;:<88:ϿпοϾξͼνͼͼ̺˺̺̹ʹ˹˸ɷɷɶȵǴȴȵǴƳŲűűıŰðî®­¬ҿпѾϾоннνμμλ̺ͺͺ͸̸̷̹˷ʶɵɶʵʴȳȳȲȳDzDZƲƯůƯůįĮĭ쬬ëͰeYQ %##$$$$$$##"$$"##%$# !<.fA V: 2 ڭf̜xբ}ܨૂᬃ⬄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄⭄ᬄ氇פ~jQ>vW:#&#61oo;Reλ_ϻ`ϻ`λ^ϻ^Ϻ_κ_λ]λ]κ^λ]͹\ʷ\ͺ[S12;>>><;=<;<;;=<;<<:<;:;759ϿϿϾξμμͽ̼ͼ˺̺̹ʸ˹˹ɷȶȵɵȴǴǵǴƳŲŲűıŰðïíí¬ѿѾϿнмνϼλμκ̹͹͹̸˸˸˶ʷʷʵʴʳȳɴɳȲȲDZƲűưưůĮŮĮìíëë«}ѵHB>('($#$##%#$%$#%#$%$ 7,d@"[=!3!ڲiəupȘuʚv˛v̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w̜w͝xƗs٥ۨjQ=wX;#&#61oo;Reκ_λ_λ_ϼ`μ`ϻ^ϻ^κ_κ^ϻ^ͺ^̸\м[VVQC;:==<=<;><;=<;=<;<;:=;:=A>@пϿϾξνͼνͻ̼̻̺˺ʹ˸˸ɷɷɷȵȵȵȵǴƳŲűİűıïï­­­поϿϾнϽϼμͻλͺͺ̸̹̹˷˶˶ʵɶʵɴȳɴdzDzDzƲƱŰƯůįŮĮíìì뫪z>95'&'#$%$$$%#%$$%%!$!,&K3 aA$_@"5"ضkΝxndcbddddddddddddddddddeeeeeeeeeefckީڧiQ=wX;#&#61oo:Rfλ_ϼ`ϻ_λ_ϻ`ϼ_μ_λ^ͻ_λ^ͺ^ʸ]Ҿ]U..<@>@=<>=;==;=<;><:=<;=<;=EA@пϿοξννͽͼͼ̻˺˺˸˹˹ɷȷȷȶǴǴǴƴƳŲŲűŰŰïîî­ҿопϾнϼϽϼμͻͺ͹͹̸˸̸˷˷˷ʵʶʵɴȴɴdzdzDzƲưƯŰưįįĭĭ¬ë묩§~o624!&%&$$%%#%%#$$$%%#%"+'K4"fC%dC#6#غmџznhϛtՠxՠw՟wԞvӝuҜtќsЛsКrΙq͘p̗p̗oʕnɕoȔmǒmƒkƑkŐjÏiÏiŽhgfeeddcblީڧiQ=wX;#&#61oo:®Rfλ_μaμaϺ_κ`κ_κ^λ_λ_λ_ͺ]̸\м]T0/?=<>=<=<;>=;>=;=<;=;:<>=<>=<>=<=<<><:=99;ϿϿννͼͼͻ̻̺̹ʸ˸˹ɸɷɷɶǵǴȴdzƲƲƲŰŰİïîí¬ҿѿоϿнмϽϻϻͼͻ̺ͺ͸̹̹˷˶˶ɵʵʶɴɳɳȳȳƲƱDZŰƯưůůĭì­ì¬ëԷHB=(''%$%%%&%$%$$%$&'& 2(]<'mI(mI(:%q֣}oiНv٤z֡y֠y՟xԞwԟuӝuѝuЛtЛsΚs͙r͘q̗pʗo˕nɕoɔmǓlǓlŒkĐjÐiÏhŽggfffebkީڧiQ=wX;#&#61oo:Rfκ`ϼaμaϻ`ϻ`λ`λ`ϼ`μ_λ_ͺ^̹]̹[S34=@??><>==>=<>=<><;=<;=88:Ͼοξνͼμμ̻˺˺ʸʸʸʸɸɶȵǵȴǴƴƳŲűİűﯮ¬¬ҿпоϿϽмϼϻμλͺ̹͹͸˹̹˷˷˷ɵʵʵɴɴdzDzDzƱDzưůƯůįĮĭì¬ë쫪q832!(&'%$'%%&%%&$%&&#% +%B-\='rM)qK);&ėrפ~piѝvڣ{סzסy֡xՠw՟wӞwҞvѝuМtЛtΚrΙr̘q˗p˖o˖nɕnȔnǓmƓlőkőjĐiiihgffckީڧiQ=wX;#&#61oo:Rgϼaϻbмaϼ`λ`ϼaϼ`ϼ`ϻ`ϼ^͹]̹^˸\Q45=A??>=?><>>=?=<==;?<:<768пϿονμͽ̻̽˺̸̺˸ʹɸɷȶȶǵǵǴƳƲƲİŰİï®®­­­ҿпоϾнϼνλλͻͺͺ͹̸̸˸ʶ˷ʶʵʶʴɳɳȳȲDZDzƱűưŰĮįĭĭíí쫪Ǭvib,).##$%&(&%&%%&%%&%&%&#& .(E/!_A)wP+uN+<'řtإpiҟwۥ{آzآzסy֡y֟xԟwԞvӞvҝuќtϛtΚrΙr͘q̘p˖pʖoɕnȔmǓlƒlőjőkĐjÏhŽhgggckީڧiQ=wX;#&#61oo:¯Sgλ`ϼbμaϼaλaϻ`ϼ`μ`ϻ`μ_˸]`X77=A@A?=@>=?>>@=?ϿξϾϽͽμͼ̻̺˺˹˸˹ɷȷȶȴȴǵƳdzųƲİİİïïí­¬ҿпооϽϼϽνλͼͻ̹͹͹̸̹˶ʷ˷ʵɶʵɴȴȳdzȱƱƲǰůƯůůĭíĭ«ì¬ټKE@ )'(&%''&&&%'&#&%''&"!4+U8"bB+}T,yQ-='ǚuڥpiӠxܥ|٣|أ{עy֢y֡yաx՟wӟvӝvҜuМsКsΙr͘q͘q̘q˖pʖoɕnȔnǔmƓkƑkŐk‘kÐiÎhhďhdkީڧiQ=wX;#&#61oo:®Shμ`нaϻaλaλ`μ`μaϼ`ϼ`ϻ_˷^`V&(;DAA==@==??=?><>=;=EBDпϿϿξͼͽνͻ˺̺̺ʹʹʸʷɵɵȵǴǴdzǴŲƲİıį®í­ҿѿϿннϽϼμμλͺ̺͹̹̹˷ʶ˷ʶɵʵɴɳɳȲȳDZƱDZŰƯƯĮįĭĬ­ì쫪}833('('&&&%'&%&%%&$ $'91#R:S7$gD-W.~T.>(Ȝvۦpjաyܦ|٤|ڤ|٣zעyסx֠xաwՠxӞwӝvѝtЛsЛtΚr͙r̘q̘pʗp˖oɔmȕnƓmƒlƑkÐkĐkÏihŐidkީڧiQ=wX;#&#61oo:ShμbϽbмaμaλaϼaϼaλaϻ`ϼ_˹^aW+,;CB@?<@>=@>=?>=@>=?=<><;>KHIѿοϾνμνͽ̻̻̺̹˹˸ʸɷɶɵȴǵƴdzƲƱŲŰŰð®­­¬ѿѾϿннνϼλͼͻ̹ͺ̸̹̹ʷ˶˶ɶɵʵɴȴȳdzDzDZƲƱưưįŮĮĭì¬ì«Ūsh`,+/$$%'''&&''%'&%'&&(&$(A5$Z>U9%mH/Z0V/?(˝wܧpkԡzܦ}ۥ|ۤ{٤|ؤzעyסyנyՠxԞvӞvҝvѝtћtКsΙrΙr̘q̘p˖pʕoȔnȔnǓmƒkőjđjÑiiǑidkީڧiQ=wX;#&#61oo:¯ShϼaнbϽbϼbϽbνaλ`ϻaϼaλ`͹_ϼ_T21>B@A?>??=@?=@>=?>=?>=@<<=PJLϿϾϾͽͼλͻ̻̺̹˸ʹɸʷȶȵȵȵǴƴƳƲİűİïï­¬ппоϾϽмϽμͼλκ̺͹̸̷̹ʶ˷˶ʵʵɴȳɳȲȲDzDZƱưůůĮĮíííìì«©ټPHC#(()&&''&'&%'&%''((&!*F8&fE Y;'sL0^0X0?( ˝xܧpk֢zߨ~ܦ}ܦ}ۤ|ڤ{أ{آyסy֡xՠwԟwӞvҝuќtЛtϚsϙr͙q̘q̘p˗oʕnɕnȔmǓlƒlőkĐkÐkǒjdkީڧiQ=wX;#&#61oo:SiϼaϽbϻcлbмaλbμbϻ`ϼ`λaκ_̹_S65>A@A>=A>>@>>@?=@>=@>=?>=?^Z[Ͽξνͽͼͼͼ˻˹̹˹˹ʸɷȶȵǴǵǴƳŲűŰıð¯­ìѿѿѾоноϼϼμλͺͺ͹͹̸̹˷˷˶ʶʶʵɳɳȳDzdzDzƲƱưưįŮíĬ¬ìëë;65!)')(&((&'&&(''('$&&-+,\D)iG!^>*wN2`2Z1 @( ̞xݨpkף{ݦ~ܦ}ܦ}ڤ|ڣ{٤zآzסy֡yՠx՟wԞvҝuҜuМtϚtϚr͙r̘q̗p˖pʖoɕnȔmǔlŔkƒkĐkȒlejީڧiQ=wX;#&#61oo:SiϼbϼcϼbϽcϼcϼaмaϽbμaλaκ`̹_S66?CB@?>??>@?>@?>@>=@?=@?@?>@?>@?>@>=??=@`^]ϿϿϾνͽμ̼̼̻̺˹˸ʸɷɶȶȵȴǴƳŲŲİűİî®­¬ѿѿѾϿонϽμλͻͺ̹̺͹̸˹̷˶˶ɶɶʴɴɳȲdzDZƲDZưưŰŮůîííì쫪ػGA="*)*(&(''('&((')())%#*J:2zU,oN$gE-U6g3^3 A) ͟yݨqkؤ}᪀ߨިݧ~ݦ}ۦ}ۥ}ڤ|٤zأzסy֠xՠx՟wӞvӜvҝuМtЛsΚs͙q̘q˗p˖oʕnʕnȔmǔmǓl˕lfjުڧiQ=wX;#&#61oo:¯TjϼbмcϽdнcϼbϼbмbϼbϼbмaλ`̹_T66?CAA??A@>A?>@?>@?>@?=?>>@a^^ϾϾνͽν̼̻̺˹˹˸ȹȷɶȶȵȵǴƳƲıİİį¯í­­ѿппϿоϽϽϻμμͺͺͺ̸̸̸ʶ˷ʶɵʶȳȳɳDzȲDzDZƱưưůůįíì¬ë¬ªs201"#%))*(&))')(&)(&((((&$'+R?5Y.tQ&lH.Y7i4_3!A) Πyݩqk٥}⪂ઁߩߨݧ~ۧ~ۦ}ۥ|ڤ{٣{آzסz֡xՠwԟvӞvӞvѝuќtϛsΚr͙r͘q̗p˖o˖nɖnȕnǓl̕ngjުڧiQ=wX;#&#61oo:°UjϼcϽdϽcмbмbнcϽbϽcϼcμaϻ`͹`S67?BAB@>@??A@>A@>A?>@>>@?=@_][ϿϾϾͼͼνͼ̻˺˹ʸʸɸȶɵȵȴǴdzŲƱıűİï®­¬­опϾнϼμλͻͺ̺̺͹͸˹˷˷˶ʵʶʴɴȳȲDzDzDZƱŰƯŰŮĮĮĭìììȰOIF%%'('*)())()''((')(()'#'+C80lL7[1zU'qL/\8k4a4!A) Πyީqkڥ}䫃ᫀ઀ߩިݨܧ~ܥ}ڤ|ڥ{٣zآzעy֠xՠwԟwԞvӝvѝuМtϛtΚrΘr͘q̘p˗oʖoɕoǓm͗nfjߪڧiQ=wX;#&#61oo:¯TjμbϽdмdнcϽcϼcϼcϼbнcϻbͻa̹`T67?CAA@>@@>B@?A@?A@?A?>A?=@WRTϾξϽͼͽͼ̻̺˹ʹ˹ʹɷɶɶȴȵǴųŲűİűİïî­Ѿооонϼϼμλ͹͹ͺ͹˸˸˶ʷʶɵʴȳȳɴdzȳƱDzƱưŰŮůĮííìëD?;!$*)*)())')(())()),+'"-N>3|W:`4Z)uN0^9m5b5"A) Πzީqkۦ~嬃⬁᫁ઁߩިާݦ~ۧ}ۤ|ڣ{٣{آzסy֠y՟y՟vԞwўvѝuМuϛsϛs͙r͘q̗q˗p˖oȔn͘pgjߪڧiQ=wX;#&#61oo:°UjλcнdϼdϼdнcмcнdмcϽbϼbμa͹`T67ACCBA@B@?B@?A@?A??A@?@?>@OJMѿϾξͼͼ̼̻˺̹ʹ˹ʸȸɶȶȴȴƳŲƲİıı°îҿѿпомϽμλͼͺ͹ͺ͹̸˹˷˶ʶɵʵɳȳȳȳȳƲDZűưưĮŮůííí묪īsg[.,,&&'*()()*((*)')))*'#%+?52jM6|Y=f6_+zR2`:o6c5"B* ϡzީqkۦ䮃ᬃ⫂᪂ੀߩިި~ݦ~ܥ}ڥ|ڤ|٣zآyסy֡y֠x՟wӞwҝuҜuМuЛtϙr͙r̘q̘q˘pɖoϙpgjߪڧiQ=wX;#&#61oo:°UjϽcмdмdнdнdнdмcнcϽbϼcλa̺aT78@CCD@@B@@AA?A@?A??A?>@>>?KGIϿοϾνͽλ˻˺˹ʺ˸ʹɸȷȵȴǵdzƲŲƱŰűðïî­ҿѿѾϿϿϼμϻλͻͺ͹͹̸˸˷ʶ˶ɵɶʵȴȳɴDzȳƱŲƱŰŮĮůîĬíë««©ؾ522 !#,**)(*))*((*)())**'$'/[D6Y9\@k8b-}S3b:q5d5"B* ϡzީqkܧ孅㭂㬂⪂᪁઀ߩߩާ~ܦ~ۦ|ۥ}ڣzآ{آzעx֡y֟w՞xӝvӝuќtЛtϚsΙr͘rΙq͙p˖oљqgjߪڧiQ=wX;#&#61op:°UkϽcϼdϼeнeϼcϼcмcϼcнbмcϻa̺aT88?EAD@?BA?A@@B@@A?>A??A?=?HCFпοϾνͽνͼ˹˹̺ʸʸ˹ɶȵȵǴǵƲŲűİűİï®­ѿопϾмϽϼλμκ͹͹͸̹ʸʶ˶ʶɵʵɴɴɳDzdzƱDzƱŰưĮŮîĭíëë«ĭzj522'%(+*+)(**)*)(*)(**,+'$0SB:]=bEp;f-V4c:r5d5"B* ϡzީqlݨ篅䭄䮄㬂ᬁᫀߪੀߨ~ܧ~ݦ|ۦ}ڤ|٤{أzסz֡z֡xՠwԟwԞvӜtНuϜuЙrϙr͚q͙q˖pћrhjߪڧiQ=wX;#&#61oo:°UkϼdѾeϾeϽdϼdϼdϽdϼcмdμcϻbͺaU78ADBCB?A@?A@?B@?BA?AA@A@>@?<=Ͽνͼνͼ̻˺˹˹˹ʷɷɵȴȵƴƲƱűűŰï®î­пѾоϽϼλλμͼͺ͹ͺ̹˹˷ʶʶʵʵʴɴȳdzdzdzDZƱƯưŮįîĮĬ­ë«ͳ<78#$&+*++)**)**)**(**),(#'-@86oR<`AhHu=j/X5d;r6e5!B* ϡzީqlݩ簅䯅宄㭃㬃⫂᪁ᩀߨި~ަ~ܦ~ۥ}ۤ{٤z٢{آy֡z֡xՠxԞwӞvҞuѝuњuКs͚r͙q˗qҜrhjߪڧiQ=wX;#&#61oo:UkϼdоfнfϽdϾdоeϽcнcϼcϽcμb̺bT89@DBCA@AA@CA?BA?BA@A@?A?>A;:;Ͽνͽνμ˻˻̹ʹʹʷɷɶȵȴȵǴųƲűŰðîî­ҿѿоппϼνϼλͽͺ̹̺͸̸˸ʷʷʶɵʵɴɴɳȲDzƱƱƯƯŰŮŮíĬ¬ìëª834%%(++,*)**)+**+)(+*--("4_I=b?dEnJz?m0Z4f;s6d5!B* ϡzީqlު鰇殄殄宄䬃㫂⫂⫂ઁ਀ާަ~ݥ}ܦ}ۥ|٤zأzآzءyנyԠwӟwӞvҝtќtКtϛtϛt͘qԜtijߪڧiQ=wX;#&#61op:¯UkϼdѾeѾeнeѽdнdϽeоdϽcϽcμb̺bT98@EDDAACB@CA@BA@BA@C@@B?>A=@>=@οϾͼͼν̻̻̺˹˹ʷɸȶɵǴǵdzŲƱıŰݯ­­¬ѿѾϾϽмϼϻλλͻ̹͹˹̹˸ʷʶɶʵɵɵȴȳȳDZDzűưƯůŮĮĮíì+++$$&,+,**++*,**+*)++--(%6eM?cBfGpIxNAq0\6g;s6d5"B) ϡzީqlߪ겇籇籇氆宅宄䭃䫃⫁᪁઀ߩާݧ~ܦ}ܥ|ۥ|٤|٣{آyءyנyԟwӞwӝvҝuќtЛsΚs՞wjiߪڧiQ=wX;#&#61op:UlнeоfѾeнeϽfоeϽdмdϽdмdнcμbV8:BECDB@CBACBABBACB@CB?CA@C@?BrddονϽννͼͻ˻˹ʸ˹ɸȶɵȴȵǴdzƳƱűİįî­¬ѿѿпомϽϼμͻͺͺ̹͹͸̷˷ʷʶʶɶʵȴȳDzDzƱDZŰůƯĮŮîìϸ\TN/..,*-**,++,*),+*+++,)!&0I=:tWAdFmKvM{QCr1\5g;t6f5"B) ϡzީplᬃ괈谇豇簆簆殅寅䭃㬂᫂᪂ߩߩߨ~ݨݦ}ܧ}ۤ|ڤ|٣zءyעyաy՟xԞvӞvӝuҜtϛs֞vjiߪڧiQ=wX;#&#61op:VmнeѽfнfоfѾeѾeнeнdϽeнdмcλbW99BFEDCACBADBABB@CA@CB@CA@CA?BVPPпϾνͼͽͻ̻̺˹˹ʷɸȶȵȴȵdzųƲŰűİî­ѿппоϽнϼμͼκͺ̺͸̸˸˷ʷʶɵʵɴɳȳȳȲƲDZŰưưįůíĬĭv$#&%%(-,.++,++,+*++*+,..)%(8jPBfEiIsN{ORDt1]5h;t7f5"B* ϡzީql⬃뵊겈겈谆豆簆寅寄䭃㬄⫂ંઁߨߨݨݧ~ܥ|ۤ|٥{ؤzآy֡y֠y՟w՟xԞxҞwМtנwjiߪڧiQ=wX;#&#61op:°VnмfѾgϽfϽfоfоeнeϽfнeϾeѾdͻcU::AFDDCBDBACBACBACB@CA@BB@CAABOMOϾμͼͽͻ̻̻˹ʸ˹ɸɶɵȵǵǴƳŲŲűݯ®í­ѿпоϿомϼλμμκͺ͹̸˸̸˷ʷʶʶɵɴȴȳȳDzƲŰƱƯůįĭ¬ζKy[EfJqNxQQSCu1]6h=t7e5"B* ϡzީpl⭄괉곉鲇豇鱅簅篅殄䭄⬂⫂᫁ੀߨߨݧ}ܧ}ܥ}ڥ|ڤ{أ{آz֡yנx֡xԠwӞvќuءxkiߪڧjQ=wX;#&"61op:VmϽfоgѾfѽeнfѾeѾeмeмdнeϼdҾdY67AFEEBBDCBDBACCACB@CAADB@BBACD@CϿνϽͽͽ̻˻˺˹˹ʸɸɶǵȵǴƳŲƲİŰï®íѿпϾмϽνμμκ͹ͺ̹˹̷˶ʷʵɵʵɵɴȳdzDzƱƱưƯůĮŮů').'(*.--,+-,+-++-+*,--.+'*;lTFgIlNwRSSTËDu1]6h=t7e5"B* ϡzީpl㭄봉괉곈鱈鱈豆簆毅䮄䭃㬃㬁᪁ੁߨިݧ~ݦ}ܦ}ۤ|ڥ{٤{עzסy֡x֡w՟wҝv٢yjhߪڧjQ=vW:#'#61op:VnоfнgѽgпgϿgоfоfнeнeѾfλee^.0?HFFCCDBACCBCBBCC@DB@DAACA@B?=@ϿξϽͼνμ̼˺˹ʸʸɸɶȶǵȵdzųƲűűİî­ѿпϾннϽϻμμͺ̺͹˸˸˶ʶɶʵʶʴȴȴDzdzDZƱŰƯŰŮíɰUMP0./-,--,-,,.,,,,+,,-.) &6UFB~_HiNtS|TUTUċDv1^7h=t7e6"B*!ϡzީpl㮆쵊쵊봉겉鱈鲇豆毆寅它䭄㫂᫂᪁ੀߩިݧݦ}ۥ}ۥ|ڣz٣zעyסy֡xՠxӞwۣzjhߪڦjQ=uW:" ($51op:VlϽfѽgѾeϿfϽeѽeѽdϾeϾdнeͻde].0AHFECBDCACCBDBADCACBACCADB@C>=@Ͽξνͼνͻ˻˺˹˹ɷɷɶǵǵȴƳƲıűݯҿпоонϼλϻλκ͹͹̸˸˷ʶ˷ʶʶɴɳɴdzdzƱDZƱŰưįͶw&&()++,,-,+.,,-,,--+-./.+(*>nVJkLpR{VUVUUŋDv1^7i=t7e7$C+!Πzީpl䯆ﶍ뵉볉겉겈鲇簇篆宄宄㬃㬂᫂ੁߪߩިݦ~ݦ~ۤ}ۤ{ڣ{آzעyסyנyԟwݤzkhߪڦkR>qT7!)$51op9IJYrkljjkkjjijѿhj`00>IFECBDCAECBDBADBADBACCACC@BB@Cpbbονμͽͻ̺̻˹˸ɸȶɶǴȵȵƳƲűİűﯭҿпϿомϼμϼλκ̺̺͹̷̹˶˶ʶɵʵɴɴȳDzDZDzưŰƯì745.-0-,.-,--+--+.,+.-./) %9VHFdNnSxVWXWTUnjEw2^7i=t7e7$E,"͠yީpm密쵊촊볉볉鲇谇鰆毅寅䭄䭃㫂᪂ીੀߩާާ~ܦ}ۥ|ڤ|٣{أzآzסzԟxݥ|lhߪ٥mT? kO461op;Qμeɷ_ʷ_ʸ_ʸ_ʷ^ʸ^ʸ^ɷ_ʷ^ɷ]ȶ^λ_W[U:CBGEBDCBECBECBDCADBBDBBDB@DDBD@@BϾϽνͼμͻ˺˺ʸʸɷȷȶǴȵǴųƱűűİîî­ѿпоннνλλͻ̺̺͸̸˸ʷ˶ʶɵʶʴȳɳDzDzƱƱŰǰѸbWS,,.,,.-,.-,.,,-,,-,,--./,'+AqXMnRuVYYYXUUŋEw2_7i=t7e9%H-#̞yީpm䰇뵋봊곉鲇豈豇毆密宄㬃㬃᫂᫁ઁᩀߨݧ~ݧ~ݥ}ܥ}٣|٤{أzآzՠyܦ|khૃפ~qWB ybG/;1oj?;99999999999989@::FFEEDBEDBECBDCBDCBDCADBBCCBEBACϿομͼνͻ̻̺˹ʹʸɷȶȶǴǴƳŲƱİıïïîѿпϾϽмϼϼμͻ͹͹͹˹˸̶ʶʶɶʵʴȴɴDzDzƱƲƱȲ--/.-/.-/--/.,/.,.-,.../+"(DmYRpVy]`baĒ_Ȓ]ɒXƏXΒG{2_7i=t7d;&K/%˝xߪpmﶋ촉겈鱇鰇谅毅殄嬃䬂㫁᫁᪀ߧ~ݦ~ݦ}ۤzmh᫄ԣ|v[Eo {gS=( :0rtмXbaaaaaaaaaaaaaaX98BHEFCCEDCEDCDDBDCBECBDCBEDCD>=@ϾϾϾϽͼμ̻˺˹ʸʸɷɶȵǴǵdzƲűıİð®í­¬ѿпонϽϼμμͺ̺͹˸˹̶˶˷ʶʶʵȴȴdzȳDZƱŰĮD>B0///./.-/.-.--/-,..-/./0&#&?pWJlNrRzUVUURON@q1\7i=t6d=(O1'ʜwߪpkݪ貈密將䯇䮆㭅㬅᭄ଂૂߪީݨܨܨܦ~ڥ٦}إ|أ|ף{֢{ա{ԡzԠyӠyҟxўwϜvآyihᬄҠzaIN cQ@0  @6ʼa؂}}}}}}}}}}~ـڀـv65BHFGECFEBFDCECBEDBECCDDBDCBDA?BϿξϾͽͽͻ̻̹ʹ˸ɷȷȶȴȵƴƳƱűűï°ïѿѿпϾнмμϼμͻ͹͹̸̹˷ʷʶʶʶɵɴȴȳȳȲȳ̷q**+/.0/-/.-/.-/.-.../.../'-Q7V6Z:e@ kE"pH#sJ%tL&wM&wN'xO(yP){Q/Z7i;s7e>(P2'ʜwީ•rga~```````aaaaaaaabbbbbcbccccccccckߩϟyhN- I9."BC:쩕2ת3ڪ3ڪ3ڪ3ڪ3ڪ3ګ3ګ3ڪ3ک2ݨ1ᥐ1墎0額0힊/-{066DHEECCFDCFDCFCBECCEDBECBDDBEEEG0+-ϿпϽμμͼ̻˺˹ʹʸɷȷȶȴȴdzŲűűİįﮬ¬пѾоϾнμμλλͺ͹͹̸̹˶ʶʶɶʵɴȳȳDzdzȲ&',1/1/./../..//-/.-/../.*.+?5(kJ,V1]5e8k;n;p;s;r;sy>y>y>y>y>z=w7e@)P1'˞xߪީުݩܩܩܨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨۨ⭄ĕrx['" B>;>614|0|k. #|aB(fJSiR:YXE1mI9)>1"7+2'1&,"0(#HFJEBEDDFECFECEDCEDBFDCEDCFEDF??@οοϽννͼ̻̺˸ʸɹɷɶȵȵƳƳƲıűįïîì­ѿоϽннνλλλͺ͹͸̸̷˷˷ɶʶʵȴȴȴ̶|--/0010.10.1./0.///.0///1-1L3P4 V:"^?#fD&jG'mH(oJ(pK(qK)rL(rL(rL(rL(rL(rL(rL)sM,xP;&I-$hwZ{]|^~_`禀a槀a槀aaaaaaaaaaaaaaaaaaaaaaaaaaaaa`ଃcg9,! {^G`sgjjjklllnf??EHEGDCFEDEDDFEBFDCFECFDBEDCEHGIϿξνμͽ˺̺ʸ˹ɷʷȷȵȴȴųƲűıðð®î­ѿпϿнϼϼϼλͺͺͺ̹˹̸˸˶ʶɶʵɳʵͶ"$'3121/1//10/00.0//00-0,,.'%'qS5 -#pUvZqq봋଄⭅⭅⬄ᬄૃ谆țy9;?IFIEDGEDFECFEDFEDGDCEDCEEBFFEH@>AýпοϾͼͼ̼̺˸˹ʸʸȷɶǴǴƴƲűűİï¯î¬пѿпϽмϼμͻλͺ̹͹̸̷˷˶ʶɶʵɳϹ!$5450/11.2//00.1//00/0./0**,  f I 1 )>/$ [G6uZDrWCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCsXCrWBx\F_I7 -#pUvYr•qૃŖrɚuȘuȘuȘuȗuўyf LILEDFFDGEDFEDFECEECFDCEDBEEBEFDFZOQϾϾͼͼͼ̻˹˸ʸɷɷȶȵǵdzŲƲİİįѿѿϾϾоϼμμλͺ͹͹˸˸̷ʶʷɵɵк7145340011021010/10021/00/2++,RRTabejjmssvyy|~~KKLfG- -#pUvYrq密ocddddced=?DHEHEEGFDGEEGECFECFEDFDDFECEHFG559ľпϿϾͼν̻˺˺ʸʸʹȷɶǵȵǴƳƱİűİïî­­¬ҿѿоϾнмμλλκ͹͹˸˸̸˷ʷʵιŰqef.-.2130121020011/1000/.10/1A@Bzz}CCDgH- -#pUvYrq氆lh}֠xנx֟wԞuٟvoFEGHFHEDFFEGEDGFCFFDGECFEDFECFEEGDBEsjjξνͼͽ̻˺˹˹ʸɷɶȵȴǴƳƲıűðï®í­ѿѿпϿнϽϽϼλͺ̺ͺ̸̹˷˶ʶ̸ȴ}pr&'(3241031010/21020020/2101<;=llnvvxDDEgI- -#pUvYrq氆lhߧ~ԠxՠwԟwҞvנvnIFIHFHFDHEEGFDGEDFFDFEDGEDEDDFEDFHHI0/4Ͽονμμͻ̺˹ʸ˹ʸɷȵǵǴƴŲűıŰį®®¬пѿпϽϼϼϼλλͺ͹͹̹˷ʶ̹Ʊsf#&*54511210221320210210210188:WXZ__aggimmpssvxw{z{}||}}}~~~~~~~~~DDEgI. -#pUvYrq氆lh~աx֡yՠxԟw֟x̘siZBBFGFHFEGFEGFEGEDGEDFECGFDFEDEDDFFGJF7-ϿϽνμ̼̺̹ʸʹɸȶɶǵȴƳƳƱıűİî­¬«ѿѿϾооϼϼμκͺͺ̸͸˸̷̷s"545213212113202112112102))+fdgDDEgI. -#pUvYrq氆li֢yآz֡yՠxԟw٢xǗq;>DIHIGEHGEHFDGFEFGEGFDGFDGEDGEDFGFI98<пϿϾμͽͼ˻̺˸ʸʸȷȶȵȴǴƲŲŰűðïî­ѿоппнϼϼμͻͺ͹͹˸ʸ͸y&&*5363143231232121142122131.1ihjDDEgI. -#pUvYrq氆li㪀עzأzآzסxՠwܣzɗr7?D~ssϾϽͽν̻˺̹˸˹ʸȷȶȴȵƳƳűŰŰݯî­ѿѾϿннϼλͻɵðaWY3252035353344253353144232243230/0DDEgI. -#pUvYrq氆lj宂ڥ|ܥ|ڤ{٣{أzעzסz٣yʙr.6@KGKGEIGEHFEGGEHGEHGFGFDGFEHEEGFEGHCF=>FbϿϾͼν̻˺˹ʹ˸ʸȷɶǴǴƳųưűıݯѿѿѾоϾоϼ˹ȷɲ0/2869222446436324424325423324212012DDEgI. -#pUvYrq氆kj篃ۥ|ܦ}ۥ}ڥ{٣zآzעyעyڣxm:>DIHIGEHGFHFEHFDGFEGGEGFEHEEGFEFFEGHIL6/,ϿϾͼνͻ̺˺˸ʸʸȷɵǴȴƴƲƱűűᝮѿϿϿλʷƬ͸|ke99:/.0645545545435435445325434435<;=DDEgI. -#pUvYrq氆kj谄ܦ}ݦ~ܦ}ۥ|ۤ|٣{٣{עyآy٢xh\SEEHEFHFEHGEHHFGGEHGEHFEGGEHFDGFDGFFGCEHB@CϿϽννͼ̻̺ʹ˹ʸɷɶǵǵdzųŲűűİïí¬ѿпо̻ʹêǰHCC756013778535435546446445435555102-,.}}DDEgI. -#pUvYrq氆kj鱅ݧ~ި~ݧ~ܦ}ۥ|ۥ|٤|أzآz֡yʙtm^UNKLFGHHEHFFHGFIGFGFEGGEGFEHFEGFEFIGJ?=AA=?Ͽξννͼ̻˺̸˹ʸɷȶȵȴǴƲűııİïî¬ͼ̼пʹ̷TNL;9;003335757547456646546545436556435=<>~}DDEgI. -#pUvYrq氆kk벆ިߩިާ~ܦ~ۥ}ۤ|ڤ{أzעzޥz͚t*4@LIKIEHGEHGFGGEHFFHFEHFEHFEGGDGFDFJIJ<:BοϾͼͽ̻˺˹ʹʹɷȶȵǴȴŲıïο®¯ϷŲyohPJJHFE857,,01148796696576676476475576566580/1(')`_`DDEgI. -#pUvYrq氆kkੁ᫁ੀߨާݨ~ܦ}ۦ}ۥ|ڤ{٣z֡xާ{l3;CIHJIHHGFIHFIHFHGFHGEHGEGFFHGEHFDGJIK@?BIGJb[[пϾνͽͽ̸̻̺ʸ˹ɷȶȵııŰθıŷ|tXSQLIIKGG657)),102768989878668668657657657657868:89325DDFDDEgI. -#pUvYrq氆kkૂ⫂᪁઀ިߩާݦ~ۥ}ڥ|٤{٣z֡x|m9=EIHJJHIGFHGGIHEHFFIGFHFEGFEGGFGFDGHFIFDH>9:=((.-.1224868::<98;879779868768769767767657869214('*>=>vvxDDEgI. -#pUvYrq氆kl﵊᫂㬂⫂᪁᪀ߩߨݧ~ܦ}ۦ}ڥ|ڤ{أzաx|o9A((,,-1..3778?<>><=<;=;9;98::9::9;88;97::8;88:97997:87:869988<:8;99+,72/175).0/ђDDEgI. -#pUvYrq氆jl⮃宄䭄㬃㫂᫁⫁ߪߨި~ݧ~ܦ}ۤ}ڤ|٣{٢zԟy}ng;=EDEHMKJGFHGFHFFIGFIGFIGFHFEHGEGGEHFEGEDHLKNCCE,,/RPRʮyryt{tnqki@;>/.2-.1,,198:@>@><>=<=;:<:9<:9<;:<;:<98::8;98;:9;:8:98:88997:99:<::A=;769');0-1hdFW`T:98ٓDDEgI. -#pUvYrq氆jl䮄箅歅䮄㭃⫃᫁᪀ੁߩިݧ}ܦ}ۥ|٤{٣{أy֠xݥ{|h4;C7?>>@=;=;:<;9=<;;;9<::<;:;::;;:;;::;9<:8<98:98;:9;::;?=;879*,86HE<|r?p3ctyh <<9֖DDEgI. -#pUvYrq氆jl殄谆篆宄㭃㭄⫃⪂᪁઀ߩݨݧ}ܧ}ۤ|ڤ{٣{٣z֠yўw}~gr`V9=EDCHNIKHFIHFIHFIFFHGFHGFHFFGGFHGFHGEGEEGFFHJHJIGJ??C12598:LHKnghŶ}~xtVNPD@@<=>204,+016<99:A>@@>@@?A@>A==;>=;=<;=;:<;:<<;=;;<;:<::<;:;:9;:9<:9<;;<=:<@?<65;32: #6EC:}sBxoBIC:npvf=<:֗DDEgI. -#pUvYrq氆jl簆豆簆箅宅䮄䭃⬃⪁ઁੀߩާݧ~ܦ~ڤ|ۥ|ڤ{٣{أzМw~Ȗr}eACH5;CLIKKIJGGHGFIGFHFEHGEHFFGFFHGFHFEHFDHFEGFDGGFHJHKHGIDBE89<,+/=:>>>A?BBACA>@?>@><>><>=<><<><<>=;><<>=<>=;=<;=<;<;:=<;<;;<;9;=;<<;<><=@?=98<11; 7HEAF=@FLIJKGJGFHGEHGEIHEHGFHFFHGDHGDGFEGFEHFDGEEFFDGFEGHGIJIKGFIBBDCCE;;>358((,*(,=9;MGI^[\][\URQYVT_ZZc]^hbamffmffga`a[[\WWNKJVST[XY][ZMIK;6;.+/('+'%+--168:<=?==>CBCDBECBD@?A@>A?>@?=A>=?>=@>=?>><===>>;=<<=<;>=;=<;><;><;==:<@==A?=99<:9<..:!7C@=e^BphCILʴOϻPONɴRH;otzj >>;֙DDEgI. -#pUvYrq氇jm鱆겉겈豇谆毅宄䭄䭄⬂᫁ઁߩީާ~ݧ~ܦ~ۥ}ڤ{٣zآ{آz֡zΜv~Ŗr{ej[T6;D=@FNIJIGIGGIHFIGEIFEGFEGGEGGEGGEGFDHFEHEDGFDFEDGEDGECGFEGFDHGEHHFIJILJIKFFGCBD>=@>=?@AC>>A<88<67966:88<::><=@;:=;9<>=@BBCEDFGEGGEFDCECADB@B@@AA@A??@??@?>@?>A@=@>=@?>?>>?>>@>>=>>><>=<>=<=@>>@>>==><;>><>+,:%(9B@>BA>kcCxnEHMԾQκRDzPİPðQȴQȳPθSH;ot{i >>;ՙDDEgI. -#pUvYrq氇jm鲇괉겈鲇豇豇毅宆孄䬂⬂⫂᪀ߩߨިާ~ܧ}ۥ}ۥ{٣{آ{آyآyҝvӟwﰀmv`aWQ5;CBCGMKJJHIHFIGEIGFHGEHGEHGEGGEGGDHFDGFEFFEGEEGEEFEDGECGEDGDCFDDFECEECGECFEEHFDGDDFFDFFDFEDGFDFFEGFDFFDFECEDBDCADDCEDBEDCECBDC@CA?C@?AA?A@?B@?BA@A@?B?>@@?@??@@?A@?A?>A@>??=@?=A>=??>@>=@?=??=?@@@A>@A@??>?>=>01<,-;55<><>66=umEzqEIJįPTкSdzQïQİRDzRȴQʴQɵRɵQιTH>;ՙDDEgI. -#pUvYrq氇jm곈봉봉겈貉豇籆毆宅䮃㬄㬂⬁ંߪੀިݧݧ}ۥ|ڤ{ڣ{أzסyסxՠxΛvҞuh{gXZRO39C:>FBCHIGIIFHGEGGFHFEHFFHFEHFFGFEGFEGFEGEEFFEFEDFFDFEDFECFDDEECFDCFDCEDBFCBEDCDDCEDADCBDCAEBBDCBCCACC@DC@DAACBACAACB@CB@CB?BA?BA@BA@B@@B@@BA?B@?A@?A@>A??A@?@@>A@>@A@AB@BA@@A@AA@@A?@:9?/0=/0=/0<87>76>h`DvnGtH}I~vGԾSVлTϻTdzS®RŲRȴRɵSʶRɵRʶRʶR˷RʶRκVJ>;ՙDDEgI. -#pUvYrq氇jn봊촊봊鲉鲈豇谆毆䯄孄㬄⬂⫂ઁੀߩިݧ}ܥ}ۥ|ڥ{ڣ{٣zעzסy֡y՟xϛvƕoןsgyg]{fZ\SOAAIEDLPNMHGGIGIHFHFEGGFGFDGFEHGDGFEHEDGFDGEEGEDGECFEDFDDFECFDDEDCFDCEDBFDDEDBDCBECBEBBEDADCBDCBDCBDBBCCADC@CA@BBABBABA@CAACAABA@B@?AA@ACABCABCAAC@BBAACAA?=@13=33>33>23?32=44=KIAtjGqjHskG}rJ~tIİSWVѽVԿUñSïTdzTdzTȴT˶TʵS˶SʶSʶS˶S˷TʷTʶRʵRϺVJ>;ՙDDEgI. -#pUvYrq氇jn뵊촊곉곉鱈豇谆毅毅䭄㬃⬁᪂᪁઀ߩާݧ~ܦ}ڥ|ڤ|٣zأzעyסy֠x٢yȗqh˚vآxeQFHH:WQ='(5@@K<-/>>>@qiHleHnfGqiHrjHskHNWXWԿWXȴUįVŲUƲUdzT˷UʶUʶT˶T˷TʷU˵T˵UʷT˶U˶U˶T˶S˶SʶRκVI>;ՙDDEgH, .#oUvZrq氇jn쵋﷌볉곉번鱈鱆谆氆殄䭃㬃⫂⪂ઁߩߩݨݦ~ۦ}ۥ|ڣ|٣zآzעz֡y٢yȗqkĖtդ~ėr?--d[š>YV?slOogH]YJ-0C::E9:E>>E==F>?EKHHIGHHGHIHGIGGHGGGDFGEGFEFFEFGEFFCFECFEDFGEDFEEGEEFEEFDEGDDFDEFDEEDDHFE>=C67A98A98B9:B57@34@./??>Aa[GgaIf`HjcHmfId^GyMZϼXҾXZZYѼYıVŲVIJVƳUƳVɵV˶V˶V˶V˶W˷V˷V˷U˶V̷UʸV˷TʶU˶U̶T˷UʷTʶT˷SʶSϺWJ>;ՙDDEfH, /$mSwZqq氇jn쵋ﶋ쵋볊곉겉鱇籇篇殅宅䬄㬃⬂⫂᫁ߪިݧ~ݧ~ۦ}ۤ}ڤ{أ{ףzעz֢xآyȗrjƗt٧ɛtL83H@f˵JȲJV\WNpiPicPe_OicN_ZL32C88D77D77E67C78DAAH?=F=>E>=D>=D>=E==D??G66C44B46B55B55B55B45A34A66A+-?QNFfaJ_ZIa[H`ZHb\JhaJ_ZHuMW˸ZʷZҾ[[[ֿ[IJYǵXƴXǴXdzXdzXȴXʶX̷X˷X˷X̷X̸W˷W˷W˷W̷W˸W͸W˷V˷V˷U˷U̷V˷U̶T˷U˷T̶U˷TʷSʵRϺVJ;ՙDDFbE+ .$mSwZqq簇ip˜ﶊ첈벇鲇豆簆箅孂孂㬂⫁⪀ߩ~ߧ~ݧ|ߨ}ΛukŗtڧȚsM94SKξ^t­MGͺ^kgfóc̺c`^ZMibNgaNf`Mf`Ne`NYUI\XL[XK[WJZWJ[XJ[WJWTGd^Ke`Lc^Kc^Kc^Kc^Kc^Kb]JfaJROFT̺][°ZZϺ]__]ʷ\ȵ[ȵZǴZƳZǴYǵY̷Z̷Z˸Z˸Y˸X͸Y̸X̸X̸Y̸X̸Y͸Y̸X̸X˸W̸W̸W̸W̸W˸V̸U̸V̷U˷V̷U̷UʶU˷T˷U˶U˷TʶSϺWJ<ҙFFGx^@) .#jQx[pq氇jj춌ૃᬄଃ߫ުުީܨۨۨڧ٦~إ~٥}ף|֣|֢{աzԡ{ԠyӠyҟxҟwўxОwϝvΛu͛uϜuÒoiƗtڧǙsW?:ZQξ_wİLIǶ]̺f˸eͺeϼdͻdҿdhgggffP^]\][^PadcccbbaacѾ_ȶ]͸]˸\˹]ʶ]ƴ[Ǵ[ɵ[˸]̸]̹\̹\͹[̹Z̸[̹ZͺZ͹Z͹Z̹[͹ZͺY͹Z͹Y̹Y͸Z̹X̸Y̸X̸W̹W͸W̷X̸W̷W˸V̷V̸V˷U˸V˶V˷U˷U˶U̷T̶T˵SкWJ;pu|l"@?=ΘHHKnU;% ay\oq㮄od`aaaaaaaaaabcccccccccccdcdddddeiǗt٦ƘraFAf\̼^xİLIɷ^ѿhѾgоgϽfнeϻeɹcʹdʷcʸbɸb˸bfнbнcнcϼbϼbϻaнcȶ`ȵ_ȵ_ȶ^ȶ`ȶ_ȶ^ȶ^ȶ_Ƕ^˸^͹^̸]˸]̹]ι^ι^ͻ\ͻ\̺]ͺ]ͺ\͹\͹\ͺ\κ\ͺ\ͺ\κ[ͺ[ͺ[̹Z͹Z̹Z͸Y͸Z̸Y͹Y̸X̸X̸X˸X̸X̸X˷W˸V˷W̸W̷V˷V̸V̸U˶U˷T˷U˷UʷUɶTкWJ;ptn"BB?ȘNNPss^H2~_y\oq⭅˛wգ}֤~֤~֤~֣}֣}֣}֣}֣}֣}֣}֣}֣}֣}֣}֣}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}գ}ҡzҠzۧÖqoPJtiɹ]xİLHʷ^iϾfоfоgѾfѿfоgоfϾfоeнeнeλcϼdλcλcλbλbκbͻaмbϻaϼaμaϻ`ϼaϻaμ`ϼ`ϻ_Ϻ_ͻ_λ^Ϻ^κ_λ_ϻ_λ_ͻ^λ^ͺ]κ^λ^ͺ]κ\ͻ[ͺ\͹\ͺ\ͺ[͹[͹[͹[̸YθZ̹Z͹Y̸Y̸Y̸Y̹Y̹X̸X̸XͷW̷X˸V̸V̸V̷V̷U˸V̷U˶U˷V˷U̷T˶SкWJ;psq#|FECTTWV ]J9'|^{]op곉⮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅㮅宅ᬃp]VpxoǸ\xİLIɷ^ѿhоgоgѾfпhпfϽfнeнfоeнeнeнdϾeнeмcнdϽcϼdϽcϽcϼbϼcϼbϻbмaϻaμ`ϼ`ϻ`ϻ`λ_μ_ϼ^λ_λ^ͻ^ͻ_λ]ͺ]ͺ]κ^λ^ͺ]ͺ]κ\ι[ͺ\͹\̺[ι[͹Zͺ[͹[̸Z͸Z͸Z̹Y͹Y̸Y͹X̸X͸X̸W̸W˸X̸W˷W˸W˸W̷V̸V̷V˷V˷T̸U˷V˵SкXK;qrv%\LKHrrutuxttxutxuuxuuxuuxuuxuuxuuyuuzvwzwwzwwzwwzwwzwwzwwzwwzww{xx{xy|yy|yy|yy|yy|yy|yz}yz}yz}||]]^8 E5( g~`nlӡ|̜w͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝x͝xlkagcŶ[xŰMG¯TǴ[ƳYƳYƳYƳZƳYƳXųYƳXŲXųXŲXųWŲVŲVųWŲVŲWųXŲWűWųWŲVŲVŲWIJVųUŲVŲUŲUŲUŲTıTıTŲSŲTűTŲSIJSıSıSıSűSıSİSİSıSİSİSİRİRıQðRıRðQñPðQðQðQðPïPðPðPðPïOïOïOİOïOïNïNîOîNîNïNîNïM®MƱPG=pp|':SROeeg.# heTdةbcêcêbêbêbébébébébébébébébébébébébébébébébébébébébébébébébébébébébébéb©bdўpqC"dŶ[wűMCA@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?oo)^]Zoor İF/rŷZ|н[Ѿ\ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]ѿ]^͸Suo*ihdxz{}z|}{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~{|~|}xy{s++, edh`nTuYoTaJeLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLdLF 4uT؀}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}܆˽b15/ABl?;尜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찜;찛;粞>BOG#../ 223 :;; ABCPQRQQR]^`\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_\]_]]_]]_DDE                                   A@B9r-z1yk+l`&{1u/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/u/y0ui*x~????????(  ':DGHHHHHHHHHHHHHHHHHHHHHHHHGB4  #Jm{dB$ &^cF==??????????????<7*Mǹ^[软YWWWWWWWWWWVVVTSRQQQRTUUVWXO;4psy{{{{{{{{{{{{{{ynS.ʼ`fɷVͻZμZμZμZμZμ[μZμ[μ[ͼZ̺Z˹YǶWURPONNNPS²UǶXʹY˹X_nA9u@ɻ_ǶV'$$###""! ~umyhwfwezhnuCcNG'oqz냃끁~~~}~}~}~}~}~}~}~}~}~}}}}}||򁁄aacIʻ_ʹZ(#$"""! ~ptck\fWcU eV cUfX p`}jwEcPJ*ܘKʻ_ʹY)%%$###!!wbU?7-' ,& *% -(<4 MB XL ZM `R m]~lz@Ⱥ`NH(ے~~Kʻ_ʹY)%%$##"! qb(#        *% H= VJ YL eV ud8XKE'ݒKʻ_ɹY(%%$%$"!ND      5- PE VI ^Q {n/NFA%ߐKʻ_ʹY)&&%%$#!E=     QE SG g\'C>:!ኋKʻ_ʹY*&'&%$" G?    D6%lS7L@8!    NC [R#|s:73䄄Kʻ_ʹY*''&%##`T  s]GPN~N|OeDB4$   '" YP nf31-}}Kʻ_ʹY*((&%$v  r\DQxKxLxKxJ|KNjD6-$ JCha0,)vv}K($ʻ_ʹY*()&&#)% ^L9TyN|O{N{LzLxLwJ|L~NP@/ -)h`/)&rsyK )9ʻ_ɹY+)(&§&fY B5*V|P}Q|P{P{O{NzMzMxLxJPA7-  d].)&rqwK  Ⱥ^ʹY,)(($ |WS~S~Q}Q}Q|P{P{O{N{MxL}MkK SN)-*rrxK #7DHIIIIIIIIIIIIIIDķ\˺Z,))é(^R kXF[~TU~SS~R~Q}Q}Q|P|O{NyK~S,$ WQ*0,uu}K=e{Z̻Z,*)&)$  1+(]VWUUUT~S~R~R~Q}P{O}NyT ]W.62||K3#  ,[Xͼ[-*ī+r!  xcP^WWWVVUUTS~S|PQYL>1 {s:;6ㄅK1^-Ut4d5g5e4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d3d;%ֻS;\-*©+72 *%"^YZYXXXWUUT~RWvPC8.  1-K@;"K3b.W|:q7j6h6h6h6h6h6h6h6h6h6h6h6h6h6h6g8l=vA)ںRξ\.+*.* bTFb[\[ZYXXXWTbcQ?   ti1VHB&ݐI3b.Y{8l6cG{ExFyFyEyFyFxEyFxExFxFxEyFyEw4a:p@(ںRξ\.ɯ,|% pTb\\\[ZZYYX[F<3   ZO?ķ]MG(ܒwG$ 3b/Y{7k;===============;4%3b/Y{6k=k_ɓ[Ŏ\ŏ[ŏ\Ə\ŏ[Ə[ŏ\ŏ\ŏ\ŏ\ŏ\ŏZŎR6e:q@(ںRξ\.Ȯ.<7 G=7f`a``^^]\[aG>: VJn|CͿbPJ*kisyzzzzzzzzzzzzzzvhJ% 3b/Z{6k@mg͙bǓcȔcɔcɔcȔcȔbȔcɔcɕcȔcȕaǓ[ŎS6e:q@(ںRξ\.ȯ.2.^O>haba``__^\`<53 G>[OhZp=õ\D>KLW]\`\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a[[`^]cJJOh33b0Z{5jBnnϝhʘiʙjʙjʙjʙj˙j˙jʙiʙj˙hʗaǓ[ŏR6e:q@(ںRξ\/ɰ/61 cR>icdbbaa``]cXJ;  :3VJ[Nm]z3YA9<헊=옌=옌=옌=옌=옌=옌=옌=옌=옌=옌=옌=옌=옌=옌=엋=작Ayh!&Tb_]\\\\\\\\\\\\\[]:ww;3b0Z{5jDpuҢp̝q͞p͞q͞q͞p͞q͞q͞qΞo̝hʘaǓZŏR6e:q@(ںRξ\/ʰ/2.bSCjdeedcbaa`aqVD;VJYMla'AP[ʻadffggggggggggghcvG*č^z<3b0Z{4jFq}էvϡxТxТwТwУxТwТxУvϢo͝hʘaǓ[ŏS6e:q@(ںRξ\0ʰ0SJ F=7nfgeeddcba_fRE8 G>VJWLdWtev"'+------,,,,+++*)_E'ŌaJONOONNOOONONOOJ]z=3b0Z{4iHsح}Ҧ~Ҩ~ӧ~ӧҧ~ӨӨ}ѦvСo͝hʘaǓZƏR6e:q@(ںRξ\1̱1|n&  djhhgeeeddbba6-& 60SG WJ`SsbucE'ŌeSXXXXXXXXXXXXXXN^z=3b1Z{4iKu۲ӫլլլլլԫ}ѦvϢo̝hʘbȓ[ƎR6e:q@(ںRξ\0ʱ1+ gXIohihgfffddcbi(%&  "QFVJ\Om^p bE'ŌeX^^]^^]^]]^]^]YN^z=3b1[{3iMvݷ֯ױױװױׯժ|Ѧvϡo͝hʘaǓZŏR6e:q@(ںRξ\11ǭ1F?eliiihhffeecee%"!  @8WKXLhZ{j|cE'Ōf^cbbcbccbbcbb_ZN^z=3b1[{3hOwٴڶڵڶٵװԫ}Ҧvϡo͝hʘaǓ[ŏR6e:q@(ںRξ\21ʰ2*J@7qjkjihhhgfecef(%# ;4VJVKbUuexcE'Ōfdihhhhhhhhhhd_ZN^z=3b1[{2hPy۹ܹܺܺڵװԫ}ҧvϢo̝hʘaǓZƏR6e:q@(ںRξ\2ª22ë1:5o_OtklkjihhgfecfhA81 -(PEUJ^RqatbE'Ōginmmmnmnmmmjd_ZN^z=3b1[{2hS{޽޾ܹٴְԫ}ҦvТo͝hʘaǓZŏR6e:q@(ںRξ\2ª32ɰ3~*u^skmlkjihhhfded[MA MBXK\On_rbE'Ōgnssrrssssroid_ZN^z=3b1[|1hU{޾ܹٵװӫ|ѥvТo̝hʘaǓZŏR6e:qA)ػS;\2ë332ѷ4ZP# *((iplmmlljihggecpyeO =6VJ ZNl]rbE'ŋhtyxxxxxxytoid_ZN^z=A+1Y~1gW}߿ݻڶױլ}ҧwУoΝh˙aȔ[ƐS6e:qC*ӼSͽ\4«43231-*3.)sqmnlmljjhhgfbix^&! ;4VJYMl]p bE'ŋhy~}}}}}}ztoid_YN^z=   .{T1hX}ݿۻٶֲԭѨzΣt̟mʛfǖ_đYÍQ6e:pF,ȾUͽ[4«4ª433ʰ3,C;8uqonmmlljiihgdgc:3/ >6WJYMk\p bE'ŋiztoid_ZN^z= 2@FHHHHHHHHHHHHHJ;%gE9o;eNuJsIrHqGpEoDnBmAl@k>j=i;i:h8e5c:qG,U̼[4ë55ª3ª42ж4zk(  PE;voponmmlkjihgdekWI< :3THYMl]r bE'ŋjytoid_YN^z= 2[wyY<;t8q5n5o6o6p6p7p7p7p7q8q8q8q9q9q9r:s:uG-˾Uͽ[5ë6ª5ª4©443δ4uh'm_VzoqponmlkjiihfdjyeS <4WJ[Nn_v!bE'ŋjytoid_ZN^z=N %N*#T3!Q1!N1K.I-I-I-I-I-I-I-I-I-I-I-I,I,H,J.  ˹Sν[5ë6ª6ª5ª4443ī3>9 }kUxpqqpomllkihhgdku[$"' ;4TH]Pscz!bE'Ŋkztoid_ZN^z=6510XQP[YWVVUVTVTVTVTVTVTVTVTVTVTUTVTVTUSYXeZMȲW®W­VUUUUUUUUUUUUUUUUUmɸX6ì7ª6ª6ª5ª5©43ī24@;&fvqqppommlkjhhhdgi,'" J@VJaSzh!bE'Ŋlztoid_ZN^y<7587]igQPQOQOQOQOQOQOQOQOQOQOQOQOQOQORPLJsp((t_VuʺY˻Z̼Z̼Z̼Z̼[̼[̼Z̼Z̼[̼[̼[̼[̼[̼[̼[̼[̼[̼ZʸXJ9ì6ª6ª6«5ª5ª4ª43ŭ35,)50-xssrqppnmlkjihgefb(&( MCWKgYp!aE'Ŋl~ztnid_ZO_t:65;:]`_64A?@?@>@>@>@?@?@>@?@?@?@>A?@>CA21a^))t^Ul>>>>==<<<;;;::::9988;9ë7ë7ë6«6ª6ª5ª4420z*tdU}rtrqqpnmlkjihhfh}c +'UIYNp`x aE'Ŋn|vqke`ZNaj565;:]a_?=URSQSQSQSQSQTQSQSQTQSQSQSQTQVT=;c`()t_UnBȲCǰBǰBưAư@Ư@Ư@Ư?Ʈ?Ư>Ů>ŭ=Ů<Ů<ŭ<ĭ;ĭ;ĭ:ĭ:Ĭ8ì8ë8ë8ë7ª7ª6ª5441.(2/82/wvttsqqponlkjihhefqV81VK_Syh ξ`D&NJfoqnkhgda_][XVTQKab265;:]a_@>ZXYVXVYWYVYWYVYWYWXWYWYVYVWVVS<:c`))t^UnBưCŰBůBƯAŮAŮAŮ@Ů?Į>Į?ĭ>ĭ=ĭ=ĭ=ĭ=ĭ<ì;ì;ë:ì9ì9ë9ì8«7«7«6542.(F? )''syuutsrqportqmkkkjĠskZG LBYMj[uɺ^D+̐bj965<:]`^B@b__]_]_]_]`^_^_]_^_^_]`]`]YVVS<:c`))t^UnBDZCƯBưBƯAƯAŮAŮ@ů@ů?Ů?ŭ>Ů>Į=ĭ=ĭ=ĭ<Ĭ<Ĭ;Ĭ;Ĭ:ì:ì9ë8ì8«7752.(>9   UJA~xwvutssvvs[|iSWMH-(#/*&.)#1,'aSD}gMjMB: )%SG^Qxg{³ZD :yC{D|D|C|C|C|C|C|C|C|C|C|C|C|B|B|B{B+b{D65<;]`^CBhgfdfdgefegegefefdgdgefd`^XVUS;:c`))t^UnBƱDưCưBůBůBƯAů@ů@Ů@Ů?Ů?Ů?Ů>Ů=Į=ĭ<ĭ<ĭ<ĭ;ĭ;Ĭ:ì:ì9ë8853.(<7 !  E=9x|yxxvtxun^O2-*  G=2i#!"?7YMj[pR];11ꑀ1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀1鑀11閄3vd J65<;]`^EDonmkmkmknkmkmlmlmlnlmjge`^YWUS<9c`))t^UmBǰDǰDƯCưCưBƯBƯAŮAů@Ů@Ů?Į?Į?ŭ>Į=ĭ=ĭ=ĭ<Ĭ;ĭ;Ĭ;ì:ì9874/~o',)  ! vhZ~{{zyw}{e,)*   jT}hQ $"TI_SvfCŶ_dijjjjjjjjjjjjjjjkgvPL65<;]_]GFvvtrtstststrtstsussrnlge`^YWVS<9c`))t^UmBȱEǰDưDưCưCưCƯBƯAůAůAŮ@Ů?Ů?Ů?ŭ>ĭ=ĭ=ĭ=ĭ<ì<ĭ;Ĭ;«9850ui((&  !!  ! 841rƩ}}}|xmZ...SSTdddffgbbbZZZ \Nĭ=ĭ=ĭ=Ĭ<ë;961re( !"!!! "! TJDĪ~}}}r $PPQsaNqsZ(%WKcUp ! bNM65=<]^]KJ|ztsnlfe`^XWUS<9c`))t^UmCDZFưEƱEưDƱDŰDưCưBƯBƮAůAůAů@Ů?Ů?Ů?Ů>Į>ĭ=ĭ<ì<;83xj+"! !"!!"!# tfXǭ|dWI1,.oflC;5 H>_Rwg!#"##"!! bNM65=<]^\ML{ztsmlfe`^YWUS<9c`))t^UmCȲFDZFǰEDZEǰEưDưDưCůBƯBưAƯAƮAŮ@Ů?Ů?ĭ>Ů>Ů>í=«<95wj-"! """"###%$(yiʰ~?94eees\qgmr^:3[On_{!###"""!! bNM65=<]^\ON{ztsmlfe`^XVUS;9c`))t^UmCȲGDZGDZFǰFưEǰEưCƯDƯCưBůBƯAƯAů@ů@ů@Ů?Ů?ĭ=ì=;7w/! $!!#$##$$$ (%%r̳§4/*"!"raPrjlij0+($!WKeXs"#$""""!! aNM65=<]][QP{yusnlge`^YVVS<9c`))t^UmCȲGDZGDZGDZFDZFDZEưEǰDưCưCƯCƯBƯBůAŮ@ů@ů?Ů?ĭ>=9~1,*&"!$%$$%$& ,))yʱ§NEBWXX)(* gXIxnmmjpiYI MCaT|k"#$$#"""!!  aNM65>=]][SR{yurnlge`^YWVS<:c`))t^UmDȲIDZHDZGDZFǰFưEDZEDZEưDưCƯBůBĮAŮAí@í?í?ì>=;552'%&%$&$&!+))y˳Ūl_R-,..-.!  eWGyopomln~`?8_Rte"$$$$#""""!  aNM65>=]][UT{zusnlge`^YWUS;:c`))u_VmDɳHDZHDzHDzGDZFDZFǰEưEůDĮCíB¬B@??>=<;7PJ*%'&%&%&""#,*+z̴¬çu!  ggg``` #!"aTF¢|srqpnmlo2.+2-[Nm_{!%$%%#$#"!"!!  aNM65>=]\ZWV{zusnlge`^YVUS<:b`**wbYmDɳIȲIDZHDzGDZGưFůEíDCB@><:98775YQ,&'&&&%'$$$#!&ζí쬪ƪTKF###www|z{!!!ME>sttrqpolqfXJ " XLgZu!$%%%%##""!"! !aNM65>>]\ZYW{ytrnkfd_^XVUS;9a_+,|h]lDɳJȱIDzHưGůE­ECA?;852~1z.x-v-z,nb*$$('&(&%'('( vhѺ¬įĮíí쬪}(&'#""!! 1.-yxvuutrppmrlVJAeXp %%%&%$$###"!! !aNM65<;[b`A@YXUTTRRPPNOMLKKIIHHFFDDBB@@>A>42da--|kalDɳJDZIůGFCA=95|0s,zm)wj'qe$na#l_"k_ g["1/($$(('(*))g]WӼïưůůĮíììë«Ūp)') !n~xxwutsrqonj)&%F=cU{k %&&&%%$$##""!!!"aNM5432]caa`][_]`_a_b`b`bacacacbdbdbdcececcbsr%&}h^lDDzJîHFA=8~1t,vh(f[&_T#WM!?:#A;&?:%>9%@:":6#$%*)(()))!NHEȳdzƱƱƱưůŮĭíìë«ĩOGB)&%(%%82/r{zyxwutsqqoq/*%71`Svg%&&&&&%$$###"!!"aNM4321-98CA96x1.f,)[)'V(&U(&U(&U(&U(&U(&U(&U(%U(%U(%U(%U(%T)'Y 1eZiC®ID?82{m,eZ)IC)A<(,+,-,-.--%%,$$+$%*#$+$#***+*)*(()&&'411кDZȳDzƲƱưůůĮĭ쬫¨¨~}|}{yyxvutsqosA:5+']Psc%'''&&%%%###"!! #aNMðA˼SO㻭LKKKKKKKKKKKKKJN]i@D=4ui.TL,:7,,+-((/++0,,.$$'#+*+-+,0.-/,-,+, #'&(,+, #]VQӾDzɴȴȳDzDzƱƱưůĮĮí쬪~}|{yywvutroutcV&#\Oo`~%''''&&%%%$##"" "aNMõ]jɸZͼ]ͽ]ͽ^ν^ν^ν^ν^ν^ν^ν^ν^ν^ν^ν^ͼ^̻\ɸYN<;t2OI-10.((/,+//.0,,,#"%)(+OKH|qhųŲ~ri.,/#$&,,, #vkƳʵɴȳȳDzƲƱưůįĮì쬪~}}{zxwvttqvjR%"[Ol^|%(((''&&&%$$$##!#aNMƸ]ʷWD¯MKKJJJIIIIHHHGFEB=7dZ1310**0.-/311...#$&635ne^ʱĬҾѾѿǭ>:9##%+*+""%ӾǴɵɴɴȳDzƲƱŰůůĮĭìì«~}|zyywutrwnXOEm^z%((((''&&%%$%$#"#aNMƸ]ʹYŰOϻZ͹W͹W͹W͸V̸U̸U̷T̷T̷T̷R˷R˶RʵPƲOKD:MG2**1/.1201312&')0.2xngòɳƯпͼνϽϽϼλʹī<87&&($%'GBA˷˷ɶɵɴɴȳDzDzƱưưůĮíí¬«ª~}|zywvtrwpWH?l^w%())(((''&%%%#$"$aNMƸ]ʹYîN͹Y˷V˷V̷U˶U˶T˷T˶TʶS˶RʵRɵQɴPƱOKFx9542**2212213//0"#'^XU˵Űопѿппонϼ˹Ī0.0)() #sɵʶʶʵɴɳȳDzƲưƯůĮíìëª~}|yyxvtxsZH@j\u%)))))('('&%%%$#%aNMƸ]ʹYįNκZ˷W̸V̸V˸U˷U˷U˷T˷T˶S˶RʵRǴQMFxl7642..3422424+,.323{ɴɴ­­ѿѿпоϽн˹Ǯ}%%($%&JDCϺ˸˷ʷʵʵɴɳDzȲƲưƯůįĭ¬ì}|{yxwuw~e!H?i[u%)***((('''&%%%#%aNMƸ]ʹYįOκZ̸W̸V̷W̸V̷U˷U˷U˶T˷TʶSɴQ¯OJx=-,1104323435**-=:<һð¯İįî®î­­ппн̺ȯypf #'')ʷ˷˶ʶʶɴȳȳDzƱưưůĮĭ¬ëª~}|zyxvvn&$(E>j\t%)***)))(('&&&%$%aNMƸ]ʹYïOλ[̷X̷X̷W̸W̷V̷V̷U˷T˶TʶSűQM@334325434536++.MHHƸϻ°ŲŲűıŰİïî®­¬пϾѿ̹A=< i`[êʷ̹˸˷ʶʵɵɳȳDzƱűưůŮĭ쫪~}|zywxl#"&F>m^w'**++*)))('&&&&$%aNMƸ]ʸYİPϻ[̸X̸Y̸W̸W˸W̷V̷V˷VʶTdzSŰPF:86105545657,,.IDEοϻIJȵȵǴdzƲŲűűŰİïî­­ѿѿνƮ!!%977òн̸̹̹˷ʶɶɵɴȳDzDzƱůįĮíì«~}|ywyi!#G>n`y!'+++++*))(((''&$&aNMƸ]ʹYįOλ\̸X̹X̹X˸X̷W˷W˷V˷UʶTŰRM^X<+,47666560/1978ѾƴɶȵȶȵǴǴƴƳŲűİıİïî­ѿνȱjc]Ĭ˸͹͹˸˷ʶʶʵɳȳDzDzƱůůĭíìʲ˲ʱȰ}|zx{}eI@pa|!(+,,+++**))((((%'aNMƸ]ʸYİPϻ\͸Y͹X̸Y̸Y̸X̸W̸W̷VDzT˶RuB,,5976557334868ȶ˹ʸʷɷȷȵȵȴȴǴƳŲűűŰðî­¬­оĭ""%k`UƮ̹ͺͺ̸̹˶ʶʶɴɴȳDzDZưŰůìƯoHB<;77999;558DAAõϿϿξννμͼͻ̺˹˹˹ʸȶȵȵǴƳƱűİî­Į|μϾмϼλκ͹̸̹˶ʶɵɴȳŰйzi$#%~m϶}A:7#!#"-*i\t!).////..-,,,++**))aOzCƸ]ʸYűSн_κ]ͺ\ͺ\͹[ͺ[ʶYӾZ{I119;:;;:<-,0{snϾνμμͼ̻̹˹˹ʸɷȵǴǴƳűŰİïîоѿѿонϼλͻͺ̹˷˶ʶʵɴȲƱѺ}msѹ¬«©~940#"""4/i[u!(,--,,,+****))(('&μ]Qb3Ƹ]ʸYűSм`ͺ]κ]ͺ\ͺ[͹\˷ZʶWc]C21:<:;:9;435ϾϾξͼͼͼ˺˹ʸʷɶȵǴƳƲűİïî¬понϼλͺ̸̹˸ʶʶʴɳȳŰϹ̶ííììª{52/ $#$!B>'yo3ANųTɷVʸWʸW˸WʸWʸWʸWʸW˸W˸WʸW˸W˸WʸW˸XǴSkTqK" Ƹ]ʸYűTн`ͻ]κ^κ]κ\͹\κ[T=;<:8;<;<335_YYϿξνͼͼ̺˹˹ʸɷȶǵƴƳűİï®ѿпонμλͺͺ̸˷ʶʵɴȳDzŰůůĮĭì«Ĩ}h%$$$"#"NH(xo7GTYZZZZZZZZZZZZZZZY\>sCƸ]ʸYűTϽaͻ^λ^κ]κ]̹\Ҿ[L55;<;<>=?,,/|οξμͼ̻˺˹ʸɷȵǵǴƳűݯ­¬ѿпϾϼμͺ̸̺̹ʷʵʵɳȳDzƱưůįìì«ĩ|l[%%%##$!!                  EƸ]ʸXŲTоbͺ^κ^κ^κ^ʷ\\qjH01:>==<;<647Ͽξνͼͻ̺˹˸ɷȵȴƴŲűİî­­ѿооϼλͺ͹͸˸˷ɵɳȳDzDZưŰįĭì«ĩYME%$%# ##)&K2!(|`qŖtƗtŗtŗtŗtŗtŗtŗtŗtŗtŗtŗtŗtŗtƗtĖs̜xrXHƸ]ʸXŲUѽbλ_λ_λ^λ^κ]ɶZ^YD66<>==98;CACϾνͽͼ̺ʹ˸ɷȵǵƳŲűİîíпϾϽϼμͺ͹̸˷ʶʵɴȳDzƱƯůĮíìª521 !%%%$ ##6,_>$+oǘtpĖrĖrĖrĖrĖrĖrĖrĖrĖrĖrĖrĖrĖrŖroݩ}`HƸ]ʸXƲUоcλ`λ_λ_ͺ^Ҿ^V98==<>>@?@003{yϿξͼͼ̺˸ʸɷȵǴƳŲİð­ѿпϽϼϼͻ̷̹̹ʶɵɴȳDzƱưůĮìì«Ƭyj\('(%%'#!#L4lG)2#ɕspӟwڣz֠x՟wҝuќtϙs͘p̖oɕnǔmőkĐiŽhgbҡ{|_HƸ]ʸXƲUѾdλ`μ`ϼ`ͺ_`Q88>?>?A?A.-1ξμͼ˺˹ʹȷȵǴƳűݯ­­поϽϼλͺ͹̸˷ʶʵȴȲDzƱůĮĭíëīIB? "'''&$&")& Z<#tL+5%̘upӟwڣ{֡yՠwӟvќuϛsΙq̘pʖoȔmƒkđjiÎhcҡ{|_HƸ]ʸXƲVѿdλaμaϼ`̹_aleI33=A?@A?A103Ͽνμͻ̺˹ʸɶȴǴdzűİî­пнϽμͻ̺̹ʷʶɵɴȳDzƱƯŮĭìì«êz*)+%$&'&(&"%$B4#fC&}R,8'Кvqաyۥ}أz֡xՠxӞwќtϛs͙q̘pʕoȔnƒlđkĐidҡ{|_HƸ]ʸXƳWҿeϼbϼbϻaλ`Ҿ`keI66>@?A@?B335Ͽνͼ̻̹˹ʷȵǴƴƲŰİ®¬понϼͼͺ̸̹ʷʶɴɳDzDzưůĮììëɯpb!*))&%'''((V>'nI(X-9)ћwqעzާ~ڤ{أz֡xՠwӞuќtϚsΙq̗pʕoȔmƓkǒkeѠ{|_HƸ]ʸXƳWѿeϼbϽbϼbλaн`hbI77>A@A@?B647ξνͼ̻̹ʸɷȵȴƳűİï­ѿоϽϼκͺ̹˸ʷʶɴdzDzƱưůĮ­ìªĪGA>!!$)(*'#&(60,mL*uO+^/;)Ҝxrؤ|ߩܦ}ڤ|أz֢yՠxӞvѝuЛt͙r̗pʖoȔnɔmfѠ{|_HƸ]ʸXdzXҿfϼbϼbϼbλbѾ`icJ78?A@AA@B547Ͽνͼ̺˹ʸȶȵǴŲıİï­ѿпоϼλͺͺ̸˶ʶɴȳDzDZưƯįíì«ǯv&&((())()'!%,J;2{U-U-a/;*ҝx•rڥ}᪁ݨ~ܦ}ۥ|أ{סyՠwӟwҝuϛsΙr̗pɖo˖ngѠ{|_HƸ]ɸXdzXҿgϼcϽcϼcλbѽajcK88@BABBAC436Ͼν̼˺˹ʸɶȵƳűűð®¬поϼμλ͹̹˷ʶɵɳȳDzƱŰŮîì«˲lbU",*+)')(+*3mP7^0Z/d/<*ӝy•rܧ~㬃ߩިݦ}ڥ|٣{֡yՠxӟvҝuЛtΘr̘q͗phѠ{|_HƸ]ɸXƴXҿgϼdнdмcμbҾbjdK99ABAABBD314Ͽξμ̻˹˹ɷȵǴƲűİï­ѿпϽϼͼ͹͹˷˶ʶɴȳDzƲưůĮí«ŭ0..(')**+(#'+>5;`aItEv6e0h0<+ӝy•r᫂鲇宄䬄⫂઀ިܦ~ۥ|٣{ءyՠxӞvќtӜtlѠ{|_HƸ]ɸXǴZiнeоfнdϼdӿckeL::ADBCCAD=>@MKMξͽ̻˺˸ʷȵǴƳƲİ®ѿϾмμλ͹̸˷ʶʵȴdzDzưŮư832))+--.*&)0B:EgNwTJ|6e1h0=+ӝyÕr䮅鱈谆毅㭄⬂᪀ߨݧ}ۥ}٤{עyՠxנxēnПz}_Hƹ]ʸXɶ]mhiҿhϽgitmQ88AEDECBD@?AHFHϿνμ̻˹ʸɶȵǴŲı¯онϼλͺ͹˷ʶʶʴȴƲǰ®Ϸujb#$(/./,,-+(*>oVNtTVK~6f1i0=,ӝyÖr密겉鱈簆寅䭃⪂ੀިݦ~ۤ|أz֠yآyŔoПz}`Fǹ]ȶUS̹aɷ]ʶ]ɶ]Ƴ\ѽ]~tH;:BEDECBDEDF869ξμͻ˺ʸɷȵǵŲűį®пнμλͺ͹̸˶ʵʴȳDzİ̶-,.,+---.+'+6I@PrY[ZǏM7g1i2?-ӜyÖs곊﷌촉곈豆箅䭃⬂᪀ߨݦ}ڤ{ݥ|ȗqϞybt>ǹ]gŲRǵVǵUǵUȶUɶVϼWTDBFDBEDCDFEG446Ͼνͼ̺˹ɸȵǴƳűð®ѿонϼͻ͹̸˷ʶʵȴdzƱͶYRM&&)0/1--.+'*ArYQuVUSFw5d1h5C0Ҝypު籈㮅⬄ૃުݨۧڥ~إ}ע{աzӟyўwӟxl˛wfgT,Kɻ_ʼ`ʼ`˽`̾`Ȼ^[Y羽S@?CEDFCCEEDE>=@^[[Ͼͼ̻˹ʸȶȵǴŲŰï­онϼλͺ̸˷ʶʵɴŰк|m%%)1/0.-/0*.*N<(zP0\3d5f5g6g@Ͽνͼ̺ʸɷɶǴŲıįî­онϼλ͹͹̸˷ʶdz͹203.-/0/01.0(4/ a@)yP.Z0^0_1`1`2`&V2?-jqƘtșușușușușușușușușușușușușușușuƘti׮jʛw˛wșvԡztaV:=CGEGECFHFH759ϿϾͼ̺˸ɸȶǴƳűİ®¬ѿомμͻ͹̸˷ȵ̶įLHD++-1020/0,+. T$ R?/곈oԢ|o“q˙toX@@DGEHEDGECFCADMJLϾͼ˻˹ɸȷȵdzűİî­ѿоϽμλ͹̸ʶɵԽf\X$%)323102,+-NNOyx|$$$V!⭄oɚunӞvМtƕqMIJDDGFDGEDGGGH88;Ͽμͻ˹ʹɷȵǴƲűï­пϽϼλͺ˸ɵӽyme))-423213-,.>>@nnp$$%X" 㮄oʛvɗrܥ|՟xءwm]T=@EHFHFDFGDGDDFD@@Ͽνͼ̹ʸɸȵǴƲűð­ѿпнϼλ̸˸§vj'&*323324/.0;:<|z}$$$X"㮄oʛvɘrܦ}Ԡxߦ{h>@EHFIFEGFEGHFI<;>rooпνͼ̺˹ʸȶȵƳŰİîпоϽ˹ϼzq**-435425203/./rrs$$$X"㮄oʚvʙsߨ~أz֠yަ{o_U=?EIFHGEHFDGHGI::?Ͼν̺˹ʹȶǴƳƱݯ­оͼμīƴe^Z,+0435536324/.0ooq$$$X"㮄oʚv̛tڤ{آzۤz˚tNKKEEGHFHGEHFEGGGI;88Ͼμͻ˹ʸȷǴƳűű­ппȰ«IDC)+.766667324-+.tsu$$$X"㮄pɚv͜v㬁ܦ}ܥ}עzަ|l>AFHFHHFHFEHGFHFEH>=?ξν̻˺˸ɷǴıðİȳ˵Ȳɷ_XU//2103878768/.0757}|~$$$X"㮄pɚvΜw孃ިݧ~ۥ|ףz|yc<@EHGIHFIFEHGFHGEG96:Ͽν˻ɷɷȶ˷мθdz~le_DAA/.1./2878868546.-/IHJ$$$X"㮄pɚuϞx篅ߩߩݧ~ڥ|עz}~f>AEGFHIGIFEHGFHIHK97;\WXϿξ̻ѿҿϼȹ{tPLK?=>*+0003446:9;;9:879769=;>SSU$$$X"㮄pɚuПy鱆᫁᪁ߨݧ}ۥ|֡z}hHGJCDGKHJFEHFFHIIK@>B>=AtppɻzSONIFG-,0113436779<;<<;;;9;8790/8659#!aac환$$$X"㮄pəuҠy번㬃⬂ઁߨݦ~ۥ|עzާ{ĕr\TP9>DJHIIGIGEHIGIGFI;:=BAChefŸmeb`\ZJGH//3225547879>=?=<==<<=;<:9;349//965:ZS9W4- deo曚$$%X"㮄pșuӡz宅䭄⫂ઁިݧ~ۥ}עzߧ|ќvl]@AGBBHJHIHFHGEHIHJGEH==?:9=B?Bd`a~{yĽƼȾƽ~wrrmj`\[ECD88:33655854899@?>??=>>=>=<<:9;44;01:86:OK=xDJCl;3efp瞝$$%X"㮄pșuգ|ﶋ簆篅䮄⬂ઁީݧ~ܦ}آz٣{|jcXR>AFDDHJHIGEHGEHHGIIGIFEH>=@<:><;>77:;9;MJLOMNOLMTQQWSTSOQKHJMKMKIK;8;43655977:768769=>::=55<55<22;===RN?zpEK®O͸Q͸QFk:3 fgq柞$$%X"㮄pșu֣}鱈豇毆䭄⬂ઁߩާ~ܦ}٣{ՠyަ{סw}dVPM>@EGEJIGJIGHHFHHFGIGIGGHGEHHFIFFHBADA@CB@C?>B>=@?>@@?B?>A@?ADCDECDDCDDBCDCBDBCCAA=;?87?88?77>45>44=EC?_YCg`DLOɴRкSιSɵRȴRʵSGl;3fgq柞$$%X"㮄pșuפ}겉鲈谆毅䮃᫂ઁߩݧ~ۥ}٣{ՠyסyןunjXOF>>?==HA@GAAFB@FFEHIGGHFGGFFGFFGFGFEFGFFHFFGEEFEEFEEDBD==B<>BUQFROFSPF^YGOQPUλY͹YлYҾYӾXκWɵVʶWʶVʶU˷U˷U˶U˶T˶S˷TGl;3fhq枞$$%U!ڧpǘtϟz곉⬄ᬄ߫ީܨۧ٥}ؤ|֢{աzԟyўwўwƖppəxeS.g̸QѼ`Ѿf˹c]XZT}SS|RRWVUUVǴ\ðZ͸\м\Ҿ]Կ\\ϻZ˷Z̸Y˷X˷YʶY˷X̸W̸W̷W˸V̷V˷U˷U˶T˶T˷UGl<5his㝝((({L将oգ|”qÕrÕrÕrÕrÕrÕrÖrĕrĕrĖrĖsĖrĖsĖsÕrϞx͜zze6c¯Q˹bjhiihgffeeedddcмaѽ`ϻ`λ_κ_ͺ^ͺ^λ]ϻ]λ]κ\Ϻ[κ[κZͺZͺYιY͹X͹X͹X͹W̸V͸VιVHkC:lmwڜ002V8ӡ{kԢ|֤}פ}פ}פ}פ}פ}פ}פ}֤}֤}֤}֤}֤}֤}֤}֤}ץ}Ɩv{CcMïUȵ\ǴZƳZŲZŲYŲYųXŲXŲXŲXıWıWıVñVűUŲUűTƲTŲTűTƲTűSűSűSŰRűRıQİPİQİPİPİOįOİOïNįNïMįMįMChTJstȩFFGj&  feDcdb^a``````````````````````````````b~iU>SgϾ^ǵTȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶUȶVȶUȶUȶUȶUȶUȶVȶVȶVȶVȶVȶVȶUȶVȶVȶVǶVʸXl|mbst昘蘘蘘蘘蘘蘘蘘蘘蘘蘘蘘蘘蘘蘘蘘藗獍bbdD A96U˾b˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a˽a̾cĵX8L     //0ehjlnnnnnnnnnnnnnnmpͶZX7  A*vn4|}@????????????????????????????????(0` $  }q1? E@#^(&(&(&(&(&*(*(+(*()' 6%('''(!Ǹ[Ǹ]UñNACBB?:79;ųLga<34?>>=;;<<<=<<=>>?::;ɺ]ɻeV: ZM5-:1 SG tb'k񠠩ɺ\ȻcV=!%&" /( l_uqX򪪱ɺ\ȺcV>"$,' nW:qHdN3;5_[HA}C|EEEiŹcX>ǫ%aU eQ7V|NQrH SO?^feeg[rj8ʴA#0*$[~S}RzNYG9+ WSD.W/Z0]*zQ)xP)xP)xP+yPtOZuF׺@wh|eI^WVWcO8 3/{uW0]${Nc{Ag4Vmu 0]r@FuzѥxУyФsΟf˖;x\MնA=9""hfcf~gL OEs%.ì2ì2ë1ë0ĭ16bldfffik V9l9KxزװլuΠf˖;x[MعBwi$|hOpfeikYE>6 m]0^a]^]^Y` 1]l4P{ݺ֮uϡg̖i:e8d7c7b'_aNͱD2ͳ5pc(E=4tolhkc;3+(#^Q 2]yj]c PNEDCBCBCBCADC@>q穝BꮡLIJJJIPîB45ȯ5^T' aTExomhilI?2 /)j[3^zk\d } ]_QOPNTQSQSPTQNLNK¯C˳EʲCɲAɱ@Ȱ>Ȱ>Ʈ;ª8ë76ȯ4{)muqwrikA8- >7q1Yzwpkdab m SQc`feecfdcaPNJG꽫BưDůBĮ@ĭ?ĭ>ì<ì;Ĭ:«9ë6v*"!TJ@yysaRA+$+&!bRA [N:awsuuty~eUTtrxwxwtsdbOMJH뾬CȱFƯCƯBůAŮ?ĭ>ĭ<«;Ʈ9|n,{lZ¦~y4/*%',xy{25:5-%tbL81v é0ũ*ũ*Ũ)Ĩ(ç'ȫ'A XW܄utcaOMJH뾬CȲHưEưCůBŮ@Į?ì>ɲ8421.'$}ηéC;5-/4#eWHĦpsqW A:&$#"!C VTVTPNPNOMNLMKNLvIůG<{n0QI$9440*( &rҼ­ů쪩[PDl]Nxttg/+x'&%#"!D ĴSĴRIPJKJJINIxl653'$$(KGH{rlzh`Z!!$ѻƱƱůí«ʯƫ~{xuq-)($!q''&%$"D ɺ]ZTɶWιV͸V͸U̶SιRGWP4'MIJƯʱǯ˲zpf301ɶ˶ȳƱůí«~zwt3.+{k))'&%#D Ǹ[WSȶV̸X˷VʶU̷TMPK8 *xphɴ̷­пϾνʲUPK{oĩȴɴDzůĭĬ¨}yy>74zj**)(&%D ȹ[VTɶW͸Y̸XʶVϺTkc@ +|ulȵŲƳıįƯbZTӿ˷ʶɴDzįɲ|z:41o++*)(§'E ȹ[VTɶX͹Z˷XӾYM''/`[W˺ʸʸɷȵƳıʳu˸ʶDzͷ~ "852~{51/! u!..,+)¨)E ȹ[UTɷXͺ\̸ZлY\W@--5ͽξͼ̻˹ɷǴűDz³ͺ̸ȴѻy""$ziŭy,*,,*#¨.¨-¨+*)ĩ(F ȹ[UTɷY͹]ҿ]U//3idaϾν̺ʸȵƲŰѿϽͺ˸ɵʴʳ«q#=6!5B@@@??J \ȹ[UTɷZ̹^_O%&0ξͻʹȶƳİпϼͺ˷ɴʴĮìƫwc!-"|eGܔwUpPrQrQqQxW]L3O  ȹ[TTʷZͺ``ogH109żϿͼ˹ȶƲïоλ̹ʶDzưĮ«ȮeYN!K5iء{ќvΙs˖qĐlКt~_JRȹ[TTʸ[ϼbн`VQC?>DϿͼʸȵűîϽͺ˷ɴDzůì<54-('bBiۥ|ԟvϚrʖnhʖox\GRȹ[TTʸ\ѽd̺aOLBCBGϿͻʸǴİ­пμ͹ʶȳư¬ɱs!",P>-yQkઁ٤{՟wЛtɕnЛsy\GQȹ[TTʸ\ѾeͺbSODBAFξ˺ɶƲïϽͺ˷ɴDz­̴]UL":\2Yk毄ިڤ{ՠxΚrӞvy\GQȹ[SSʹ^h̺dTQH;:?ͼʹȴű­пμ̸ʶƱ˴)#'2H=Iz3Zk볉䭃ߩڤ|ԟwעzx\FRȹ\UTɸ\ͻbbc^L218Ͼ̺ɶƲîϽͺʶƱϹ]UO&%)RqVō5]m︌貇㭃ߨ٣{٤{}_IH³VT1ǷXVL^XE33:ͼʸǴİϽκǴԾw%!'"@1.Z/`(yN浈hРz̜w˛vʚvət˚v}` ’sqYŒrm[;EB?Aξͼϼл˵̻|867002zz|t-'"vZEiiigɚumgբ{᪁}o^;>D?>A̺ic_=;B$%-BAC|{~tɚumgפ}殄ݧ~|eJHJ24:RPSüɾù¹kfdKIN009'(2444b\@{>wuq||sɚukfܩ宄ੀ嬀ƖsyfZFCC44;00:65?::C:9C77A33<017657DA:YT@xoHMRԿUIsro||~uʛvng֤}ᬄۧؤ}ӠzףzȖsP꬞][{TvRzQ}QTWYɶZѼZYտWϺU͸UGutqdĕrp?ǘtŗsŗsƗtƘtƙtsƳZѿ\^]ҿ\\\ѾZнZͺYʷXǵWƴVƴVǵUȶV±P鄂|םМћњϚ،`_`ɽfS/VFSATBUBUBUBVBVBWB´XBĵYBĶYBĶYBĶZBƷ[CõX=v(( @ "A=>>>?7Tɺ])Aܓ4뙉6隊5v/t.阉5nf6'(277644699:''()BŸb=ì6Ǭ""RH#! 81 lWmlo?UΗxƷYƹc;6!/+) _J3`[=rqt<  LM͵:i[TTP 87,ssu>-90Tk(H] -W/[3$jF ]>"`?Z>NnBū8#!w`H[UiHYV?xx{68j3c`NXƎXČK^_.#!^`vS NDXqqre_b` d+/}U0`_eyҤuΠT][/%" gd]5/ t,7886MW\Z\W aqn?m1``}ʡݷ~ѤVÏVZǩ9('s`NogwX raåJ^ffc]^8p(a`̫ۺo͡KN\ӳƪCɬAɬ?ȮA:ŭ6ƭ6 H?9ztlbH=4 pLmnbZTSRfdkikiNLnhs̷?îCį?î=:Ʈ:7KD !t^¤tbM83.DB@K@4# ";4 :bbac\ eYW“~trMLohrͷAĮEůBŮAǰ?ĭGdzѽıðDZ}q°κdzʴsbħ]QH1-),*&7kT9ɶYҾ\S435ʹ̺ɷƳȳѾȴվoeZHB<ŬũSJD@:-ƭ/ê,ǭ(:gT9ȶZa{rCYV[ν˹ȵƲоͺ̷®ƯĬ§?97D?!B쥓AAB? AS9ʷ\cVQ;Ͽ̺ȵűϽ̹˶Ʊ«ê%))AM:qlhkdO8R9̺^ϼbFC:Ͽ̺ȵİλ˷ȳí˲|i)%UsQ|٣yϚqњqpT9R9ͻ_ͺdDB:ξʸƳ­н̹ɵį˵WFCP=\`|ۧ~Ҟv՟voT9R9ͺ`hGE<ͼȶİλɵθ~0/1Dt^c驂籆ܦ}ߧ}pU;T)ɸ[XKG;wuxϾʸƲͻʷѼODB$I76nU~Wڟ{֥~џyӠyblUSS̘t|fW?AFʹŲǬqg]66:w|{|QSR+ jR~bh lpfG աyʚw>=?poqԿ˴ijld];;=dcfjiU@Ϟy筂oB?A`ae¿ö|zXUXA>:GFCaacN<.omjM=-֤}鲇讂̜wm\P=>>\%%%5QQSIJMɹ]%.fXA5bZ/WWY8%&iDD N7xaD}o%mUAmH:6.bcjnstȧR}_Ócn_R'f]L5PK!sih~z?Fy!((ʴjxԲ^wq'saNkC9*\Q à n^.964{]喨RMҸ:SKycl<31fT |]/:6ZYRywYY^ݽ<۽A-\S?iyqe]W905JD,,>igK[Y]4zn-_WGĭojfqn\Jyhϯ!1/AY'TPpg>wu̶ĮŨm[i]ͱ+,/-@S'\EѺ̷{jrapd̴*,31 ?ɹ_'ǴVzs`̼ʷ͹ͳodUpb;œ\J 'g'UvϾǴпʷαFVHhꨃ~b&iTvrjʸ­ȭt%aHt뫂h֡wowcVŷebaVVSrۧu֢{l_xyXxqPWVX|ɛvEܨӟtHH̝HȮKɵMdiikD?pgmodeler-0.9.2/main/res/windows_ico.qrc000066400000000000000000000002061360462764600202640ustar00rootroot00000000000000 IDI_ICON1 ICON DISCARDABLE "windows_ico.ico" IDI_ICON2 ICON DISCARDABLE "windows_ico1.ico"pgmodeler-0.9.2/main/res/windows_ico1.ico000066400000000000000000012615361360462764600203520ustar00rootroot00000000000000 ( V (~ 00 %(  NN h^(        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  #((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((("  ',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,&   *///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*   !##$$$.333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333.$$$##!  "#%'(())26666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666662))(('%#"  ***':::G<<>>N''' ===&IIILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKHHH999,???,JJJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJJJ===3<<<JJJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJJJ999""""IIILLLLLLLLLLLLLLLJJJLLLOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOMMMJJJKKKLLLLLLLLLLLLIII!!! HHH7LLLLLLLLLLLLLLLOOOjjjoooPPPKKKLLLLLLLLLLLLAAA6JJJ~LLLLLLLLLLLLMMMPPPLLLLLLLLLLLLIIIAAAKKKLLLLLLLLLLLL^^^aaaKKKLLLLLLLLLKKK+++FFF&KKKLLLLLLLLLKKKvvvxxxLLLLLLLLLLLLKKK===%HHH+KKKLLLLLLLLLKKK}}}MMMLLLLLLLLLKKK???.GGG,KKKLLLLLLLLLKKK~~~MMMLLLLLLLLLKKK???.GGG,KKKLLLLLLLLLKKK~~~MMMLLLLLLLLLKKK>>>/GGG,KKKLLLLLLLLLKKK~~~MMMLLLLLLLLLKKK>>>/GGG,KKKLLLLLLLLLKKK~~~MMMLLLLLLLLLKKK???.HHH+KKKLLLLLLLLLKKK~~~MMMLLLLLLLLLKKK@@@.HHH+KKKLLLLLLLLLKKK~~~MMMLLLLLLLLLKKK@@@-KKK*LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLKKKBBB,KKK*LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLKKKDDD+KKK)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLKKKDDD+KKK)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLKKKFFF*LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLIII(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~uuugggbbbaaa```````````````````````````aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabaabaabbbbbbbbbbbbbbbbbbcbbcbbcbbcbbcccdgggnnn}}}MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~~ffbUTQONKMLILLHLLHLLHLLHLLHLLHLLHLLHLLHMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMMIMMINMIMMINMINMJNMJNMJNMJNMJPOLRROVVUddd|||MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ϲù|m\O|GyCyCyCyCyCyCyCyCyCyCyDyDyCyCyCyCxCwCwBvB~uB~uA~uA~uA~uA~uAvBwBwCwCxCyCyCyCyCyD{CwoBUSFVVVkkkMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~˿ʽaljlllllllllllllmmllkkiige˾eɽdɻdɻdȼdɽd̿efghjkkllnlP]XAPPQcccuuu|||zzzsssnnnjjjiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkknnnuuuMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ÎndɶUɷXɸXɸXɸXɸXɸXɸXɸXɸXɸXɸXɸXɸXɸXɷXȷWǵWŴWñUSRPMLKJJJJLNPQS²VƴWǵXȵVͻZlWZV@NOPbbbooorrriii^^^UUUQQQOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPPPSSSZZZmmmMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐkȶX7211100000000///.-,+(&~$x#u"s"q!p!q!s!v"z#$%'())-BdVXT>XY]ppruuvuuwoopiijcdebbc``a``a``a``a``a``a``a``a``a``a``a``a``a``a``a``a``a``a``abbc]]_QQQ```MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷZ1"""!! ~umygtcq`o^n^n_q`tcygnt|>fUWS=ppwQQR]]]}}}MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷZ1#$$##"""!!! zpygp`jZfWdVcUaS`R `RbT fWk\tc}kt~<οcTVQ6  ("D: RF UI [N eWxk*LFMI7klrNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷZ2%&&&%%$#"" r;2 5.PF UH ZMk_%Dz@IF4iioNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷY3&''%&%$##! zj)#  2+OC RG_U }u=vn9C@0efkNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷY3&&&&&%$$"!}.( ([H3_J3J<10' 4,OD XNrj7kc4>;,aafNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷY3''&&&%%##=5  C6)lG}O|NyLvLeD[H40&  ?6 VLjc2c\/:8)\]aNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷY3'(''&%%$ MC K=0xRP{L{M{L}M}M|NrJlU;9." OFg_1\V-63'YY]NNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ĐlɷY4'(((&%$#n_E8,xSR{L{MzMzMxLyK{L|LPtKaL4! <5e]/XS+31%UVYNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ÏlɷY4())'&%$+& 7,#rOR|N|O{N{N{MzLzMyLyKyK}L~N}a?.%$ ^W,XQ*1.#SSVNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ÏlɷY4())'&&$TI gHT}P|P|P|P{N{N{MzMzMzLyLyL{LOiG*" QL(ZS+0.#QQVNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~lɷY4()('&&r kV>UR~Q}Q}P|P|O|O{O{N{MzMzMyLxLzLOqY= C?"YQ*1/$QQVNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ƽlɷY4)*)'(#B9I;-VT~SS~R~R~Q~P}Q|Q|P|O{N{N{MzMyL}NyPC6)53UO)30%RRVNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~lɷY4*)('(n& pRXTT~T~S~S~R~Q}Q}P}P|P|O|O{N{M{M{MUfQ; 41WQ*52%STXNNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~qmȷX4**()&PF aO<\UUTUTTS~S~R~Q}Q}Q}P|P|O{N{N|NSlT5 63[T,74'VV[NNOZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~yyytttrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrssssssssssssssssssssssssssssssxxx`mȷX4**))! 3+%yUYWVUUTTTT~S~S~R~Q}Q}Q}P|O{O|OWdP; 95aZ/;8*ZZ_NNNZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~kkk\\\UUUSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSTTTTTTTTTTTTTTTTTTTTTTTTTTTUTUYXY___RmȷX5**)(dW mYE^YXWVVUUUTTTS~R~Q~Q}Q}P}PUvQ6,#B?#kc4@<,__dNNNZZZ{{{MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~ewnPbYDVL>OG;NE;MD;NE;NE;NEBHE4iioOOO\\\|||MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~p8l5d6e6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f5e5d;p6f4NBsAnȶX5,ª,)>6C7-d]\\\[[ZZYYXXXXWYs\D*"'" s/XNQN:mnt[[\hhhMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~=o6h9gExG|G{G{G{G{G{G{G{G{G{G{G{G{G{G{G{G{G{G{H|Cv6e8m5f3NBtAnȶW6,Ƭ-#&! `O=b_^]\]\\\[ZYYYX[s]E o`8´]QTP;oovgggtttMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~=o6i>nRUƌTċTċTċTċTċTċTċSċTċTċTċTċTċTċTċTċTċTċUƌM9i8m5f3NBtAnȶW6-ʰ/o oTd`_^^]\]\\\[ZY[sS' k[;ɻaTTO;novqqq}}}MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~=o6i@oWZǏYŎYŎYŎYŎYŎYŎYŎXŎYŎYŎYŎYĎYŎYŎYŎYŎYŎYōXƍN9i8m5f3NBtAnȶW6-ū/dW3*!`c```_^]]]]\\[Z\`N; .(iZy<̾cSRN9nnurrs}}}MMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~=o6iBpZ^Ȓ]Ƒ]Ƒ]Ƒ]Ǒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ]Ƒ[ŏWŎN9i8m5f3NBtAnȶW6ƭ/+C:J>5ccaa```_^^^]]\\[E:0 4- \Oter;ɺaQQL7lmskkkqrr}}~yzzvwwuvvuvvuvvuvvuvvuvvtuutuutuutuutuutuutuutuutuutuutuusttstttuuxxxMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLLLLKKK~~~=o7iEr_đcʖbȔbȔbȔbɔbȔbȔbȔbȔbȔbȔbȔbȔbȔbȔbȔbȔaǓ[ƏWƍN9i8m5f3NBtAnȶW6Ǯ/*=5YJ9edcbbaa```__^]^[@6-/( VJ]PgYxgv7\OLH5NOXjksmmsnntnovnovnovnovnovnovnovnovnovnovnovnovnovnovnovoovoovoovoovoovoovoovoovoowdejYYZdeestt|}}z{|pqqcde\]]XYYVWWVWWVWWVWWVWWVWWVWWVWWVWWVWWVWWVWWUVWUVWUVWUVWUVWUVVUVVWXXZ[[bccuuuMMMLLLLLLLLLLLLJJJ(LLL)LLLLLLLLLMMMLLL~~~=o6iFtdƔh̙fʗfʗgʗgʗgʗgʗfʗgʗgʗgʗfʗgʗfʗfʗgʗdɖ`Ǔ[ŏWōN9i8m5f3NBtAnȶW6Ȯ0*?7 `N9fedccbbaaa``_^^^MA5+%QGVJ^Pl\zi2UIYR/FB2LH6OJ9PL:RNUe>Ue>Ue>Ue>Ue>Ue>Ue>Ue>Ue>Ue>Ue=Ud=Ud=Ud=Ud=Ud=Ud=Ud=Ue@WgEU_PSUfffMMMLLLLLLLLLLLLJJJ(LLL)MMMMMMMMMMMMLLL~~~=o6iHuiǖnΜl̚l˚k˚l˚k˚k˚l˚l˚l̚k̚l̚l˚l̚l˚iʙdɖ_ǒ[ŏWōN9i8m5f3NBtAnȶW6Ȯ0+?7 gU?gfdddccbba`a``_anZD B9 THVK_Sj\|o+LTMNPSTUUUUUUUUUUUUUUUUUUUUUVVT=KURNmssrqppppppppppppppppppppqiNHU]__^MMMLLLLLLLLLLLLJJJ(LLL)MMMMMMMMMMMMLLL=o6iIvmɚrϠq͞q͞p͞p͞p͝p͞q͞q͞q͞p͞q͞p͞p͞n̜jʙeɖ`ǒ[ŏWōN9i8m5f3NBtAnȶW6Ȯ1+=6 `P>hgeeeddccbaaa`_bxX(! J@SHVJ]Qk_$y SHVK_Rk\zix$FnKFQM_lo~zvsolhd`\XQj^DR\\\[~~~MMMLLLLLLLLLLLLJJJ(UUU)UUUUUUUUUUUUTTT|h=g=g=g;g:f:e9e9d8c7c7c6c6b4`3`8n:kMh\RmȶX9«555©44ª33ª3ͳ5'# F;0lsqpponmmmmlkjiihhgfeghzeQ% D;RGVJ_Rm^m}%FnKFQM_mt~zwrnkhd`\XRj^DR\\\[~~~MMMLLLLLLLLLLLLJJJ(UUU)UUUUUUVVVVVVUUU|||zzzzzzzzzzzzzzzzzzzzzzzzzzz{{{{{{{{{{{{{{{||||||||||||||||||\qttppponnmmllkjiiiigfegiuX90(D;SGVJaSp`o%EnKFQM_mu~zwrnkgd`\XQj^DR\\\[~~~MMMLLLLLLLLLLLLJJJ(UUU)VVVVVVVVVVVVUUUqqrddc]]\ZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ^^]_a`Kq_9eWM{HmȶX:«6ª6ª5454433Ʈ4ʱ4vg  gXGusqppponmlllkjjiihggfej_N@3  I? SHXLcVscr%EnKFQM_mx~zwrnkhd`\XQj^DR\\\[~~~MMMLLLLLLLLLLLLJJJ(UUU)VVVWWWWWWWWWVVVss{YYaIIQBAJ?>G>>F>>F>>F>>F>>F>>F>>F>>F>>F??G??G??G??G??G??G??G??G??G??GBBKHILOXPUfVZj\Zj\ScTIYKBQD=M?;K??B@>@>@>@>@>@>@>@=@>@>@>@>@>@=@=@>@>@>A>?=53VTcb76[tl9cϽ[B@AAA@@@@?????>?>>>>=======<<=;ë8«7ë7ê7ê6ª6ª6«6ª6ª54422Ĭ3t#% f{uttsrqqpponmlllkjiihgfghaRD I@ XL\NhYziy%DmLFPN_n{xtqlhea\XQjeXfoponMMMLLLLLLLLLLLLJJJ(XXX)YYYYYYYYYYYYXXXfeXV:8LJOMNLNLNLNLNLNLNLNKNLNLNLNLNLNKNKNLNLNLOMMJ97VTba66[tl9cϽ\Bí@ůAůAŮAŮ@Ů@Į@Į@Į?Į?Į?Į>ĭ>ĭ=ĭ=ĭ=ì<í<í<ì;ì;ì;ì:ì:ì:ë9ë9ë9ë8¬8«8«7¬7ê7ª6ê6ª6«6ª5ª544200,E=bTDzwtutsrqpppoommmlkjihhgfhiYK= '#RGWK_Rn_n$DmKEOM_ly~zxurolifc`]ZWSNhicpz{zyMMMLLLLLLLLLLLLJJJ(YYY)YYYYYYYYYZZZYYYfeXV;:ROURTQSQSQTQTQTQSQSQTQTQTQTQTQTQSQSQTQTQTROL98VTba66[tl9cϽ\CĮAưBƯAƯAƯAƯAƯ@ƮAů?ů@Ů?Ů?Į?ĭ>ŭ=Ů=ŭ>Į<í=ĭ<Ĭ<ì<ì;ĭ:ĭ;Ĭ:Ĭ:ì9ì9ë8ì9¬8«7ë7«7ë7ª6«654531/-*J@<3,pzuuttssqqpppnmllllkjhiigidE:04- UIYMdVuew$ClJCMK]thomlkjjjigggffdccbbaa_]ukgu~~MMMLLLLLLLLLLLLJJJ(YYY)ZZZZZZZZZZZZYYYfeXV=;WUYWXVXVXVXVXVYVXVXVXVXVXVXVXVXVXVXVYVXVUSOL98VTba66[tl9cϽ\CĮAưBŰBůBƯBƯAůAŮAů@ů@Ů@Ů@Į>ĭ>ĭ>ŭ>Ů>Į=ĭ=ĭ=ĭ<ĭ;í;ì;í:Ĭ:ĭ:ì:ì:ī9ì8ë9ë8¬7ë7«7ë7ê65442/-~&UK/)%n|vvttttrqqqpppoprsrtuspmkl}_.'"D;WK]Pk\}l~#BkI@LJZgcq{xwwMMMLLLLLLLLLLLLJJJ(YYY)ZZZZZZZZZZZZZZZfdWU><[Y]\][][][]Z]Z][][][][][][][][]Z]Z][\[YWVSOL98VTba66[tl9cϽ\CĮAưCƯCŰBƯBƯBůBůAƮAƯ@ů@ů?Ư?Ʈ?Ů>Į>ŭ>ĭ=Į=Ů=ĭ<ĭ<Į<ĭ;ì;í;Ĭ;ī:ë9ì9ì9ë8ë9¬9«7ë7ª7ª65420.x%:3 E;0t|wwuuutssqqstvtg{_nUydKwcOtcTubOzeKmR{]krlS'"SGYLbTsdu!@jJ@EDG|hnnooooooooooooooooooooonohQVclkjjMMMLLLLLLLLLLLLJJJ(ZZZ)[[[[[[[[[[[[ZZZfdVU?>`]c`a`a`b`b_b_b`b`b`b_b`b_b`b`b_b_a^^[YWUSOL98VTba66[tl9cϽ\CůBǰDƯCƯBůCŰBŰAưAƮ@ůAŮAŮ@ů@Ů?Į?Į?ĭ>Ů=Ů=ŭ=Ů=Į=ĭ<Ĭ<Ĭ;ì;í;ĭ;í;ī9Ĭ9ì9ë9ì9¬8«766430-v%70r]~zxxwvvuttvxvgvdPRF96.%$  +$J=1zdMigUC  =5 WK[Oi\}l|>iKD@45ET8Qb;Qc=Se>Uf>Uf>Uf>Uf>Uf>Uf>Tf>Tf>Tf>Tf>Tf>Tf>Tf>Tf>Tf>Tf>Tf>Tf>Te>Te>Te>Te>Teĭ>ĭ>Ů=ĭ=ĭ=ĭ=ĭ<ĭ<Ĭ<Ĭ;ì;Ĭ;ì:Ĭ:ì9ì9«9«876530.u%60tcT~|yyyxwwvuzyg[N?+$  mZDd<2(NDYMbUtdt:ȻfV@@?ABBBBBBBBBBBBBBBBBBBBBBBB@|>\WCTTUsssMMMLLLLLLLLLLLLJJJ([[[)\\\\\\\\\\\\[[[fdVTBAihlkkikikikikjkilikikikikjkjljkigfb`]\YWUROL98VTba66[tl9cϽ\CůCǰDƯDǰCůBưBưBůBƯAƯAƯ@ůAŮ@ů@Ů?Ů@Ů?Į>Ů>ĭ>Ů>ĭ=ĭ=ĭ<ĭ=Ĭ<ĭ;ì;Ĭ;ĭ;Ĭ:Ĭ:ì9ì977631-qc-(  =5.zd~}{{zyxxxw}tbTF"w]oW91 WK]Pk\|l7^mmpqqqqqqqqqqqqqqqqqqqqqqqqrptǸ]gaARRTqqqMMMLLLLLLLLLLLLJJJ([[[)\\\\\\\\\\\\\\\fdVTCBmlqppnpnpnpnpnpnpnpnpnpnpopoonljgfb`]\YWUSOL98VTba66[tl9cϽ\CůCǰDǰDǰDưCǯBƯCƯCůAƯAůAůAůAŮ@Ů@ů@Į?Į?Į?ĭ>ŭ>ĭ=ĭ=ŭ=Į<Ĭ;Ĭ;í;ĭ;í;ĭ:Ĭ:ì9ë88742.na`SFy~|||{zyxy}jF<2 bRBnRC7NDYNdVte{2CLOQðRðRñRðRðRðRðRðRðRðRðRñRñRñRñRñRñRñRñRñRñRñRñRñRðRİPjŸbd^@PPRpppMMMLLLLLLLLLLLLJJJ(\\\)]]]]]]]]]]]]\\\fdVSECsqwtususututusustsusususvstrqoljgeca^\YWUSOL98VTba66[tl9cϽ\CůCDZEƱDƱDǰDƯDưDưCŰCŰCŰBƯBƯAůAƯAƯ@Ů@Ů@Ů@Ů?Į?ĭ>Į>Ů=Į=ŭ<ĭ<ĭ<ĭ<ĭ<ĭ;ì:«:8742,_T-&!q^§~~}}}|{z~i90( $$$CBB[[[sssxxxssstttnnn///QD6m{]'!80 VK_Rn_p!&(*++,,+,++****)))))((((((('(9eƹbd^@OPQoooMMMLLLLLLLLLLLLJJJ(]]])]]]]]]]]]^^^]]]fdUSFEvu{yzxzxzxzxzxzxyxzxzxzxywvuqomjgec`^[YWUSOM98VTba66[tl9cϽ\DůDDZFǰEDZEǰEǰDưCưCƯCưCưCŰBůAƯAů@ů@Ů@ů?ů?ů?ů?ĭ?Ů?ĭ>Ů>ĭ=Į=ĭ=ĭ=Ĭ;Ĭ;«;:852,MC E<4pĩ~~}||~xI>5III@@@ eUElnhWCQFZNgY{j}9gƹbd^@OPQoooMMMLLLLLLLLLLLLJJJ(]]])^^^^^^^^^^^^]]]fdUSGF{z~~}~|~|~}~}~}~}~}~}~|{yvtqoljgec`^[YWUSOM98VTba66[tl9cϽ\DůEDZFưFƱEDZEDZDǰDưDưCƯBƯCưCƯBůAůAƯAů@Ů@ů@Ů@į?Ů>Į?Ů?ŭ>Į>Į=ŭ=ŭ=í;ì;«;964.KC cVJū~~}~{hT 999ppp!v[kma0) A8 YMbTsdx """"""!!! :gƹbd^@OPQoooMMMLLLLLLLLLLLLJJJ(]]])^^^^^^^^^^^^^^^fdTSIH~{yvtqnkjgeb`^\YWUSNL98VTba66[tl9cϽ\DůEDZFDZFǰFƱDDZDDZEưDưDǯCưCƯCưBůBŮAƯBů@Ů@Ů@Ů?į@ů?į?Į?ĭ>Į>Ů>Ů=ŭ=í;¬;:650NC  xiWĪ~LB8III^OAljjnfUD  ,% WK^Qm_q "#""#"!!! ! :gƹbd^@OPQoooMMMLLLLLLLLLLLLJJJ(^^^)____________^^^fdTRKI}zyvtqokjgec`^[YVUSOL98VTba66[tl9cϽ\DŰEDZFƱFƱFǰFDZEƱDDZEǰDưCưDưCưBƯCưBŰAƯBƮAŮ@Ů@Ʈ@ů@į@Ů?Ů?ĭ>Ů>Ů=ĭ=«<;960OF )$ yfūīv3,'"""3+$gojil~b*$ J@[OhZ|k"""####""!! ! :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(___)_______________fdTRLK}zyutqokjgec`][YVUSNL98VTba66[tl9cϽ\DŰEDzGƱGDZFƱFưEưEƱEưDưCưDǰCƯCưCŰBŰBƯBůAƯAƯ@Ư@Ů@Į?į@Ů?Į?Ů>ĭ>ì=<984[P /)%pȮêi& III#sYqklkkkTG8 =4 [NcUufz"####"#"""!! ! :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(___)___`````````___fdSQML}zyutqoljgeb`^[YWUSOL98VTba66[tl9cϽ\DŰFȲGDzFDzFƱFDZFDZFǰEƱEƱDưCǰDưDƯCƯBŰBůAƯAůAůAƯ@Ů@Ů@ů@Į@ŭ?Į>ĭ>=;:7vh% ;3-sɰêl("HGH{iVvnmlljmpU,& UJ_Spat!#####""""!"!! :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(___)```````````````fdSQNM}zyvtqoljgeba^\YWUSOM98VTba66[tl9cϽ\EŰGȲGȲGDzGDZGƱFƱEưFDZEDZEǰDưDǰCǰCưCƯCưBůBƯBůAƮAůAů@ů@ů@Ů?ĭ>í==;7~o'" D;3~ʱª{81+)))!!!saNuqnnmljmh90'MC]Qk\o!##$$####"""" ! :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(```)``````aaaaaa```fdSQPO}zxvtqoljheb`]\YWUSOL98VTba66[tl9cϽ\EŰGȲHȲHȱGDzFDZFDZFǰEǰEDZDDZEDZDǰCưCưCƯCưCƯBƯAƯBŮAů@Ů@Ů?Ů?ĭ?í>><:z+'" A92ʲëJ@7---n]KtrponmmljllZG D: \OfYzj} #$#$$$#""#"!!!!  :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(aaa)aaaaaaaaabbbaaafdSQPO}zyvtqokjgeb`^\YWUSOM98VTca66[tl9cϽ\EűGȳHȱHDZHȲGDzGDZFDZFƱEǰFDZEDZEưDưCƯCůBĮBĮBĭBŭAĭ@ì@ì?ì?ì?«>><<2?8<5-~̴Ĭª¨k[M RRR999 jZHuuqqqpnmlkow[3- XLcVufy #$$$$$$###""!"!!   :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(aaa)aaabbbbbbbbbaaafdRPRQ}zyutqokjgeb`^\YWUSOL98VTca77[vn:cν\EƱGȲHDzHȲHȱHȲGDZGDZFDZFDZFưEưEůDůCįCĮB¬BAA@@?>>><<;8YN 2,'z͵Į¬««ªèq&!SSS dUFvwsrqqqonmlmg;3,$SH`Spau"$%%%%$#$##""!"!!  :gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(aaa)bbbbbbbbbbbbbbbfdRPSR}zyvtqokjgeb`^\YWTSNM98VTcb::^yq=cν\EƱGȲIDzIDzHȱHȲHDzGDZGDZFưEůEįEíDCBA@?>=<;:::998ma#.(&y͵Ưìí¬ì««ªTI?###zyy  ZNDxxutsrqqponmlq`Q@OD^Rm^q#$$%%%$#####"""" ! !:gƹbd^@OOQnnnMMMLLLLLLLLLLLLJJJ(aaa)bbbbbbccccccbbbfdQPVU|{wvrpmlhfca_]ZXVSOM98VTcb@@dvCdν[FűHȲIȲHȲIȲHDZGƱGƱGůEĮE­DCBA?=;:987555434{m( "tζȱĮĮĭì¬ë«ªĩq)%! FFFG=6v|vuttsrqpponlr|hQ B9 \Oi[~m#$%$%%%$$$#"##"!!!! !:gƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(bbb)cccccccccccccccfdQOWV}{xvsqnligda_\ZXVSOM97VTcbGFk}Jdͽ[FƱHȳJȲIDzHƱHưGİFĮEDCB@><97431~0{/y.w-w-v,y-q*1+rb̶ɳůůŮĮîííìì««¨wgX /)$l}xwwuutsrpqpomo{_*# 7/ ZNfYzj~"$%&&%&$$$###"##"!"!! ":gƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(ccc)cccdddddddddcccfdTR??gfhgedcba_^]\\ZYXWVTTSRPPNMLLJJHHFEDCBA@@><:20UScbKKpNdͽ[FƱHȲIDzIDZHůGîGFDB?=:852{/u-q,}o+zl)wi(tg'sf&re&re%sf&E> g\RDz̶ŰƯůůůĮĮĭí¬ì¬«©¨dVI s^zxxxvuutsqqqpnnnB8.*# YLcUvf{!$%%&&&%%$#$###""""!! ":gƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(ccc)ddddddddddddccchffeIHHFIGIGIGJHJIKIKIKIKJLJLJLJLKMKMKMKMLNLNLNLNLMKfdfeJJoLdͽ[FưHȲJƱIįHFEC@<963{0s.|n+xl*sg(k`%cX"aV!_U ]S\R\QaV!MDMD>ϹƲƲŰưưůůĮĮĭíì¬ë¨n_RtdV}zyyxwvutsrqqqonqWI;!VKaSscx!$%%&'&%%%$$$###"""!! ":gƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(ccc)dddddddddeeedddUTgfdbfdfefegfgfhfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgfgelkUUA@jyFdͽ[EŰHŰJ®HFD@=:5~2w0~q,re)cW"VLH@D=72'#%! &! %! %! %! -( 60,ѺȳDzDzƱưŰůůůĮĮĭí쬫«ªziJ@9&""@70t_~|{zyxwvuutsrqqpopl[I KA_Roat!$&&&&&%&%%%$#####""! !":gƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(eee)eeeeeeeeeeeeeeettddSSFF{>>s::o88m88n88n88n88n88n88n88n88n88n88n88n88n88n88n88n88n88o33n88Owo@;cͻ[E­GHEB>:7}3s.vi*[Q B;0* sѼʵȳdzȲDzƲƲƱŰƯůůĮįĮíí¬¬«ªrzdm~~}||{zzxxwvutsrqqqrkS C:^Rm^r!$&'''''&%%&%$$$#"""""! #;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(fff)eeefffffffffeeeſu]vpKkd?e_9c\7c\7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7c]7d^9d]:D̾d˹ZDFEA<95~p-fZ%C;*%aUJιкɴɳȳȳȲDzDzDzƱŰŰůŮįĮĮĭì¬ë«~~}||{zyxxwvttsrqqrf'! <3 ^Qj\p $&&''''&&&%%%%%####""" #;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(fff)ffffffffffffeeeŝƹd̿gʽeȻbƸ`ķ^Ķ^Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ]Ķ^Ķ]µ\ǹakIJVAB?:6xk-XN -) %!/+&<6093.,'#\RIıмɵʴɴɴȳȳȲDzDzƲƱưůůůįĭíì¬ì«ª~|||{yxyxwuttsqqsm1)!2* ^QhZ~n $&'''''&&&%%%$%$$####"!$;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(fff)fffffffffgggfff˜iiп__`````````````a``aaa```п_̽]ŴXH=>:u1WN (#  *&#QIBth^yðȵǵyXOG mbWɵкʵʵɵɴɳȳdzDzƲƱƱưƯůůĮĭíìì뫪}}}|zyxxxvuttrqsm9/%0* ]QgY}l $&('(('''&&&&%%$$$$"##!$;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(fff)fffgggggggggfffÛkͽ\HJKKJJJJJJJJJJJJIIIIIHHGFDA<:~5bW%1, NGAwjϼŮĭŭŭĬĬĬŭͺu0+(|oҽ͹ɶʶɴɳɳȳDzDzDzƲűưƯůůĮĭĭì«ë«ª~}}}{zyxxwvutsrrpL@8)$ XLfY|k $'(()((('&&&%&%%%$####!$;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(fff)gggggghhhhhhgggÛjʺZHƲPȵSȴRȴRȴQȳQdzPȳQȳPdzODzODzODzODzOƱODzNƱNƱNűMƱLŰLİK®JHEA75/+ԿʷʶʶʵɵɴȳȳȳdzƲƲƱŰŰůůĮĮìì¬ì}}|{zyxxwvttssr\OD PFgYzi~ $'((()((''&&'&%%%%$#$#"$;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(fff)ggghhhhhhhhhgggÛj˺ZKʶU͹X̸W̸W̸V̷V̸U̷U̷U̷T˷T˷T˶S˷S˷S˶R˶R˶RʶR˶PɴPdzO®MIF?oc+)$VNHμɳǰ«ϾϾпϾоϽнϼϽλѿɰC<6cYO͹лʶʶʵɵʵɴɳȳȳDzDzƲƱưƯůůĮíí쬫ªª~~}|{zyywvutttrbQ? NDfYxh} $()())(((('''&&&%%$$$#"%;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(hhh)hhhhhhhhhhhhhhhÛj˺ZKɵU̸W˸W˸V̷V˷U˷U˷U˷U̶T˷S˷SʶSʶS˶S˶R˵QʶRʵQɴOdzO¯NJF8}ϽʴDz­ѿппопоϾнϽϼλѿɰ2,)!̸ʶʶʶʵʴɴɴȳȳDzDzDZƱŰůůįĮĭìì쫪~}}|{zyxwvutusfU@ ODeXvg| %')())()('(''&&&%%%$$$"%;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(hhh)hhhiiiiiiiiihhhÛj˺ZKɶU̸X̷W̸V˸V̷V̷U̷V̷U̷U˶T˷TʶSʶSʶS˶R˶RʶRʵQȳOŰNKH>NE"vlcó˵ȲîѿѿѿпопоϾϽϼμƯ{^TLλѽ˷˷˷ʶɵʵɴɴȳȲȲDzƲŰưůůĮĮĭì¬ë«ª}}|{zxyxwuttvq_K NDdWuez$')))*)((('('''&%%%$$$#%;fƹbc^@NOPnnnMMMLLLLLLLLLLLLJJJ(hhh)iiiiiijjjjjjiiiÛj˺ZKʶV͹X̸W̷W̸W̸V˸V̸U̷V̷U˷U˶U˶T˷T˷TʶSʶRʵRȴQűOLJ?KB @:6dz˷Ű®­­­­ѿѿппϾонϼª«yma $ ͹˸˷˷ʶʶɵʵɴȴȳȳȳƲƱưŰůįĮĮí¬ìì~}}}|zyxxvuuwyfS MCdWtez $(*****)(()'''''&%%%%$$&;fƹbd^@NNPmmmMMMLLLLLLLLLLLLJJJ(hhh)iiijjjjjjjjjiiiÛj˺ZKʶV͹Y̸X̷X̷W̸W̷V˸V˷U˷V̷U˷T˶U˶T˷S˶SʶRʵRƲQOLDNF  ZSM͸ɴŰİİİïïî®î­ѿппϾонĭ˸WOH uj^ϼ̸̹˷ʶʶʶɶɵɴɳȳȳDzDZƱưŰůůĮíììì«~}||{zyywvuxlX E=eXte{ %(***+))))((('(&&&&%%%$&;fƹbd^@NNPmmmMMMLLLLLLLLLLLLJJJ(jjj)jjjjjjjjjjjjjjjÛj˺ZKʶV͹Y̹X̸W̷W̷X̷W˸V˷V˷V̷U̷U˷T˷T̷T˶SʵSȳRðPOGYO# of]̼ϻȴűűıűŰİİðïï®­­­¬ѿппоϽоȰ.*%@:4͹̹˸˷˷ʷʶʵʴɴȴȳdzDzƱƱŰƯůĮĮĭ쬫ªª~}}{zyywvuymZA9gYuf{!&(***+****))(((&''&&&%$&;fƹbd^@NNPmmmMMMLLLLLLLLLLLLJJJ(jjj)jjjkkkkkkkkkjjjÛj˺ZKʶV͹Y̹X̸X̷X̷X̷V˷V˸W̸V̷V̷U˷U˷U˷UʶSɵSŲQðOH]T& wmǴϺdzƳƳŲŲűűűıİİİïî®®­¬¬ппоϾsgwĬͻ̸̸̹˷˷ʶɵʵɵɴȴȳȲDzDzűŰůůĮĭííë««~}|{zyxwvy}kXB9h[xi}!&)+*+++**)*())(''&&&&%$&;fƹbd^@NNPmmmLLLLLLLLLLLLLLLJJJ(jjj)kkkkkkkkklllkkkÛi˺ZLʶW͹Z̸X̸Y̸X̸W̸X̸W˸W˸W˸V˷V̷U̸UʷUʵSdzRűQNod.{qʸκǵǴȵȵǴƴƳƳƲŲűűıİİİðï®­­­ѿѿϾ«ñKC=cZQͺҿ͹̸̸̸̺˷˷ʶʶʵʵȳȳDzDzDZƱưưůįĮĮì¬ì«~}|{zxxwy{hU C:i\zk"'*+++,****)*))(('('&&&%' sjbɷѾɸɷɷȶɶɶȵȵȵȴǵǴƴƳƳƲűűŰŰİïï®­­­ѿооi_V~Ĭϼͻ̺̹͹̸˸˷ʶʶɶʵɴɳȳDzDzDzƱưůůįíììɲʲǯǮ}}|{yyyzudP NCj\}l$'*,,,,,++*+**))((((('&&(6-s_Ǯ~}}|zyzyjYF RGj]~m$(+,,,-++++*+***(((('''&(a]NlgVlfUd^MZUCTO=RL;QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:QL:SNT8F2;61v]Оyӡ{إ~٦ۧܨܨܨܨܨܨܨܨܨܨܨܨܨܨܨܨܨܨܨܨݩߪqZIHH```LLLLLLLLLLLLLLLJJJ(ttt)tttttttttttttttši˺ZN̹^ϼaμ_μ_λ_λ_κ^λ^̹]ѽ_S=7Ͽξνͽͽͼ̺˺˹ʸʷȷȶȵǴǴƳŲűİðîîѾϾϽϼμλͻͺ̸̹˸˷ʶʵɵɴȴȳDzƲƱŰůůĮĭ¬ì«ª§u.)% Z=H5<82y_ΝxnmoonnnonnnnooooooooooonʚvۨoYGFF^^^LLLLLLLLLLLLLLLJJJ(ttt)ttttttuuuuuutttši˺ZN̹]ϼaϻ`ϼ`ϼ`μ_κ_λ^͹]Կ`L!*'%ƻϿξννͼ̻̻˹˸˸ɷȶȶȵǴƳƲűıİįî­ѿоϾнϼμλͺ͹̸˸˸˷ʶɵɵɴȳDzDzDzƱůůĮĮì«««Īj /!aAL7>;4}aΝxi‘nɘrƖqŕpŔoēnÓm’l‘lkkjiihggfeedcc•rۧoYGFE]]]LLLLLLLLLLLLLLLJJJ(ttt)uuuuuuuuuuuuuuuši˺ZN̹]ϼaλ`ϻ`ϻ_λ_λ_ͻ^λ^м^{= B=;ʾϿϾξͽͼ̻̺˹ʸʸɷɶȶǴǴƳŲűŰİï®­ѿпϿϾнϼλλͺ̸̹̹˷ʶʶʵɴɴȳDzDzƱƯůůĮí¬ì«rbT?*$iFO9A=6dПzkЛvڣ{סy֠x՟vӞuќtЛsϚrΙq̗q˖oʕnȔmǓlőjđjÏiŽgfedcÕrڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(ttt)uuuvvvvvvvvvuuu™i˺ZN̹^ϼbϻaϼ`λ`ϻ`ϼ_λ_ϼ_˸\od2 [TRϿϾνμͼ̻˹ʸʹʸɷȵǵȵǴŲűŰİ¯í­¬ѿппϾϼϼμͻ͹͹̹˸˷ʶʶɵʴȳȳDzDzŰưůůíí¬ìE<4 J2&oK"Tkפ~mաzߩۥ}ڤ|٤{أz֡yՠxԟwӞvќuЛtϚsΚr͙q˗pʖoɕnȔmƒlŒkŐjg•rڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(www)wwwxxxxxxxxxxxx™i˺ZOͺ`нcмbнbϽbϽbϼaϻ`ҿb|@ Ͼνͼͼ̻̺˹˸ʸɷȵǵǴǴŲıűİ®¬ѿонϽμλͺ̹͹̸˸˷ʶʵɴɳȳDzDzƱŰůįĮĭ¬ì«ªȯqcT  I3+lK)sM1_*gKIF?kפ~m֢z᪀ݦ~ۥ}ڤ|٣{עy֡yՠxԟwҝuќuЛtϚsΙs̘q˗pʖoɕnǓmƓlƒkg”rڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(www)xxxxxxxxxxxxxxx™i˺ZOͺ`нdнcнcϼbнbϼaλaҿb~A пϾνͽͼ̻˹ʹʸɸȶȵȵǴŲűŰݯ­­ѿоϾнϼλλͺ͹̹˹˷˶ʶɵɴȳDzDzƱưŰįůĮí쫪ƮE<5 +dG-rO+zQ3b+jMJG?kפ~mף{⫁ިݧ}ۦ}ۤ|٣zעyסyՠx՞vӝvќuМtϛs͙r̘q˗pʖoȔnǓmǓlh”qڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(www)xxxxxxyyyyyyxxx™i˺ZOͺaнdϽdϼcнbнbϼbϼbcB ξνμͼ˺˹˹ʸɶɶȵǴƳŲűűİ®­ѿпϿϾϼμλͻ̹͹̹˸˶ʶɵɴɴȳDzDzƱŰůůĮ쬫«˳n/!3wU0yU-V5e-mNJG?kפ~mף|㬂ߩާ~ܧ~ܦ}ڤ{٣{آz֡yԟwԞwҝvѝuМtϚr͙r̘q̗pʕoȔnȓmh”qڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(xxx)yyyyyyyyyyyyyyy™i˺ZOͺaоdнdмdϼcнbϼbϼbӿcB  Ͼνμͼ̻˺˹˹ɷȶȵȵƳƲűűðî­­пооϼϼλλͺ͹͹̸ʶʶʶɵɴȳDzƲƱƯůįĮí¬ì«Ŭŭg[M &W>8^3Y.Z6h-nOJH?lפ~mؤ|䭃઀ߨިݧ}ۥ|٤|أ{עyՠy՟wԞwҝvќuЛsΚr͙r͘q˖oɕoɔnh”qڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(yyy)yyyzzzzzzzzzyyyi˺ZOͺaѾeнdмdϽdнcнcϼbӿcB ϾϽνͼ̻˺˹ʸɷȶȶȴƳŲűŰïî­¬ѿѿонϽϼμͺ̺͹̹˸ʶʶʵɵȳȳDzDzŰƯůĮíììëªʱ.)#$3qQ=d5^0\7j.pQKH@lפ~mڦ~殅⫂᪁઀ߩݧ}ۦ}ڥ|٣{ףyסy֠xԟwӞvќuМtϚsΙr̘q˗p˖oi”qڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(yyy)zzzzzzzzzzzzzzzi˺Z®PͻbоeмeнdнcϼcнcмcӿdB ξνͼ̼̺˺˹ʸɷɶȵǴƳŲŰİï®­ѿпϾнϽϼͻͺ͹̸̹˶ʶʶɵȳȳdzƲƱưůůíĭì«Ŭɰ|l^  F2;^@j9d2`8l.qRKH@lפ~mۦ~诅㬃⬂᪁઀ިݧ~ܦ}ڤ|ؤ{آz֡yՠxԟwӝuѝuЛtКsΙr͘q̘pj”qڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(yyy)zzzzzz{{{{{{zzzi˺Z®PͻbоfнeнdϽdϽcнcмcdC ~zϿϾͼͼ̻˺˹˹ʸɶȵǵǴƲűİïî­ѿϾнϼμλͺ̹͹˸˷ʶʶʵɳȳDzDzƱŰưůĮĭí¬ɱ?72 .dI@gDq;i3b8m.qRKH@lפ}mܧ鰆䭄㬃⫂᪁ߩިܧ}ۥ}٥|٣{آz֡y֠xԞvӞvҝuќtϚrΙqΙqjqڧoYGFE]]]LLLLLLLLLLLLLLLJJJ(zzz)zzz{{{{{{{{{{{{i˺ZPͻbѾfѾeоeоeоdнcмcdC qmiονμͼ̻˹ʸʸɷȵȴǵƳƲİİï®ѿпоϽϼμͻ͹͹̹˷˶ʶʵɴȳȳDzƱŰƯůĮíìŮʹzh;+>^DlIw>m4d9n.qRKH@lפ}mܩ겇宄䭄㬃⫂઀ߩިܧ~ۥ|ڤ|٣zآzסy֟wԞwӞvќuЛsϚrϚrkrڧoYGFE]]]LLLLLLLLLLLLLLLJJJ({{{){{{{{{||||||{{{i˺ZPμcѿgнfоfоeнeоcнceC [WTϾννͼ̺˹ʸʸɶȵȵǴųűİïîпонϼμλͻ̺͹̸˷ʶɶɵɴȳȳDzƱŰƯŮĮíɳJ@8 1dKDiHtL|@o5f9o.rRKH@lפ}mު봉簆毅宅䭄⬂᫁઀ީܧ~ۥ~ۥ|ڤ{٣{סyՠxԟwӞwҜuќtМslrڦoYGFE]]]LLLLLLLLLLLLLLLJJJ({{{){{{||||||||||||i˺Z®PλcѾgнeнfоfнeϽdϽdfC D??ονͽν̻˺˹ʸɷȵȵȴdzűİİï­­ѿпϾнμμͻͺͺ̸˷˶ʶʵɴȳȲDzƱưƯįĮůͶ|i:,AbHoLyOAr5f9o.rRKH@lפ}m߫쵊籇簆毅宄㬃⫂᫁઀ިݧ~ۦ}ۥ}ڤ|آzסy֠x՟wӝvӜuҝtmrڦoYGFE]]]LLLLLLLLLLLLLLLJJJ({{{)|||||||||}}}|||i˺Z®PλdѾgѽfѽfѽeоfнeнef~B -+*Ͽξνͽ̻˺˹˸ɷɶȵȵǴŲŰűį®­поϾнϼλͻͺ̹̹˷˷ʶʵɴɳȳDzDZƱŰůĮ̴G>4 5iOHmLvPPBs5f9o/rRKH@lפ}mૃ貇籇氅毅䭄㬃⫁᫁ߩި~ܧ~ܥ}ۤ|٤zآyסyՠxӞwӝvӞumrڦoYFFE\\\~~~LLLLLLLLLLLLLLLJJJ({{{)||||||}}}}}}|||i˺Z®QμdѿgѾgѾfѾeнfѾdнdgI!Ͽξνͻ˺˹˹ʸɷȶȵƴƲűűİî­ѿппϾϼμͻͺ̸̹˷˷ʶʵɴɴȳDzƲƱŰůưϷxi<-FfMsQ}SRBs5f:o.rRKH@lפ}mᬃ﷋鳈鲈豇簆宅䭄㬃⬂ઁߩިݧ~ۦ}ڤ|ڣz٢zסy՟w՞v՞vmrڦoYGFE]]]LLLLLLLLLLLLLLLJJJ(|||)}}}}}}}}}~~~}}}i˺Z®QϽeiѿhѿgѿgѿgѾfѾfg\62Ͽξͼͼ̻˹ʸɷȶȶȵƳŲııï®ѿпоϽϼλͻ͹͹̸˷˷ɶʵɴȴDzDzƱƱŰ̶A94 9mRNrR{UUSCt6g:p0sTMJBl֤}m⮅봊곉賈貈氆毅宅䭄⬂᫁઀ީݧ~ܦ}ۥ|ڤ{أzסy֠xՠxnrڦo[JIH___LLLLLLLLLLLLLLLJJJ(}}})}}}}}}~~~~~~}}}iʺZ®QνfjѿhѿgѿhѾhѾgѾghƵa<7 xsoϿϾνͼ̻˺˸ʸɷȵȵƳŲűŰï®­­понϼμλͺ̹̹˸˷ɶʵɴɳȳDzDzűɳζvh\ %E5JkSyVXWTŠCu6g:p2uUROGn֤}m㮅쵋뵊볉鳈籇氆毅宅㭃⬂᫁઀ߨݧ~ۦ~ۥ|٤{آzءyסy’o”r٦s]RRQgggLLLLLLLLLLLLLLLJJJ(}}})~~~~~~~~~~~~ši˺YJðVƳXŲXŲWƲWŲWŲWŲWȴXSOG!TQPϿνͼͼ̻˹ʸɷȶȵdzƲűűï®­¬ппнϼμλͻ̸̹̹˷ɶɵɴɳȳDzDzDZй,'%%E|`V{Y\\ZŎUŌDv6g9o6yZ[WPo֣}n汇︍︍ﶌ봉鳈貇豆毅宄䭃㬂᫂ੀߨާ~ܦ}ڥ{ڤ{ڣ{Ĕp”rإydcbbuuuLLLLLLLLLLLLLLLJJJ(}}})~~~~~~~~~™jbƲQųRųSųSųRųRųRƳSƴSȵTǵSsi1 865Ͽννͼ̻˹ʸɸȷȶǴƳƲűİïî­ѿоϽϼμμͻ͹̸̹˷ʶɶʵɴȳȲDzͷDZZOE*Mk>l=l1Q@1RA2RB2SB2SB2SB2SB1RA2SC9PESRO{mbwƶͽϿϿϿϿϿϿϿϿϿϿϿϿϿϿϿϿϿϿϿϾϿͼLLLLLLLLLLLLLLLJJJ()ƀx٦إ~פ~٥٦密tY ea`пϾξν̻̺˹ʹʸȶȵǴƳűűİîоϾнϽλͻ͹̸̹˷ʶɵʵϹs 667JIKQNQWTWZWZ\Y\]Y]]Y]]Y]]Y]]Y]]Y]^Y]^[_TRTJIJ___LLLLLLLLLLLLLLLJJJ()Ɓ›|գ|pkmmÕrw[%ϿϾνͼ̻˹˸ʸȶȵǴǴŲıİï­¬поϽмϼͻͺ͹̹˷˷ʶѼ2-'AAAzx{trvIII[[[|||LLLLLLLLLLLLLLLJJJ()ƁÛ|ҡ{lŕpΛu̙s͚sŔnT>0lhgϾνͼ̻˺˹ɸɷȵǵǴŲűİï­­ппϾнϻͻͺ̹̹˷ʶҼ=72(((ggiuuxFFGXXXyyy~~~LLLLLLLLLLLLLLLJJJ()ƂÛ|ҡ{nМvۥ|آy֠xߦ{wYBϿϽͼ̻˺˹ɸɶȵȵǴƲűŰį­поϾнϼͻͺ̹̹˷ҽG@7 bacyy{tsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƂÛ|ҡ{nϜuڤ{סyՠxܥ{pS XSPϿξͼ̼̺̹˹ɷȶȵǴƲűűİ®­¬ѿоϾϽϼλͺ͹͹ҿSLCa_btsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƃÛ|ҡ{nѝwܦ}٣{סyڤ{i<,!Ͽξμͼ̻˺˹ɷɶȵǴųűİİî­­ппϾϽλͺκԿKC< POPtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƃÛ|Ҡ{nўwܧ~٤|آz٢zڤzlQ2//Ͼμͼ̻˺˹ɷɶȵǵƳŲűİ®­­ѿпоϾϽλѽ?94 GGHtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƃ›|Ҡ{nӟxިۥ|٣{آzܥ|ՠxcJ8LHFϾνͽ̼˹˸ɸɶȵȵƳƲűŰï®пооҿŭλr0+' IIJtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()Ƅ›|Ҡ{nӠyީۦ}ڤ{٤{٣zާ}e5(e`]Ͽνͽ̼˺˸ʸɶȵȴƳƲűűï­¬«ưĭf\SCBCtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()Ƅ›|Ҡ{nԡy઀ݧ~ۥ|ڤ{٣{ڤ{ާ}uX& lihϿνͼͼ̻˹ʸɷȵȵƳŲűŰïįįůDZʳíuj72- A@AtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƅ›|Ҡ{nբz⬁ީݧ~ܦ}ڤ|٤{ۥ|ާ}eL  ]ZXϿνͼͼ̺˹ʸɷȶǵdzƲƲȴʵʴ˵ȳ~nd[940 VUVtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƅ›|Ҡ{n֢|㭃ߪިݧ~ۦ}ڥ|٤{ާ}МtgM9 GDBξͽͼ̺˹ʸʸɷʸͺлιɵ®tf]T?95"!!mlmtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƅ›|Ҡ{nפ|䮄ુߩިܧ~ۦ}ڥ|أ{ߨ}ΜtgM9 '%$ξͼͼͼμнмðvldKE?+'$ 223tsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()ƅ›|Ҡ{n٥}宅᫂઀ߩݨܧ~ۦ|ڤ|٣{ި~̚thO;  SPN˺{p[TM4/, WWYtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()Ɔ›|Ҡzoڦ~籆㭄⬂᫁ߪީݨܦ}ۤ}أ{ݧ}ўwhO$^ZX|r`XR=84  $$#ggjtsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()Ɔ›|Ҡzoڧ貇䮅㬃⫂ઁߪݩݧ~ܦ}ڥ|٣{ݦ}ݦ}uX4'KIG¿ʻun^WPA<7%!  ZU/qh5GE?yytsvFFGWWWxxx~~~LLLLLLLLLLLLLLLJJJ()Ƈ›|Ҡzoۨ鳈寅䭄㬃᫂ઁުިݧ~ۦ}ڥ}أ{ڤ{~fN;,  #!!QMKɼŻxpaXQC>;($!  '#^T";̿fKFD>wxtsvFFFVVVwww~~~LLLLLLLLLLLLLLLJJJ()Ƈ›|Ҡzoݩ봉簆宅䭄㬃⬂᫂ߩިݧ~ۦ~ڥ|أ{ڤ|Λt~^G'2//SPNjdc|yƿżǿûŽyrjf`ZUNID4/-  $ LEt4HHıLnKFD>xztsvFFFVVVwww~~~LLLLLLLLLLLLLLLJJJ()ƈ›|Ҡzoޫ鲈簆毅宅䭃㭁᫁ઁߩݨܧ~ۥ}ڣ{٣zާ}ݦ|b[D2  ,)(31/853>;9A=@=:97421.0/,*'& %!OG |o3@İP͸SлTïKImMGE?z{tsvFFFVVVwww~~~LLLLLLLLLLLLLLLJJJ()ƈ›|Ҡzo߫鳉豇簆寅宅䬄㬂᫂઀ީݧ~ݦ}ۥ}٤{آyۤ{ҝuhM>-"   3.^T(x8DNѽUкUθS˷R˶S­JKnMGE?z{tsvFFFVVVwww~~~LLLLLLLLLLLLLLLJJJ()ƈ›|Ѡzo᫃︌괉鲈豇氆密䮅㬃㬂᫁ߪިݧ~ܦ}ڥ}ڤ{٢zآzܥ|ڤ{Òm}^G5(   ($A:bX){o4ENƱSѻWӽXιU˶S˶SʵR˶R̷S­KKnMGE?z{tsvFFFVVVwww~~~LLLLLLLLLLLLLLLJJJ()Ɖ›|Ѡzp⬄쵊곉鲈豇簆密䭄䭃ᬃૂߩިݧ~ܦ~ڥ|ڣ{أz֡y٣{ަ}˙sflR?1'  #!/+IB]T)nc0>HűT͸WͺVҾXҽXϺW̷U˷T˶T˶SʶS˶S˶S̸T®KJnMGE?z{tsvFFFVVVwww~~~LLLLLLLLLLLLLLLJJJ()Ɖš|Ѡ{p⭅촊볉鲈豇识毅宄㭃ᬂઁߩިܧ~ۥ}ڤ|٤{أz֡yآyƖqɚv宆r]FC4c\0GB"   # >8H@ [Q(r7x;FKSӿ[ҽZҽZҽZѼYϻYκX̸V˶U˷U˷U˷U˷U˷U˷U˶SʶT̸T®KJnMGE?z{ttvGGHXXXwww~~~LLLLLLLLLLLLLLLJJJ()Ɖ›}џzp將﷌쵊봊겉鲇谆篅宅㭃⬂᫁ߪݨ~ݦ~ܥ}ڥ|٣{ڤ{ĔpÕqܨwdlhN]ô[At;e\2HB#51'#         $!4/3-:4aX,i_/}q8GLRSƲW__]Կ\ѽ[ϻZϻZͺX͸X˷X˷W˷X̸W̸W̸V̷V̷U̷U˶U˶T˶U˷T̸U®KJnMHFAz{wvxMMM^^^{{{~~~LLLLLLLLLLLLLLLJJJ()Ɗ›|Ҡzo٧粉㯆⭅ᬄଃ߫ުݩܨۧڦ٥}٤}أ|ע{աzԠyӟxҟxНvўvmqإ~~lzu^bd̸Sϼaнgʷbij`R}By@{Bx@g^4QJ(PI&PI%PI&]U/}sy>y>x=y>KXXXʷ\˸\л^``Կ^Ҿ^Ѿ]λ\λ\κZͺZ͹Z͹Z͸Z͹Z͹Y͹X̸X̸X̷W̸W˸V˷W̸U̷V˷UʶU˷U˶T͸UîKJnOLJE}|{{}XXXiii~~~LLLLLLLLLLLLLLLJJJ()Ɗ|ӡ{pqŗtŖsĖsĖsĖsĕsÕrÕrÕr”q”r”qqqqppppopmǗtף}xuea®Oͻ`jiihhhgfffeҿdҾdҿddccccbbbbbԿaѾ`Ѿ_м_λ]λ]ͺ\ͺ\κ[κ[ͺ\ͺ[̹[ͺZ͹Z͸Z̹Z͹X͹X̹Y̹X̸W̷W˸W˸W˸U̸U̷U˷U˷U˶U͸VîLKmQVTNnnn~~~~~~LLLLLLLLLLLLLLLJJJ()Ɗ™{֣ۧ~Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{Ѡ{ѡ{ҡ{ҡ{ҡ|ҡ|ҡ|ҡ|ҡ|ҡ|ҡ|٦إ}Ĺj`®P͹akhhiihhhggggffҿeѾdҿdҾdѿcѾcѾcѽbмaн`м`ϼ`м`ϼ_ϼ_м_ϼ_ϼ_ϻ]ϻ]ϻ]ϻ]λ\λ\λ\κ[κ[κ[κZκZκZιYιY͹Y͹X͹W͹X͸W͸W͸W͹VκWįNKlVhf`~~~LLLLLLLLLLLLLLLJJJ()ƋuϞxҠ{џzџzџzџzџzџzџzџzџzџzџzџzџzѠzѠzѠzѠzѠzѠzѠzѠzѠzѠzѡ{ʚvȼnο`K¯UǴ[ƳZƴZƳZƳYdzYƳYƳYųXųXƳXŲXųWųWƳWŲVƳVƲVųVŲUŲUŲUŲUŲTŲTűTŲTŲSıSűSıSıSİSİSİSİRİRİRİQİQİQİPİPİPİPįOįOïOïOïNïNîNîNïNïMİNFIk^y~~~LLLLLLLLLLLLLLLJJJ()Ƌ®¬¬¬¬¬¬¬¬ǹīʾodİNIKKKKJJJJJJJJJJJJJJJKKKKKKKJJJJJJJJJJJJJJJJJJJJJJJJJJKKJKHƲPlf~~~LLLLLLLLLLLLLLLJJJ()Ƌǫƹfkihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgkmb~~~LLLLLLLLLLLLLLLJJJ()Ƌ͸övĸoźqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqŹqƹrƹrƹrƹrƹrƹrƹrƹrƹrƹrƹrƹrƻrķnx}}}LLLLLLLLLLLLLLLJJJ()ƌ}}}LLLLLLLLLLLLLLLJJJ()ƌ}}}LLLLLLLLLLLLLLLJJJ()ƌ}}}LLLLLLLLLLLLLLLJJJ()ƍ}}}LLLLLLLLLLLLLLLJJJ()ƍ}}}LLLLLLLLLLLLLLLJJJ()ƍ}}}LLLLLLLLLLLLLLLJJJ()ƍ}}}LLLLLLLLLLLLLLLJJJ()Ǝ}}}LLLLLLLLLLLLLLLJJJ()Ǝ}}}LLLLLLLLLLLLLLLJJJ()Ǝ}}}LLLLLLLLLLLLLLLJJJ()Ǝ}}}LLLLLLLLLLLLLLLJJJ()Ə}}}LLLLLLLLLLLLLLLJJJ()Ə}}}LLLLLLLLLLLLLLLJJJ()Ə}}}LLLLLLLLLLLLLLLJJJ()Ə}}}LLLLLLLLLLLLLLLJJJ()Ə}}}LLLLLLLLLLLLLLLJJJ()Ə}}}LLLLLLLLLLLLLLLJJJ()Ɛ}}}LLLLLLLLLLLLLLLJJJ()Ɛ}}}LLLLLLLLLLLLLLLJJJ()Ɛ}}}LLLLLLLLLLLLLLLJJJ()Ɛ}}}LLLLLLLLLLLLLLLJJJ()Ɛ}}}LLLLLLLLLLLLLLLJJJ()Ɛ}}}LLLLLLLLLLLLLLLJJJ('Ð|||LLLLLLLLLLLLLLLLLL'oooLLLLLLLLLLLLLLLNNNYYYKKKLLLLLLLLLLLLUUUc𑑑rrrMMMLLLLLLLLLLLLKKKjaaaLLLLLLLLLLLLLLLKKKLLLT鑑~~~~~~}}}||||||{{{{{{zzzyyyyyyxxxwwwwwwvvvvvvuuuttttttsssrrrrrrqqqqqqpppoooooonnnnnnmmmllllllkkkjjjjjjiiihhhggggggffffffeeeddddddccccccbbbaaaaaa```______^^^^^^]]]\\\\\\\\\\\\[[[ZZZZZZYYYXXXXXXWWWWWWVVVUUUUUUTTTSSSSSSRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPJJJJJJLLLLLLLLLLLLKKKJJJZIIIx~~~}}}}}}|||{{{{{{zzzzzzyyyxxxxxxwwwwwwvvvuuuuuutttssssssrrrrrrqqqppppppooonnnnnnmmmmmmlllkkkkkkjjjjjjiiihhhhhhgggffffffeeedddccccccbbbbbbaaa``````______^^^]]]]]]\\\[[[[[[ZZZZZZYYYXXXXXXWWWWWWVVVUUUUUUTTTSSSSSSRRRRRRQQQPPPPPPOOONNNNNNMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKIII z哓~~~}}}}}}|||{{{{{{zzzzzzyyyxxxxxxwwwwwwvvvuuuuuutttssssssrrrrrrqqqppppppooonnnnnnmmmmmmlllkkkkkkjjjjjjiiihhhhhhgggffffffeeedddccccccbbbbbbaaa``````______^^^]]]]]]\\\[[[[[[ZZZZZZYYYXXXXXXWWWWWWVVVUUUUUUTTTSSSSSSRRRRRRQQQPPPPPPOOONNNNNNMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL Q~~~}}}}}}|||{{{{{{zzzzzzyyyxxxxxxwwwwwwvvvuuuuuutttssssssrrrrrrqqqppppppooonnnnnnmmmmmmlllkkkkkkjjjjjjhhhhhhggggggfffeeeeeedddccccccbbbbbbaaa``````______^^^]]]]]]\\\[[[[[[ZZZZZZYYYXXXXXXWWWWWWVVVUUUUUUTTTSSSSSSRRRRRRQQQPPPPPPOOONNNNNNMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKLLLWLLLV˕䕕䖖䗗䗗䘘䘘䚚䚚䛛䛛䜜䜜䜜䝝䝝䞞䟟䟟䟟䠠䠠䠠䠠䟟䟟䞞䞞䝝䜜䜜䜜䜜䛛䚚䚚䙙䘘䗗䗗䖖䕕䕕䕕䕕䔔䓓䓓䒒䑑䐐䏏䏏䎎䎎䍍䍍䌌䌌䋋䋋䉉䈈䇇䇇䆆䆆䆆䅅䅅䄄䃃䂂䁁䁁䀀~~~}}}}}}|||{{{zzzyyyyyyxxxxxxxxxwwwwwwvvvuuutttsssrrrrrrqqqqqqpppppppppooonnnnnnllllllkkkjjjjjjiiiiiihhhhhhgggfffeeeddddddcccbbbbbbbbbbbbaaa``````___^^^]]]\\\\\\[[[[[[[[[ZZZZZZYYYXXXXXXVVVVVVUUUTTTTTTSSSSSSSSSRRRRRRQQQPPPOOONNNMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKJJJ_KKK!LLL??(       }}}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&|||  ppp%-------------------------------------------------------------------------------ooo$  $&(fff.6666666666666666666666666666666666666666666666666666666666666666666666666666666eee.(&$  ,,,BBBQGGGGGGFFFEEEDDDDDDBBBOOO]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]NNNBBBDDDDDDEEEFFFFFFDDDw8880AAAJJJLLLLLLLLLLLLLLLLLLLLLLLLLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKLLLLLLLLLLLLLLLLLLLLLLLLKKKEEEV>>>JJJLLLKKKMMMQQQQQQQQQQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPKKKLLLKKKEEE@III>LLLKKKdddPPPLLLKKK000 KKKtLLLLLLkkkJJJKKKBBB KKKLLLOOOwwwJJJKKKBBB*KKKLLLOOOwwwJJJKKKBBB+KKKLLLOOOwwwJJJLLLCCC*KKKLLLOOOwwwJJJLLLDDD)LLLLLLOOOwwwJJJLLLHHH(LLLLLLOOOwwwJJJLLLJJJ&LLLLLLOOOwwwJJJLLLKKK&LLLLLLOOOwwwJJJLLLKKK&LLLLLLOOOwwwJJJLLLKKK&LLLLLLOOOwwwJJJLLLKKK&LLLLLLOOOĿed_[ZU[ZT[ZT[ZU[ZU[ZU[ZU[ZU\ZU[ZU\[U\[V\[V\[V\[V]\V][V][W``\tttwwwJJJLLLKKK&LLLLLLOOOҰǼwgZWWWWWXWVUSRQRSUWWX}KYYV{{|||{||{||||}||}||}||}||}||}|}}}wwwJJJLLLKKK&LLLLLLOOOУ̻ZïFİFŰEŰEİEŰEİEïDCA=9777:=@A̺UT\[Yuuwppqccd________`__`__`__`__`__`__`__`[[[pppwwwJJJLLLKKK&LLLLLLOOOѥƵT'#""! lo_iYgXiZp`~l|AQwvwttwdddwwwJJJLLLKKK&LLLLLLOOOѥǵT($##"!nLA +%! '":2QE _Q m]o;NyxywwycccwwwJJJLLLKKK&LLLLLLOOOѥǵU)%$$"!fX:2TH cU z1zEuuuwwycccwwwJJJLLLKKK&LLLLLLOOOѥǵU*&%$#ZM $ NC mb'ng:popwwycccwwwJJJLLLKKK&LLLLLLOOOѥǵU+&&%"dV-$qW9oV9M<)!& [R [U1gfgwwycccwwwJJJLLLKKK&LLLLLLOOOѥǵU+'&%n2(qK}N|M{MpG`J2D>RL+___wwycccwwwJJJLLLKKK&LLLLLLOOOХǵU,('!.( !mI~Q{N{NzMzL|Md@"&#MG(ZZ[wwycccwwwJJJLLLKKK&LLLLLLOOO͡ǶU,('eX t\@T~Q}P|P{O{NzM}NrY;  FA%ZZZwvycccwwwJJJLLLKKK&LLLLLLOOOȶU-)##G:+WTS~R}R}Q|P|O|NtK FA&^^^wvybccwwwJJJLLLKKK&LLLLLLOOOnnncccccccccccccccdddddddddddddddhgifɸV-)xhoOXVUTTS~Q}PRjH  QL,fefwvybbbwwwJJJLLLKKK&LLLLLLOOOvXpAsY:mS:mS:mS:mS:mS:mS:mS:mS:mS:nT8aOQʸW.(?6I;+[YXWVVTTUkH2(*'le9onowwyccdwwwJJJLLLKKK&LLLLLLOOO9l7i8j8j8j8j8j8j8j8j8j8j8k4`}|M˸V/% hL^[ZYXXW|T[I5 h_+Gutu{{}lllwwwJJJLLLKKK&LLLLLLOOO¯:kExMLLLLLLLLL=o3_}|LʸV0r$\_]]\[YYQA0LA >Nxwx}}}wwwJJJLLLKKK&LLLLLLOOO¯:kQ\Ǒ[Ɛ[Ɛ[Ɛ[Ɛ[Ɛ[Ɛ[Ɛ[ƐWČ@s3_}|L˸V0_SE9,ca`_^]]tR E; rANttuyxywwwJJJLLLKKK&LLLLLLOOO¯;lXe˗eɕeɕdɕeɕdɕdɕdɕ`ǓWÌ@s3_}|L˸V1QGXH5fca``__rR,&\Osc9IZXJkh]mj^mj_mj_mj_mj_mj_mk_mk_nk_nk_nk_ok_`_X^ksncs}ScnO_jO_jO_jO_jO_jO_jN_iN_iN_iN_jU]czzzwwwJJJLLLKKK&MMMMMMPPP¯;l_oΝn̜n̜n̜n̜n͜n̜j˙aȓWÌ@r3_}|L˸V1QG\L8gedcba`\/&H? ]Pxl,KPUYYZZZZZZZZZõ\Na{yyyyyyyyyy{TzjjjwwwJJJLLLKKK&NNNNNNPPP¯ [Oob z)/34555444333ͺSUjnZ\\[[\\[[[[z\hhiwwwJJJLLLKKK&OOOOOOQQQ¯miihgfddbOA3.( SHcUyiɵLUil_aaaaaaaa_Vs[hhiwwwJJJLLLKKK&QQQQQQSSS>m|Ơܸڶ۶ٴ֮~ҧtΠj˚aǓWÌ@r3_}|L˸V31bUuZnjiihfeecSE5$MC^Rsc{ɵLUhnfhhhhhihf_Vs[hhiwwwJJJLLLKKK&RRRRRRTTT>nɥ޽ݺٴ֮~ҧtΠj˙aȓWÌ@r3_}|L˸W4ë3*0)!gnlkjihffdgT@ C: [Om^wɵMUhomppppppmg_Vs[hhhwwwJJJLLLKKK&RRRSSSUUU®?n̫ݻٵ֮}ҧtϠj˙aǓWÌ@r4`~~M˸W4©3ê3rdI>1mnlkjihgff|fL ;3 XLk\uɵMUhquxwwwwung_Vs[hhhwwwJJJLLLKKK&TTTTTTVVV?oϱ޽۶ׯӨuСk̛aɔXč@s7cSʸW5©4ê30E<ZL=oommkjihggvX1)  7/ WKiZtɵMUht}|vng_Vs[hhhwwwJJJLLLKKK&UUUUUUWWW===<;«8ë7ª6ª6ª543/=6tbOxtrqpnlkjhghr^H QEgYwƲLTg{|voib[Tsj}~~wwwJJJLLLKKK&ZZZZZZ\\\ZXLIWUVTVTVTVTVTVTVTVTTRGESRoiPʹX­BưBƯAƯAƯ@Ů?Ů?ŭ=Ů=ĭ<ĭ<ĭ;ĭ:Ĭ:ì9ë9ë8«7«7541(5.G<2xutsqpppommkkaP>,& ZMtdJRf||zzyxwvutslwwwJJJLLLKKK&ZZZ[[[]]]ZXRP`^_]_]_]_]_]_]_]][VTFESRoiPʹXíCưCůBůAƯAŮ@ů@Ů>Į>Į=ŭ=ĭ<Ĭ;ì;ì:ì9ì9«8ª752|'-( gXG{wvtutg{gPZLŭ>ĭ=ĭ<Ĭ;Ĭ;Ĭ:ì9862s$)$ ZM@v{ywxm\M>#t`J!XKscB\UWXXXXXXXXXXXX}Ka`_wwwJJJLLLKKK&\\\]]]___ZX_]trrprqrprprppnhf_]VTFESRoiPʹXîDưDưDưCƯBƯBƯAů@ů@Ů?Ů?ĭ=ĭ<ĭ<í;í;ì:73yk##r]}|{{g0)!+++AABEEF666hVCcR?A8 fX{*=A­B­A¬A¬A¬A­@­@¬@¬@¬@??ͺVU^]\wwwJJJLLLKKK&]]]]]]```YXed}||z|{|{|{zxrphf_]VTFESRoiPʹXîEƱEưEưDưCưCưBůAƯ@Ů@Į?Į?Ů>Į=ĭ<ì;94ma ?7.r~~x;3) ]]]zeMd' #[O|k űHU^]\wwwJJJLLLKKK&^^^^^^aaaYXlj{zrphf_]VTFESRoiPʺXîEƱFưEDZEDZDưCưCůBƯAŮ@Ů@ů?Ů>Ů>ĭ=;7rd"WL@g ~~~90&glgVB LBpa"##"!! ƲIU]][wwwJJJLLLKKK&______bbbYWrq{zrphf_\VSFDSRoiPʺXĮFDZFƱFƱEDZEưDưCưBƯBƯAů@Ů@Ů?ŭ>«=:u) dXJr[#|_nl_80 gYz"###"!! ƲJU]][wwwJJJLLLKKK&``````cccYWxw{zrpif_]VSFDSRoiPʺXĮGȲHȲGDZFDZFDZEǰDưCưBƯBůAŮ@Ů?ĭ>=/# obSªj !!!u[rnllI=/#^Rq!$$##"!! ƲJU]][wwwJJJLLLKKK&aaaaaadddYW~}{zrphf_]VTFESRoiQʺYįGȲHȲGDZFDZFDZEưDůCĮB¬A@?>=681i]Níì|+% OOO///rZuqonnxdMRHyi $$$##"!! ƲJU]][wwwJJJLLLKKK&bbbbbbeeeYW}|trjh`^WUGETStnVʺYįHȲIȲHƱGưFîEC@>;9775QG^TI¬Ů쫪n_P___JII }kWxtsqonaF<qb$%%$$#"!! ƲJU]\[wwwJJJLLLKKK&ccccccfffZXpozytrmkfe`^YWRPLJBAWV~x_ʺYįHȲIưHîFC?;62y/s,~p*p*\Q F?7DZůĮí¬«D;2dUF{wvtrqok6.$6/ j\$&&%$##""! ƳJU]\[wwwJJJLLLKKK&ddddddgggb`WUUTTSSRSRSRSRTRSRSRSRVTVUys\ʺYĮHŰIE@:3|n,g[$WMF?@9?8@9,'#ʵƱŰůĮíì«|WLA\OAy|ywutrppSE7)$ eWz$&&%%$##"!! ƳJU]\[wwwJJJLLLKKK&eeeeeehhh{wc_g[W_ZV_ZV_ZV_ZW_ZW_ZW_ZW_ZW_VRZzMȸYFC:5ɵűİïî®поtg\SJϼ̸˷ʶɵɴȳDZưůĮììª~|zxwlE=|l&***)(('&&&$ƳKU\\ZwwwJJJLLLKKK&kkkkkkmmm̮ʺ_dzS͹Y̸X̷W˸W̷V˷U˷UɵSMSK"ID>Ķ˸dzƳƲűŰİï®­ѿȶD>7"ϼ̸˷ʶɶɴȲDzưůĮĭ¬ª}|yxlE<o'+++*))(''&%ƳKU\\ZvvvJJJLLLKKK&kkklllnnn̮ʺ_dzS͹Z̸X̸X̸W˷W˷V˶UȴS|o3 A<8Ÿ̺ȶȶȵǴdzƲŲűİï®ѿrӿ̹̹˷ʶʵɴȲDZƱůĮíƯê~|zykJAr(+,+***)(''&ƳKU\\ZvvvJJJLLLKKK&mmmmmmooo̮ʺ_ǴTͺ[̹Y̸Y̸X̸W̷W̷VG!'$!ϽʸʸʸʷɶȵȴǴƳŲűİï­п]TL\SIҿλͺ̹˸ʶɵɴdzDzưůƯwc/)"2+$xc~|{g QGt ),,,++*))(''ƳKU\[ZvvvJJJLLLKKK&mmmnnnppp̮ʺ_ǴTͺ[̹Z̹Y̸X͸X̸WdzTYP% ̻̻̻˺˹ʸʸɶȵǴǴƲűİį®­íMG@ijϽͻ͹̸˷ʶɵȳDzƱɳvx©}|~e SIx"*---,++*))('ƳKU\[ZvvvJJJLLLKKK&ooooooqqq˭ʺ_ȴUκ\͹[͹Z̹Y̸Y͹XE WQLξϿξννͽͼ̺˺˹ʸɷȶȵǴŲűİï­ujaϼͻͺ̹˷ʶɵɴȲ˶}o^eXI~~v^ \P}$,..--,,+**)(ƳKU]\[vvvJJJLLLKKK&oooooorrr˭ʺ_ȴUκ]͹\͹[͹Z̹Z˷X_U)Ͽξνμͼ̻̺˹ʸɷȵǵdzŲİîůнϼμͺ̹˷ʶɵȳ˵wg[L«ëxgTh[&-//.--,,+**)ƳLXedcvvvJJJLLLKKK&pppqqqsss˭ʺ_ȵVλ^κ\ͺ[ͺ[κZO%"WQLϿϾνͼ̻˹˸ʸɶȵǴƲİïȶпнϽλ͹̸˷ʶɴȳȳwdocS¬ĭª`RDna*12322000/..-ƲLa~}vvvJJJLLLKKK&qqqqqqsss˭ʺ_ȵVϻ^κ]κ\ͺ\л[~= Ͽξνͼ̺˹ʸɶȵǴƲűįîпнϼͺ̹˸˷ʵɴȳʵɳůì«F<20+u7I²SȷUȷUȷUȷUȷUȷUȷUȷUɷUɷUȷUϿ]gvvvJJJLLLKKK&rrrsssuuu˭ʺ_ȵWλ_κ^ͺ]ͺ\̹[XO'-)'öϿξͼ̻˺˸ɷȵǴƲűï®пϽμͺ̸̹ʶʵɳDzƱůĮí«x*%&&^X8{RYQ{LzLzLzLzLzLzLzLzLzL|LyYvvvJJJLLLKKK&ssssssuuu˭ʺ_ȵWϼ_λ^κ^λ]U0+UPKϾν̻̺˸ɷȵǴƲŰï­поϽμ̹̹˷ʶɴȳDzưŮĭ¬«m5&PJ>jpmlllllllllmzbZWUvvvJJJLLLKKK&ttttttvvvˬʺ_ȵXϼaλ_λ^м^M }wϿνͼ̺˸ɷȵǴƲİï­пϾϼͻ͹˸˷ɵɴDzƱůĮì«yiW L5]UEÔqŕqȘsǗrƖqƕpĔpÓo“nmllŕqnYURvvvJJJLLLKKK&uuuuuuwwwˬʺ_ȵXϼaλ`λ_Ѿ`@ Ͽνͼ˺ʸɷȵǴŲİî­пϽμͻ̹˷ʶɵȳDzŰůí¬PF;  [>b[IĕrΛu֠xӞvЛsΙr˖oȔmŒkÐigekmXURvvvJJJLLLKKK&vvvvvvxxxˬʺ_ȵYϼbλaλ`Ҿ`qf4Ͽνͼ˺ʹɶȵƳűį®ѿоϼλ̸̹ʶʵɳDzƱůĮì«|% 6%%gGf_MƗsНwآzՠxҝuЛt͙q˗pȔnƒlÐiglmXURvvvJJJLLLKKK&wwwwwwyyyˬʺ_ɵYнcϼaϼaϼ`\S*ȿϿνͻ̺ʸɶȵƳűį­поϼκ̹˸ʶɴȳDzưůí¬ªêyd  V:)rNicPȘtӠxۦ|أzՠxӞvЛtΙr˗pɕnƒlÐjmmXURvvvJJJLLLKKK&wwwxxxzzzˬʺ_ɶZнcϽbϼaɷ^D> "!Ͽνͻ˹ʸȶǴƲŰîоϽλͺ̸˷ʵɳDzƱůĮì«©RH=&+pM,{UkdQəuբzި~ڥ|آzՠxӝvЛt͙r˗pɔnƒl’nmXURvvvJJJLLLKKK&yyyyyy{{{ˬʺ_ɶZнdϼcнbʷ_D> !Ͼμ̻˹ɷȵdzűï­поϼλ͹̸ʶɵȳDzưŮí¬ì~!L62Y/ZlfRʙvף|᪁ݧ~ڥ|آzՠxӞvЛtΚr̗pɔnÓnmXURvvvJJJLLLKKK&yyyzzz{{{ʬʺ_ɶZоeнcнcʷ_D> ȿξͼ˺ʸɶȵƳİîѿоϽλͺ̸ʶʵȳDzƱůĭ¬ǯwiX 4vT7c1^lgSəv٥}㭂઀ݧ~ڥ|עzՠxӝvМtΙr˗pĔomXURvvvJJJLLLKKK&zzz{{{}}}ʬʺ_ɷ[оfоdнdʸ`D> νͼ˺ʸȵǴŲİ®ѿоϼͺ͹˷ʶɴȳƱŰĮĮ4.(;+Bj Ͼͽ̺ʸɶȵƲİîоϼλͺ̸ʶɵȳDzưĮȱvc  7qSKx?p2algSʙuݩ豇宄⬂ੀݧ~ۥ}آz֠xӞvќtƕqmXURvvvJJJLLLKKK&||||||~~~ʬʺ_ʷ]ѿgѾfоe̺cIB#ξͻ˹ʷȶdzűİ­пнμͺ̸˷ʵɴDzưǰ70*<-JpQ@s3blgSʙvު곉籆宄㬂઀ݧ~ڥ|أz֠xӞvǖrmXURvvvJJJLLLKKK&}}}}}}ʬɺ_ɶ\оgнfϽeӿfd[0mheϿͽ̻ʸȶǴŲİ®ѿоϼͺ̹˷ʶɴDzƱʴ}o_ ?y\UUBt4cpjWʙvᬄ곉籆寅㭃ઁݧ~ܥ}٣z֡xȗsn_[XvvvJJJLLLKKK&~~~~~~ʫ̼`ƳTǵWȵWȵWͺZ~r7CA?νͼ˹ɷȵƳűï­оϼλ͹̸ʶɵȳʴ'#&F6RxXT@r7eyt`əvޫ괊籈䯅⭄ંީܦ~٤|ףzԡxǗrt}zwvvvJJJLLLKKK&˲˿wu˿tɾsk_~D Ͼͼ̺ʸȶǴűð­пϽμͺ̸ʶʵɴDZYOE +pM:g=mIPǴV͹XмYϻXιW̷V˷U˷U˷TűNĶZmiWWWXvvvJJJLLLKKK&ɮətԢ|֤~ԣ|Ӣ{ҠzџzϞxΝw͛v̚uȘsȘtugμZʸb±_SPJCCJMLMV¯Yɶ[м^ҿ^Ҿ]ѽ]ϼ\κ[͹Y͹Y̹X̸W̸V̸U˷U̷UƱOŶ\so^onovvvJJJLLLKKK&ǭϟz͞z͞{͞{͞{͞{͞{͟{Ο{Ο{Ο{Ο{Ѡ|xǴUʸ^ͺ`ϼ`λ`ϼ_н_ϼ_λ]͹]κ\͹\˸Z˷ZʶYɵWɵWɵVɴVȴVȴUȴUȴTȴSȳSdzRdzRdzQdzPîKǸ^tvvvJJJLLLKKK&˽̾̾̾̾̾̾̾ͿͿͿͿͿú̼[ȷXȸYȸXȸXȸXȸXȸXȸXȸXȷXȷXȷXȷXȷXȷXȷXȷXȷXȷXȷXȷXȷXȷXȷWȷWȷXȷXȷXɸX̾evvvJJJLLLKKK&ʬƚƛƛƛƛƛƛǜǜǜǜǜǜǜǜǜǜȜȜȝȝȝȝȝȝȝȝȝȝȝǞuuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&uuuJJJLLLKKK&yqqqJJJLLLLLL!PWWWKKKLLLMMM xxxXXXKKKLLLKKK`4ʓ~~~}}}|||{{{yyyxxxwwwvvvtttsssrrrqqqpppnnnmmmlllkkkiiihhhgggfffdddcccaaa```___^^^\\\[[[ZZZYYYWWWVVVUUUTTTSSSQQQPPPOOONNNLLLKKKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJKKKLLLLLLJJJ *򖖖󘘘󙙙󚚚󜜜󝝝󞞞󟟟󠠠󠠠󠠠󠠠󟟟󞞞󝝝󜜜󛛛󙙙󘘘󗗗󖖖󕕕󔔔󒒒󑑑󐐐󏏏󍍍󌌌󋋋󉉉󈈈󇇇󅅅󄄄󃃃󂂂󀀀~~~}}}{{{zzzyyyxxxvvvuuutttsssrrrpppooonnnmmmkkkjjjhhhgggfffeeecccbbbaaa```^^^]]]\\\[[[YYYXXXWWWVVVUUUSSSRRRQQQPPPNNNMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLfLLL ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????(0` $ %%%!!!'YYY0:::::::::::::::::::::::::::::YYY0'GGGKKKOOOOOOSSSYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZSSSPPPOOOIII}AAA FFFbwwwhhhCCC@EEEz}}}BBBTFFFy}}}CCCSFFFy}}}CCCRFFFy}}}CCCRFFFyŸp@@>9w46A~d}}~}}}CCCRFFFyȶX"!n^)#=4yjl}}}CCCRFFFyȶZ$l] VC-H7$ ,' pm]}}}CCCRFFFyǵXdO6R}OlS6 ^\S}}}CCCRFFFyk|Z|k[}l[~mhkHaT0&~UV}RfP5 nl_}}}CCCRFFFyFyKKI~IeB6/ bO:_\eP8 WMm}}}CCCRGGGy©am͜l̛_ǒNjA+% u`GebXG4 aUEUVVVbogeees}}}CCCRJJJyªvɞ֭zѥ`ǓMjDB:OA2if~Z1(TI!!Oj____o}}}CCCRLLLyìҮݹ}ӧaȔMjFw" jPli}[;0$ A8 uOpqqk`o}}}CCCROOOyykl\L}LgI2XMy\nkbRC2 91 uPxn`o}}}CCCRQQQyxwQPPOPOPNrviTQQQQFë51?7/'iplifT> B9 Pm`s}}}CCCRTTTy`^VSWUWTML~pɲDȰBǯ@Ʈ?Ʈ=ì:ì73TJ sZwjpS~gLE9+cUJx}wqny}}}CCCRWWWylkpnqohfQO}pDzDưBůAŮ?ĭ=Ů;5SI cUExfB:1NLKAA@6.$)",&.FGFEHc}}}CCCRYYYyxwkiQO}pȳFDZEưCƯAƯ?;SIq^^QA{||SRQjXCr^Gqb!!&]}}}CCCR\\\yihPNrɴHDZFíC?;l_"zgĬueR[[[aaaXK;pbQF"$" (]}}}CCCR___y~pnfd^\WTmîG9pc&UKG> xl]ȲĮ«[OAXL=tvo7.$81 "&$!)]}}}CCCRaaayżWVVUJaW$)$KE;uhxj71,n˶ƱĮ«~yuMA3)$"(&$+]}}}CCCRdddyÅ̷T͸U͸SJF?'$ {ξĮíXOFʵDzů¬ª|yZL<"")(%,]}}}CCCRgggyÆ˷V̸WɴT[R%&# ˸dzİî­~pκɵDzů}v|ZL="$+*'.]|||CCCRiiiyÆ̸XϻZBп̻ʸɶƳűóϼ˸ʵA:1XM@PD7*% '-+(/^|||CCCRlllyÆ̹Y͹[VN$A=:̽Ͼͻʸȵı˻оλ˸Dzn<4*93:><;>q|||CCCRnnnyÇκ\V($ysν˹ȵűоͺ˶ʵư«z#6:)bdbb_{|||CCCRqqqyÆϼ^Nξ˹ȵİϽ̹ɵƱíëi @U?Ŗsҝv˗qőli{|||CCCRsssyÇѽ`HνʹǴîѿλ˷ȳůĭbTF $NtT̛wڥ|Ҟv̘pk{|||CCCRvvvyÇҾbH ͼɷűϽ̹ɴDZ($$Z?Wbϟy᫁٤{Ӟvnz|||CCCRxxxy…н`K Ͽ˺ǴîоͺʶʴtfW$DpZhӡ|篅ߩ٣zŔp|||CCCR{{{y̩̾Y hfdͼȶİλ͹"(O&\gF1(upR[[[gggän͝j͜Zvzt0UF0f{cH$ qf,HIL|ffg[[[jjjǭزsТWv:B8wYhfS=% fX'kha[[[nnnwufvdeCu"A8$ekzdJ)"aT(rb[[[qqqTRSQOMeDDCì<292jYGq{[aP<# }n vn[[[tttqprqYWfɲBưAǯ>8YNJ@1oyhUspmMHC>3'C;9A?J[[[xxxzyWUiʴEA:eZ!TJ=k`T}}~qbQx[0)!4[[[{{{}wvpZw/bW+XN.<5*Ư«uxhUto;1 q&"6[[[~~~ȷ^ȵRKXP&_XK|qdʵįì©wE:+vf)%8[[[̺a̸Wla-g`WijɶƱ²̸ɴwb|F<,yi+'9[[[ͼdLGB1ǼͼʸƲƶμ͹wd~=5&v):6F[[[оf{1Jk{ݱ׬¥[[[ɾb,'"Ͼʶ~B>:z}~[[[Ǿ֥~wYB@=:ǺzbZMGD=[[[ǽޫۥ|kPC9)KG9XTHZUFUO9TM-eZ+~6t[[[ӸԸӸ²gdfkȹpϿrq[[[[[[[[[ZZZg|||PPPQ(  333bbb-555555555aaa-000໻߼߾߽ᑑ  QfX*ogH zo7y^=[R< ɧdok6oPYL,3zm''' £xxtZ2p^>tYQCd|221 ™gdZ6~o3{bsfbUErf':<<< ¾puK^}jĭymn^& uFFF ̖Dɷ²ȵ~wo`00}PPP Ɣ}X˹ȴvleH×gZZZ ş}tYɶ͹qr_wiתǶccc t]Źpkkk үrih]urrr lll pgmodeler-0.9.2/main/src/000077500000000000000000000000001360462764600152315ustar00rootroot00000000000000pgmodeler-0.9.2/main/src/application.cpp000066400000000000000000000155641360462764600202530ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "application.h" #include "globalattributes.h" #include "messagebox.h" #include "attributes.h" Application::Application(int &argc, char **argv) : QApplication(argc,argv) { QTranslator *main_translator=nullptr, *plugin_translator=nullptr; QFile ui_style(GlobalAttributes::TmplConfigurationDir + GlobalAttributes::DirSeparator + GlobalAttributes::UiStyleConf + GlobalAttributes::ConfigurationExt); QString plugin_name, plug_lang_dir, plug_lang_file; QStringList dir_list; QDir dir; //Creating the initial user's configuration createUserConfiguration(); //Changing the current working dir to the executable's directory in QDir::setCurrent(this->applicationDirPath()); //Adding paths which executable will find plugins and it's dependecies this->addLibraryPath(this->applicationDirPath()); //If pgModeler bundles plugins, add the root plugins path to lib search paths if(dir.exists(GlobalAttributes::PluginsDir)) this->addLibraryPath(GlobalAttributes::PluginsDir); //Check if the temporary dir exists, if not, creates it. if(!dir.exists(GlobalAttributes::TemporaryDir)) { if(!dir.mkdir(GlobalAttributes::TemporaryDir)) { Messagebox msg; msg.show(Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(GlobalAttributes::TemporaryDir), ErrorCode::FileDirectoryNotWritten, __PRETTY_FUNCTION__,__FILE__,__LINE__)); } } //Trying to identify if the user defined a custom UI language in the pgmodeler.conf file QString conf_file = GlobalAttributes::ConfigurationsDir + GlobalAttributes::DirSeparator + GlobalAttributes::GeneralConf + GlobalAttributes::ConfigurationExt; QFile input; QString lang_id = QLocale::system().name(); input.setFileName(conf_file); if(input.open(QFile::ReadOnly)) { QString buf = QString(input.readAll()); QRegExp regexp = QRegExp(QString("(%1)(.*)(=)(\\\")(.)+(\\\")(\\\n)").arg(Attributes::UiLanguage)); int idx = regexp.indexIn(QString(buf)); //Extract the value of the ui-language attribute in the conf file lang_id = buf.mid(idx, regexp.matchedLength()); lang_id.remove(Attributes::UiLanguage); lang_id.remove(QChar('"')).remove(QChar('=')).remove(QChar('\n')); } //Tries to load the main ui translation according to the system's locale main_translator=new QTranslator(this); main_translator->load(lang_id, GlobalAttributes::LanguagesDir); this->installTranslator(main_translator); //Trying to load plugins translations dir_list=QDir(GlobalAttributes::PluginsDir + GlobalAttributes::DirSeparator, QString("*"), QDir::Name, QDir::AllDirs | QDir::NoDotAndDotDot).entryList(); while(!dir_list.isEmpty()) { plugin_name=dir_list.front(); dir_list.pop_front(); //Configure the path to "lang" subdir at current plugin directory plug_lang_dir=GlobalAttributes::PluginsDir + GlobalAttributes::DirSeparator + plugin_name + GlobalAttributes::DirSeparator + QString("lang") + GlobalAttributes::DirSeparator; plug_lang_file=plugin_name + QString(".") + lang_id; //Check if the .qm file exists for the current plugin. If so create and install a translator if(QFileInfo(plug_lang_dir + plug_lang_file + QString(".qm")).exists()) { plugin_translator=new QTranslator(this); plugin_translator->load(plug_lang_file, plug_lang_dir); this->installTranslator(plugin_translator); } } //Loading app style sheet ui_style.open(QFile::ReadOnly); //Raises an error if ui style is not found if(!ui_style.isOpen()) { Messagebox msg; msg.show(Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(ui_style.fileName()), ErrorCode::FileDirectoryNotAccessed,__PRETTY_FUNCTION__,__FILE__,__LINE__)); } else this->setStyleSheet(ui_style.readAll()); } bool Application::notify(QObject *receiver, QEvent *event) { try { return(QApplication::notify(receiver,event)); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e); return(false); } catch(...) { Messagebox msg_box; msg_box.show(trUtf8("Unknown exception caught!"), Messagebox::ErrorIcon); return(false); } } void Application::createUserConfiguration(void) { QDir config_dir(GlobalAttributes::ConfigurationsDir); try { //If the directory not exists or is empty if(!config_dir.exists() || config_dir.entryList({QString("*%1").arg(GlobalAttributes::ConfigurationExt)}, QDir::Files | QDir::NoDotAndDotDot).isEmpty()) copyFilesRecursively(GlobalAttributes::TmplConfigurationDir, GlobalAttributes::ConfigurationsDir); } catch(Exception &e) { Messagebox msg_box; msg_box.show(e, trUtf8("Failed to create initial configuration in `%1'! Check if the current user has write permission over that path and at least read permission over `%2'.").arg(GlobalAttributes::ConfigurationsDir, CONFDIR)); throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e); } } void Application::copyFilesRecursively(const QString &src_path, const QString &dst_path) { QFileInfo src_file(src_path); if(!src_file.exists()) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotAccessed).arg(src_path), __PRETTY_FUNCTION__,__FILE__,__LINE__); if(src_file.isDir()) { QString new_src_path, new_dst_path; QStringList filenames; QDir dst_dir(dst_path), src_dir(src_path); if(!dst_dir.exists() && !dst_dir.mkpath(dst_path)) throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(dst_path), __PRETTY_FUNCTION__,__FILE__,__LINE__); filenames = src_dir.entryList({QString("*%1").arg(GlobalAttributes::ConfigurationExt)}, QDir::Files | QDir::NoDotAndDotDot); for(QString filename : filenames) { //Avoiding the copy of ui-style.conf file if(!filename.contains(GlobalAttributes::UiStyleConf)) { new_src_path = src_path + src_dir.separator() + filename; new_dst_path = dst_path + dst_dir.separator() + filename; copyFilesRecursively(new_src_path, new_dst_path); } } } else if(!QFile::exists(dst_path) && !QFile::copy(src_path, dst_path)) { throw Exception(Exception::getErrorMessage(ErrorCode::FileDirectoryNotWritten).arg(dst_path), __PRETTY_FUNCTION__,__FILE__,__LINE__); } } pgmodeler-0.9.2/main/src/application.h000066400000000000000000000036701360462764600177130ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ /* # The original implementation of createUserConfiguration() and copyFilesRecursively() was # originally written by Lisandro Damián Nicanor Pérez Meyer and is # available at: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # # The current code was reviewed and minimally changed by Raphael Araújo e Silva */ /** \ingroup main \class Application \brief This class inherits from QApplication and has the notify() method modified to treat the exceptions raised by pgModeler components. \note Creation date: 30/08/2007 */ #ifndef APPLICATION_H #define APPLICATION_H #include #include #include #include class Application: public QApplication { private: /*! \brief Creates the pgModeler's configuration dir on user's home folder. The output path is platform dependant and is ruled by GlobalAttributes::CONFIGURATIONS_DIR */ void createUserConfiguration(void); //! \brief Copy files from a path to another recursively void copyFilesRecursively(const QString &src_path, const QString &dst_path); public: Application(int & argc, char ** argv); bool notify(QObject * receiver, QEvent * event); }; #endif pgmodeler-0.9.2/main/src/main.cpp000066400000000000000000000111471360462764600166650ustar00rootroot00000000000000/* # PostgreSQL Database Modeler (pgModeler) # # Copyright 2006-2019 - Raphael Araújo e Silva # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # The complete text of GPLv3 is at LICENSE file on source code root directory. # Also, you can get the complete GNU General Public License at */ #include "application.h" #include "mainwindow.h" #ifndef Q_OS_WIN #include "execinfo.h" #endif void startCrashHandler(int signal) { QFile output; QString lin, cmd; /** At the moment the backtrace function does not exists on MingW (Windows) this way the code that generates the stacktrace is available only on Linux/Unix systems */ #ifndef Q_OS_WIN void *stack[30]; size_t stack_size; char **symbols=nullptr; stack_size = backtrace(stack, 30); symbols = backtrace_symbols(stack, stack_size); #endif cmd=QString("\"%1\"").arg(GlobalAttributes::PgModelerCHandlerPath) + QString(" -style ") + GlobalAttributes::DefaultQtStyle; //Creates the stacktrace file output.setFileName(GlobalAttributes::TemporaryDir + GlobalAttributes::DirSeparator + GlobalAttributes::StacktraceFile); output.open(QFile::WriteOnly); if(output.isOpen()) { lin=QString("** pgModeler crashed after receive signal: %1 **\n\nDate/Time: %2 \nVersion: %3 \nBuild: %4 \n") .arg(signal) .arg(QDateTime::currentDateTime().toString(QString("yyyy-MM-dd hh:mm:ss"))) .arg(GlobalAttributes::PgModelerVersion) .arg(GlobalAttributes::PgModelerBuildNumber); lin+=QString("Compilation Qt version: %1\nRunning Qt version: %2\n\n") .arg(QT_VERSION_STR) .arg(qVersion()); output.write(lin.toStdString().c_str(), lin.size()); #ifndef Q_OS_WIN for(size_t i=0; i < stack_size; i++) { lin=QString("[%1] ").arg(stack_size-1-i) + QString(symbols[i]) + QString("\n"); output.write(lin.toStdString().c_str(), lin.size()); } free(symbols); #else lin=QString("** Stack trace unavailable on Windows system **"); output.write(lin.toStdString().c_str(), lin.size()); #endif output.close(); } /* Changing the working dir to the main executable in order to call the crash handler if the PGMODELER_CHANDLER_PATH isn't set */ QDir dir; dir.cd(QApplication::applicationDirPath()); exit(1 + system(cmd.toStdString().c_str())); } int main(int argc, char **argv) { try { /* Registering the below classes as metatypes in order to make * them liable to be sent through signal parameters. */ qRegisterMetaType("ObjectType"); qRegisterMetaType("Exception"); qRegisterMetaType("ValidationInfo"); qRegisterMetaType("ObjectsDiffInfo"); //Install a signal handler to start crashhandler when SIGSEGV or SIGABRT is emitted signal(SIGSEGV, startCrashHandler); signal(SIGABRT, startCrashHandler); //Checking if the user specified another widget style using the -style param bool using_style=false; for(int i=0; i < argc && !using_style; i++) using_style=QString(argv[i]).contains("-style"); Application::setAttribute(Qt::AA_UseHighDpiPixmaps); //High DPI suport via application attributes is available only from Qt 5.6.0 #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) Application::setAttribute(Qt::AA_EnableHighDpiScaling); #endif Application app(argc,argv); int res=0; //If no custom style is specified we force the usage of Fusion (the default for Qt and pgModeler) if(!using_style) app.setStyle(GlobalAttributes::DefaultQtStyle); //Loading the application splash screen QSplashScreen splash; QPixmap pix(QPixmap(QString(":imagens/imagens/pgmodeler_splash.png"))); splash.setPixmap(pix); splash.setMask(pix.mask()); splash.show(); app.processEvents(); //Creates the main form MainWindow fmain; //Loading models via command line on MacOSX are disabled until the file association work correclty on that system #ifndef Q_OS_MAC QStringList params=app.arguments(); params.pop_front(); //If the user specifies a list of files to be loaded if(!params.isEmpty()) fmain.loadModels(params); #endif fmain.show(); splash.finish(&fmain); res=app.exec(); app.closeAllWindows(); return(res); } catch(Exception &e) { QTextStream ts(stdout); ts << e.getExceptionsText(); return(enum_cast(e.getErrorCode())); } } pgmodeler-0.9.2/pgmodeler-intl.pro000066400000000000000000000005331360462764600171630ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = libutils \ libparsers \ libdbconnect \ libpgmodeler \ libobjrenderer \ libpgmodeler_ui \ crashhandler \ main \ main-cli TRANSLATIONS = lang/pt_BR.ts \ lang/zh_CN.ts \ lang/fr_FR.ts \ lang/es_ES.ts \ lang/nl_NL.ts CODECFORTR = UTF8 pgmodeler-0.9.2/pgmodeler.appdata.xml000066400000000000000000000043551360462764600176360ustar00rootroot00000000000000 pgmodeler.desktop CC0 GPLv3 pgmodeler PostgreSQL Database Modeler Инструмент ER проектирования БД для PostgreSQL

pgModeler - PostgreSQL Database Modeler - is an open source data modeling tool designed for PostgreSQL. No more DDL commands written by hand let pgModeler do the job for you! This software reunites the concepts of entity-relationship diagrams and the features that PostgreSQL implements as extensions of SQL standards.

PostgreSQL Database Modeler, или просто, pgModeler является свободным инструментом для моделирования баз данных. Он объединяет в себе классическую концепцию entity-relationship (ER) диаграмм с некоторыми осоденностями, реализованными только в PostgreSQL. Модели, созданные пользователем могут быть автоматически транслированы в SQL код и применены к БД на кластер (версии 9.*).

http://pgmodeler.com.br/assets/img/ss/ss1.png http://pgmodeler.com.br/assets/img/ss/ss2.png http://pgmodeler.com.br/assets/img/ss/ss3.png http://pgmodeler.com.br/assets/img/ss/ss4.png http://pgmodeler.com.br/assets/img/ss/ss5.png http://pgmodeler.com.br/assets/img/ss/ss6.png http://pgmodeler.com.br/assets/img/ss/ss7.png http://pgmodeler.com.br/assets/img/ss/ss8.png http://pgmodeler.com.br/assets/img/ss/ss9.png http://pgmodeler.com.br/assets/img/ss/ss10.png http://pgmodeler.com.br/ pahan_at_hubbitus.info
pgmodeler-0.9.2/pgmodeler.pri000066400000000000000000000202171360462764600162120ustar00rootroot00000000000000# This file contains the main variables settings to build pgModeler on all supported platforms. # # Thanks to Lisandro Damián Nicanor Pérez Meyer, pgModeler is able to be package in most of # Linux distros. # # Original version by: Lisandro Damián Nicanor Pérez Meyer # Original code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # # Refactored version by: Raphal Araújo e Silva # Refactored code: https://github.com/pgmodeler/pgmodeler # General Qt settings QT += core widgets printsupport network svg CONFIG += ordered qt stl rtti exceptions warn_on c++14 TEMPLATE = subdirs MOC_DIR = moc OBJECTS_DIR = obj UI_DIR = src # Setting up the flag passed to compiler to indicate a snapshot build defined(SNAPSHOT_BUILD, var): DEFINES+=SNAPSHOT_BUILD # Setting up the flag passed to compiler to build the demo version defined(DEMO_VERSION, var): DEFINES+=DEMO_VERSION # Setting up the flag passed to compiler to disable all code related to update checking defined(NO_UPDATE_CHECK, var): DEFINES+=NO_UPDATE_CHECK # Properly defining build number constant unix { BUILDNUM=$$system("date '+%Y%m%d'") DEFINES+=BUILDNUM=\\\"$${BUILDNUM}\\\" } else { BUILDNUM=$$system('wingetdate.bat') DEFINES+=BUILDNUM=\\\"$${BUILDNUM}\\\" } # Below, the user can specify where all generated file can be placed # through a set of variables, being them: # # PREFIX -> the root directory where the files will be placed # BINDIR -> where executables accessible by the user resides # PRIVATEBINDIR -> where executables not directly accessible by the user resides # PRIVATELIBDIR -> where libraries not directly shared through the system resides # PLUGINSDIR -> where third party plugins are installed # SHAREDIR -> where shared files and resources should be placed # CONFDIR -> where the pgModeler's configuration folder (conf) resides # DOCDIR -> where documentation related files are placed # LANGDIR -> where the UI translation folder (lang) resides # SAMPLESDIR -> where the sample models folder (samples) resides # SCHEMASDIR -> where the object's schemas folder (schema) resides # # The values of each variable changes between supported platforms and are describe as follow # Linux custom variables settings linux { CONFIG += x11 # Default configuration for package pgModeler. # The default prefix is /usr/local !defined(PREFIX, var): PREFIX = /usr/local !defined(BINDIR, var): BINDIR = $$PREFIX/bin !defined(PRIVATEBINDIR, var): PRIVATEBINDIR = $$PREFIX/lib/pgmodeler/bin !defined(PRIVATELIBDIR, var): PRIVATELIBDIR = $$PREFIX/lib/pgmodeler !defined(PLUGINSDIR, var): PLUGINSDIR = $$PREFIX/lib/pgmodeler/plugins !defined(SHAREDIR, var): SHAREDIR = $$PREFIX/share/pgmodeler !defined(CONFDIR, var): CONFDIR = $$SHAREDIR/conf !defined(DOCDIR, var): DOCDIR = $$SHAREDIR !defined(LANGDIR, var): LANGDIR = $$SHAREDIR/lang !defined(SAMPLESDIR, var): SAMPLESDIR = $$SHAREDIR/samples !defined(SCHEMASDIR, var): SCHEMASDIR = $$SHAREDIR/schemas # Specifies where to find the libraries at runtime QMAKE_RPATHDIR += $$PRIVATELIBDIR # Forcing the display of some warnings CONFIG(debug, debug|release): QMAKE_CXXFLAGS += "-Wall -Wextra -Wuninitialized" } # Windows custom variables settings windows { CONFIG += windows # The default prefix is ./build !defined(PREFIX, var): PREFIX = $$PWD/build !defined(BINDIR, var): BINDIR = $$PREFIX !defined(PRIVATEBINDIR, var): PRIVATEBINDIR = $$PREFIX !defined(PRIVATELIBDIR, var): PRIVATELIBDIR = $$PREFIX !defined(PLUGINSDIR, var): PLUGINSDIR = $$PREFIX/plugins !defined(SHAREDIR, var): SHAREDIR = $$PREFIX !defined(CONFDIR, var): CONFDIR = $$PREFIX/conf !defined(DOCDIR, var): DOCDIR = $$PREFIX !defined(LANGDIR, var): LANGDIR = $$PREFIX/lang !defined(SAMPLESDIR, var): SAMPLESDIR = $$PREFIX/samples !defined(SCHEMASDIR, var): SCHEMASDIR = $$PREFIX/schemas } # MacOS X custom variables settings macx { CONFIG -= app_bundle # The default prefix is ./build/pgmodeler.app/Contents !defined(PREFIX, var): PREFIX = /Applications/pgmodeler.app/Contents !defined(BINDIR, var): BINDIR = $$PREFIX/MacOS !defined(PRIVATEBINDIR, var): PRIVATEBINDIR = $$BINDIR !defined(PRIVATELIBDIR, var): PRIVATELIBDIR = $$PREFIX/Frameworks !defined(PLUGINSDIR, var): PLUGINSDIR = $$BINDIR/plugins !defined(SHAREDIR, var): SHAREDIR = $$BINDIR !defined(CONFDIR, var): CONFDIR = $$BINDIR/conf !defined(DOCDIR, var): DOCDIR = $$BINDIR !defined(LANGDIR, var): LANGDIR = $$BINDIR/lang !defined(SAMPLESDIR, var): SAMPLESDIR = $$BINDIR/samples !defined(SCHEMASDIR, var): SCHEMASDIR = $$BINDIR/schemas # Specifies where to find the libraries at runtime QMAKE_RPATHDIR += @executable_path/../Frameworks QMAKE_LFLAGS_SONAME = -Wl,-install_name,@loader_path/../Frameworks/ } # Creating constants based upon the custom paths so the GlobalAttributes # namespace can correctly configure the paths inside the code DEFINES += BINDIR=\\\"$${BINDIR}\\\" \ PLUGINSDIR=\\\"$${PLUGINSDIR}\\\" \ PRIVATEBINDIR=\\\"$${PRIVATEBINDIR}\\\" \ CONFDIR=\\\"$${CONFDIR}\\\" \ DOCDIR=\\\"$${DOCDIR}\\\" \ LANGDIR=\\\"$${LANGDIR}\\\" \ SAMPLESDIR=\\\"$${SAMPLESDIR}\\\" \ SCHEMASDIR=\\\"$${SCHEMASDIR}\\\" # pgModeler depends on libpq and libxml2 this way to variables # are define so the compiler can find the libs at link time. # # PGSQL_LIB -> Full path to libpq.(so | dll | dylib) # PGSQL_INC -> Root path where PgSQL includes can be found # # XML_LIB -> Full path to libxml2.(so | dll | dylib) # XML_INC -> Root path where XML2 includes can be found unix:!macx { CONFIG += link_pkgconfig PKGCONFIG = libpq libxml-2.0 PGSQL_LIB = -lpq XML_LIB = -lxml2 } macx { PGSQL_LIB = /Library/PostgreSQL/11/lib/libpq.dylib PGSQL_INC = /Library/PostgreSQL/11/include XML_INC = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/libxml2 XML_LIB = /usr/lib/libxml2.dylib INCLUDEPATH += $$PGSQL_INC $$XML_INC } windows { !defined(PGSQL_LIB, var): PGSQL_LIB = C:/msys_64/mingw64/bin/libpq.dll !defined(PGSQL_INC, var): PGSQL_INC = C:/msys_64/mingw64/include !defined(XML_INC, var): XML_INC = C:/msys_64/mingw64/include/libxml2 !defined(XML_LIB, var): XML_LIB = C:/msys_64/mingw64/bin/libxml2-2.dll # Workaround to solve bug of timespec struct on MingW + PostgreSQL < 9.4 QMAKE_CXXFLAGS+="-DHAVE_STRUCT_TIMESPEC" INCLUDEPATH += "$$PGSQL_INC" "$$XML_INC" } macx | windows { !exists($$PGSQL_LIB) { PKG_ERROR = "PostgreSQL libraries" VARIABLE = "PGSQL_LIB" VALUE = $$PGSQL_LIB } !exists($$PGSQL_INC/libpq-fe.h) { PKG_ERROR = "PostgreSQL headers" VARIABLE = "PGSQL_INC" VALUE = $$PGSQL_INC } !exists($$XML_LIB) { PKG_ERROR = "XML2 libraries" VARIABLE = "XML_LIB" VALUE = $$XML_LIB } !exists($$XML_INC) { PKG_ERROR = "XML2 headers" VARIABLE = "XML_INC" VALUE = $$XML_INC } !isEmpty(PKG_ERROR) { warning("$$PKG_ERROR were not found at \"$$VALUE\"!") warning("Please correct the value of $$VARIABLE and try again!") error("pgModeler compilation aborted.") } } # Define a custom function to print build details defineTest(printBuildDetails) { LB=$$escape_expand(\n) log($$LB) log("** pgModeler build details ** $$LB $$LB") log(" PREFIX = $$PREFIX $$LB") log(" BINDIR = $$BINDIR $$LB") log(" PRIVATEBINDIR = $$PRIVATEBINDIR $$LB") log(" PRIVATELIBDIR = $$PRIVATELIBDIR $$LB") log(" PLUGINSDIR = $$PLUGINSDIR $$LB") log(" SHAREDIR = $$SHAREDIR $$LB") log(" CONFDIR = $$CONFDIR $$LB") log(" DOCDIR = $$DOCDIR $$LB") log(" LANGDIR = $$LANGDIR $$LB") log(" SAMPLESDIR = $$SAMPLESDIR $$LB") log(" SCHEMASDIR = $$SCHEMASDIR $$LB $$LB") log("* To change a variable value run qmake again setting the desired value e.g.: $$LB") log(" > qmake PREFIX+=/usr/local -r pgmodeler.pro $$LB $$LB") log("* Proceed with build process by running: $$LB") log(" > make && make install $$LB") log($$LB) return(true) } pgmodeler-0.9.2/pgmodeler.pro000066400000000000000000000032351360462764600162210ustar00rootroot00000000000000# This file contains the main settings to build subprojects # # Refactored version by: Lisandro Damián Nicanor Pérez Meyer # Refactored code: https://github.com/perezmeyer/pgmodeler/tree/shared_libs # # Reviewed version by: Raphal Araújo e Silva # Reviewed code: https://github.com/pgmodeler/pgmodeler # # NOTE: Reviewed code is not a direct merge from refactored version but based upon the # refactored code, containing almost all changes done by the refactoring author. include(pgmodeler.pri) # Subprojects (libraries only) SUBDIRS = libutils \ libparsers \ libpgmodeler \ libpgconnector \ libobjrenderer \ libpgmodeler_ui # Include the tests subprojects only on debug mode CONFIG(debug, debug|release): SUBDIRS += tests # Include the plugins subprojects only if exists PLUGINS_SRC_ROOT=$$PWD/plugins/plugins.pro !exists($$PLUGINS_SRC_ROOT) { warning("Plugins subproject $$PLUGINS_SRC_ROOT wasn't found! pgModeler will be build without plugins.") warning("Make sure to clone https://github.com/pgmodeler/plugins inside pgModeler's root folder and rerun qmake.") } exists($$PLUGINS_SRC_ROOT) { SUBDIRS += plugins } # Including executables subprojects (libraries only) SUBDIRS += crashhandler \ main-cli \ main # Deployment settings samples.files = samples/* samples.path = $$SAMPLESDIR schemas.files = schemas/* schemas.path = $$SCHEMASDIR lang.files = lang/* lang.path = $$LANGDIR conf.files = conf/* conf.path = $$CONFDIR doc.files = README.md CHANGELOG.md LICENSE RELEASENOTES.md doc.path = $$DOCDIR INSTALLS += samples schemas lang conf doc pgmodeler-0.9.2/pgmodeler.vars000066400000000000000000000043261360462764600163760ustar00rootroot00000000000000#!/bin/bash # If you have root access you can rename this file to pgmodeler.sh and put it on # /etc/profile.d (if you system supports this technique). # # If you do not have root access you can change this file and install it # as a .bashrc or .bash_profile. # # In both cases above you will need to set the PGMODELER_ROOT variable with # the full path to pgModeler root directory. # ---[ Custom Qt configuration ]--- # # This section specifies some environment vars responsible to find Qt framework installation in your system. # Make sure to have the command "qtpaths" correctly mapped into your PATH environment variable or use the # QT_PATHS_BIN variable below to specify the mentioned command. # # If you have a custom Qt installation at /opt/qt-5.9.6 for example, the path to the command above should be # /opt/qt-5.9.6/5.9.6/gcc_64 # # NOTE: Use the configuration below only if you have a custom Qt installation other than as defined by # your system or if Qt isn't included/installed by default on your distro. # Replace the value of this variable by the full path to "qtpaths" if you have a custom Qt installation # export QT_PATHS_BIN=qtpaths # Qt's main environment variables # export QT_ROOT="$($QT_PATHS_BIN --install-prefix)" # export QT_BIN="$($QT_PATHS_BIN --binaries-dir)" # export QT_PLUGIN_PATH="$($QT_PATHS_BIN --plugin-dir)" # Change the "lib64" by "lib" if you're running a 32 bit system # export QT_LIBS="$QT_ROOT/lib64" # export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"$QT_LIBS" # export PATH=$PATH:"$QT_BIN" # --- [ End custom configuration ] --- # Specify here the full path to the pgmodeler's root directory export PGMODELER_ROOT="$(dirname "$(readlink -f "$0")")" export PGMODELER_TMPL_CONF_DIR="$PGMODELER_ROOT/conf" export PGMODELER_SCHEMAS_DIR="$PGMODELER_ROOT/schemas" export PGMODELER_LANG_DIR="$PGMODELER_ROOT/lang" export PGMODELER_PLUGINS_DIR="$PGMODELER_ROOT/plugins" export PGMODELER_SAMPLES_DIR="$PGMODELER_ROOT/samples" export PGMODELER_CHANDLER_PATH="$PGMODELER_ROOT/pgmodeler-ch" export PGMODELER_CLI_PATH="$PGMODELER_ROOT/pgmodeler-cli" export PGMODELER_APP_PATH="$PGMODELER_ROOT/pgmodeler" export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"$PGMODELER_ROOT/lib" export PATH=$PATH:"$PGMODELER_ROOT" pgmodeler-0.9.2/samples/000077500000000000000000000000001360462764600151625ustar00rootroot00000000000000pgmodeler-0.9.2/samples/3dcitydb.dbm000066400000000000000000011436511360462764600173660ustar00rootroot00000000000000 ] $br %end $br $br %if %not {splitted} %and {index} %then {index} %end {objects} [
] $br $br pgmodeler-0.9.2/schemas/datadict/index.sch000066400000000000000000000021571360462764600205310ustar00rootroot00000000000000# Template code for data dictionary generation # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {splitted} %then [ Data dictionary generated by pgModeler ] %end $br [

Data dictionary index

] $br [ ]
    $br [ ]
  • [Database: ] {name} %if {table} %then $br [ ]

  • Tables $br [ ]
      {table} $br [ ]
    $br [ ]
  • %end %if {foreigntable} %then $br [ ]

  • [Foreign tables] $br [ ]
      {foreigntable} $br [ ]
    $br [ ]
  • %end %if {view} %then $br [ ]

  • Views $br [ ]
      {view} $br [ ]
    $br [ ]
  • %end $br [ ]
$br %if {splitted} %then [ ] $br %end pgmodeler-0.9.2/schemas/datadict/item.sch000066400000000000000000000005121360462764600203510ustar00rootroot00000000000000# Template code for data dictionary generation # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {splitted} %then %set {link} {item} [.html] %else %set {link} \# {item} %end $br [ ]
  • {item}
  • pgmodeler-0.9.2/schemas/datadict/link.sch000066400000000000000000000004731360462764600203560ustar00rootroot00000000000000# Template code for data dictionary generation # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {splitted} %then %set {link} {name} [.html] %else %set {link} \# {name} %end {name} pgmodeler-0.9.2/schemas/datadict/styles.sch000066400000000000000000000057161360462764600207510ustar00rootroot00000000000000# Template code for data dictionary generation # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [body { font-family: sans-serif; color: \#333; margin-left: 2em; margin-top: 2em; background-color: white; } footer { margin-top: 3em; margin-bottom: .5em; font-size: 75%; } h3 { margin-bottom: .5em; } a { color: \#4182c3; text-decoration: none; } a:hover { color: \#080; text-decoration: underline; } \#index { background-color: \#f8f9fa; margin-block-end: 1.5em; list-style: none; display: inline-block; padding: 1em; border: 1px solid \#c0c0c0; border-radius: 4px 4px 4px 4px; } \#index li { list-style: none; margin: 0; } \#index > li > ul { padding-inline-start: 1em; } .table, .foreigntable, .view { font-size: 11pt; border-collapse: collapse; margin-top: 3em; margin-bottom: 1em; } .table caption { background-color: \#d2f3ff; } .foreigntable caption { background-color: \#94f0b1; } .view caption { background-color: \#ffd8a1; } .table, .table caption, .table th, .table td { border: 1px solid \#b4d0da; } .foreigntable, .foreigntable caption, .foreigntable th, .foreigntable td { border: 1px solid \#6aad80; } .view, .view caption, .view th, .view td { border: 1px solid \#ba7c00; } .table caption, .foreigntable caption, .view caption { border-bottom: 0; } .table th, .table .title, .table .label{ background-color: \#e9f8ff; } .foreigntable th, .foreigntable .title, .foreigntable .label { background-color: \#e2ffed; } .view th, .view .title, .view .label { background-color: \#ffebd2; } .type-label { float: right; color: \#212529; font-size: 70%; font-weight: bold; background-color: \#f8f9fa; padding: 5px; border-radius: 4px 4px 4px 4px; } caption { border-radius: 5px 5px 0 0; } .nav-link { font-size: 85%; background-color: \#f2f2f3; padding: 5px; border-radius: 4px 4px 4px 4px; color: \#212529; font-weight: bold; text-decoration: none; margin-right: .5em; } .nav-link:hover { color: white; background-color: \#007bff; } td, th, caption, .title { margin: 0; padding: .3em; } .title, th { font-weight: bold; text-align: center; color: \#535c67; } .data-type, .value, .constr-type { font-family: monospace; text-align: center; } .constr-type { color: \#24486c; } .data-type { color: \#b00; } .bool-field { text-align: center; color: \#080; } .label { font-weight: bold; color: \#444f53; width: 1px; white-space: nowrap; } .tab-name { font-size: 112%; } .tab-description { font-style: italic; padding: .5em; } .nested-tab-parent { padding: 0; } .nested-tab { font-size: 11pt; width: 100%; border-collapse: collapse; } .nested-tab > tbody > tr, .nested-tab > tr{ padding: 0; } .nested-tab td { border-bottom: 0; border-left: 0; } .nested-tab > tbody > tr:first-child td, .nested-tab > tr:first-child td { border-top: 0; } .nested-tab td:last-child { border-right: 0; } ] pgmodeler-0.9.2/schemas/datadict/table.sch000066400000000000000000000060411360462764600205050ustar00rootroot00000000000000# Template code for data dictionary generation # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if ({type-class} == "table") %then %set {colspan} 8 %else %set {colspan} 5 %end
    $br [ ] $br [ ] %if {comment} %then $br [ ] $br [ ] $br [ ] %end %if {columns} %then $br [ ] $br [ ] $br [ ] %if ({type-class} == "table") %then $br [ ] $br [ ] $br [ ] %end $br [ ] $br [ ] $br [ ] $br [ ] %else $br [ ] $br [ ] $br [ ] %end $br [ ] $br [ ] %if {columns} %then {columns} %end %if {constraints} %then $br [ ] $br [ ] $br [ ] %end $br [ ] %if {inherit} %or {partitioned-table} %or {partition-tables} %then $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br %end $br
    $br [ ] {schema}.{name} $br [ ] {type} $br [ ]
    {comment} $br [ ]
    Name[Data type]PKFKUQ[Not null][Default value]Description
    $br [ ] [No columns] $br [ ]
    $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] {constraints} $br [ ]
    Constraints
    NameTypeColumn(s)ReferencesDescription
    $br [ ]
    $br [ ] %if {inherit} %then $br [ ] $br [ ] $br [ ] $br [ ] %end %if {partitioned-table} %then $br [ ] $br [ ] $br [ ] $br [ ] %end %if {partition-tables} %then $br [ ] $br [ ] $br [ ] $br [ ] %end $br [ ]
    Inherits: {inherit}
    [Partition of:]{partitioned-table}
    [Partitions:]{partition-tables}
    $br [ ]
    $br %if {index} %then $br
    %if {splitted} %and {previous} %then $br [ ] ← $sp {previous} %end %if {splitted} %then $br [ ] %else $br [ ] %end [↑ Index] %if {splitted} %and {next} %then $br [ ] {next} $sp → %end $br
    $br %end pgmodeler-0.9.2/schemas/datadict/view.sch000066400000000000000000000033251360462764600203720ustar00rootroot00000000000000# Template code for data dictionary generation # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br [ ] $br [ ] %if {comment} %then $br [ ] $br [ ] $br [ ] %end %if {columns} %then $br [ ] $br [ ] $br [ ] $br [ ] %else $br [ ] $br [ ] $br [ ] %end $br [ ] $br [ ] %if {columns} %then {columns} %end $br [ ] %if {references} %then $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br %end $br
    $br [ ] {schema}.{name} $br [ ] {type} $br [ ]
    {comment} $br [ ]
    Name[Data type]
    $br [ ] [No columns] $br [ ]
    $br [ ] $br [ ] $br [ ] $br [ ] $br [ ] $br [ ]
    References: {references}
    $br [ ]
    $br %if {index} %then $br
    %if {splitted} %and {previous} %then $br [ ] ← $sp {previous} %end %if {splitted} %then $br [ ] %else $br [ ] %end [↑ Index] %if {splitted} %and {next} %then $br [ ] {next} $sp → %end $br
    $br %end pgmodeler-0.9.2/schemas/sql/000077500000000000000000000000001360462764600157405ustar00rootroot00000000000000pgmodeler-0.9.2/schemas/sql/aggregate.sch000066400000000000000000000016531360462764600203720ustar00rootroot00000000000000# SQL definition for aggregate functions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE AGGREGATE ] {name} [ (]{types}[) (] $br $tb [SFUNC = ] {transition}, $br $tb [STYPE = ] {state-type} $br %if {final} %then $tb [,FINALFUNC = ] {final} $br %end %if {initial-cond} %then $tb [,INITCOND = ] {initial-cond} $br %end %if {sort-op} %then $tb [,SORTOP = ] {sort-op} $br %end ); $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/cast.sch000066400000000000000000000016131360462764600173720ustar00rootroot00000000000000# SQL definition for type casts # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: cast] ( {source-type} [,] {destiny-type} ) [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE CAST (] {source-type} [ AS ] {destiny-type} ) $br %if {io-cast} %then $tb [WITH INOUT ] %else %if {function} %then $tb [WITH FUNCTION ] {function} %else $tb [WITHOUT FUNCTION] %end %end %if {cast-type} %then $br $tb [AS ] {cast-type} %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/collation.sch000066400000000000000000000021631360462764600204250ustar00rootroot00000000000000# SQL definition for collations # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if ({pgsql-ver} != "9.0") %then [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE COLLATION ] {name} %if {collation} %then [ FROM ] {collation} %else [ (] %if {locale} %then [LOCALE = ] '{locale}' %else %if {lc-ctype} %then [LC_CTYPE = ]'{lc-ctype}' %end %if {lc-ctype} %and {lc-collate} %then [, ] %end %if {lc-collate} %then [LC_COLLATE =] '{lc-collate}' %end %end [)] %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br %end pgmodeler-0.9.2/schemas/sql/column.sch000066400000000000000000000030111360462764600177270ustar00rootroot00000000000000# SQL definition for columns # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {decl-in-table} %then $tb %else [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {table} %then [ALTER TABLE ] {table} [ ADD COLUMN ] %end %end {name} $sp {type} %if {not-null} %then [ NOT NULL] %end %if ({pgsql-ver} >=f "10.0") %and {identity-type} %then [ GENERATED ] {identity-type} [ AS IDENTITY ] %if {increment} %or {min-value} %or {max-value} %or {start} %or {cache} %or {cycle} %then [(] %end %if {increment} %then [ INCREMENT BY ] {increment} %end %if {min-value} %then [ MINVALUE ] {min-value} %end %if {max-value} %then [ MAXVALUE ] {max-value} %end %if {start} %then [ START WITH ] {start} %end %if {cache} %then [ CACHE ] {cache} %end %if {cycle} %then [ CYCLE] %end %if {increment} %or {min-value} %or {max-value} %or {start} %or {cache} %or {cycle} %then [ )] %end %else %if {default-value} %then [ DEFAULT ] {default-value} %end %end %if {decl-in-table} %then [,] %else [;] # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! $br [-- ddl-end --] $br $br %end %if %not {decl-in-table} %and {comment} %then {comment} $br %end $br pgmodeler-0.9.2/schemas/sql/comment.sch000066400000000000000000000010541360462764600201010ustar00rootroot00000000000000# SQL definition for comments # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {comment} %or ({comment}=="unset") %then [COMMENT ON ] {sql-object} $sp {signature} [ IS ] %if ({comment}=="unset") %then '' %else %if {escape-comment} %then E %end '{comment}' %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %end pgmodeler-0.9.2/schemas/sql/constraint.sch000066400000000000000000000033341360462764600206260ustar00rootroot00000000000000# SQL definition for constraints # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {decl-in-table} %then $tb %else [-- object: ] {name} [ | type: ] {sql-object} [ --] $br %if {table} %then [-- ] {drop} [ALTER TABLE ] {table} [ ADD ] %end %end [CONSTRAINT ] {name} %if {ck-constr} %then [ CHECK ] ({expression}) %if {no-inherit} %then [ NO INHERIT] %end %end %if {pk-constr} %then [ PRIMARY KEY ] ({src-columns}) %end %if {uq-constr} %then [ UNIQUE ] ({src-columns}) %end %if {ex-constr} %then [ EXCLUDE ] $br $tb %if {index-type} %then [USING ] {index-type} %end ( {elements} $br $tb ) %end %if {pk-constr} %or {uq-constr} %then %if {factor} %then %if {decl-in-table} %then $br $tb %end [ WITH (FILLFACTOR = ] {factor} [)] %end %end %if {tablespace} %then $br %if {decl-in-table} %then $tb %end %if {pk-constr} %or {uq-constr} %or {ex-constr} %then [USING INDEX TABLESPACE ] {tablespace} %end %end %if {ex-constr} %and {expression} %then $sp WHERE $sp ( {expression}) %end %if {fk-constr} %then [ FOREIGN KEY ] ({src-columns}) $br %if {decl-in-table} %then $tb %end [REFERENCES ] {ref-table} $sp ({dst-columns}) $sp {comparison-type} $br %if {decl-in-table} %then $tb %end [ON DELETE ] {del-action} [ ON UPDATE ] {upd-action} %end %if {deferrable} %then [ DEFERRABLE ] {defer-type} %end %if {decl-in-table} %then [,] %else [;] $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %end %if %not {decl-in-table} %and {comment} %then {comment} $br %end $br pgmodeler-0.9.2/schemas/sql/conversion.sch000066400000000000000000000014411360462764600206240ustar00rootroot00000000000000# SQL definition for encoding conversions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end CREATE %if {default} %then [ DEFAULT] %end [ CONVERSION ] {name} $br $tb [FOR ] '{src-encoding}' [ TO ] '{dst-encoding}' $br $tb [FROM ] {function}; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/database.sch000066400000000000000000000024671360462764600202140ustar00rootroot00000000000000# SQL definition for databases # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE DATABASE ] {name} %if {template} %then $br $tb [TEMPLATE = ] {template} %end %if {encoding} %then $br $tb [ENCODING = ] {encoding} %end %if {lc-collate} %then $br $tb [LC_COLLATE = ] {lc-collate} %end %if {lc-ctype} %then $br $tb [LC_CTYPE = ] {lc-ctype} %end %if {tablespace} %then $br $tb [TABLESPACE = ] {tablespace} %end %if {owner} %then $br $tb [OWNER = ] {owner} %end %if {connlimit} %then $br $tb [CONNECTION LIMIT = ] {connlimit} %end %if ({pgsql-ver} >=f "9.5") %then %if ({is-template} == "true") %then $br $tb [IS_TEMPLATE = ] {is-template} %end %if ({allow-conns} == "false") %then $br $tb [ALLOW_CONNECTIONS = ] {allow-conns} %end %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/dbmodel.sch000066400000000000000000000022661360462764600200530ustar00rootroot00000000000000# SQL definition for database model # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- Database generated with pgModeler (PostgreSQL Database Modeler).] $br [-- pgModeler version: ] {pgmodeler-ver} $br [-- PostgreSQL version: ] {pgsql-ver} $br [-- Project Site: pgmodeler.io] $br [-- Model Author: ] %if {author} %then {author} %else --- %end $br $br %if {function} %then [SET check_function_bodies = false;] $br [-- ddl-end --] $br $br %end %if {export-to-file} %then %if {role} %then {role} %end %if {tablespace} %then [-- Tablespaces creation must be done outside a multicommand file.] $br [-- These commands were put in this file only as a convenience.] $br {tablespace} $br %end $br [-- Database creation must be done outside a multicommand file.] $br [-- These commands were put in this file only as a convenience.] $br {database} $br %end %if {schema} %then {schema} [SET search_path TO ] {search-path}; $br [-- ddl-end --] $br $br %end %if {shell-types} %then {shell-types} %end %if {objects} %then {objects} %end %if {permission} %then {permission} %end $br pgmodeler-0.9.2/schemas/sql/domain.sch000066400000000000000000000016401360462764600177070ustar00rootroot00000000000000# SQL definition for domains # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE DOMAIN ] {name} [ AS ] {type} %if ({pgsql-ver} != "9.0") %and {collation} %then $br $tb [COLLATE ] {collation} %end %if {default-value} %then $br $tb [DEFAULT ] {default-value} %end %if {not-null} %then $br $tb [NOT NULL] %end %if {constraints} %then {constraints} %end ;$br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/domconstraint.sch000066400000000000000000000003721360462764600213250ustar00rootroot00000000000000# SQL definition for domain's check constraint # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br $tb CONSTRAINT $sp {name} $sp CHECK $sp ({expression}) pgmodeler-0.9.2/schemas/sql/drop.sch000066400000000000000000000013541360462764600174060ustar00rootroot00000000000000# SQL command to drop an object # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {collation} %and ({pgsql-ver} != "9.0") %or %not {collation} %then %if %not {domain} %and {constraint} %or {column} %then %if %not {decl-in-table} %then [ALTER TABLE ] {table} [ DROP ] {sql-object} [ IF EXISTS ] %end %else [DROP ] {sql-object} [ IF EXISTS ] %end %if {column} %or {constraint} %and %not {decl-in-table} %or {extension} %then {name} %else {signature} %end %if {cascade} %and %not {database} %and %not {tablespace} %and %not {role} %and %not {usermapping} %then [ CASCADE] %end ; $br [-- ddl-end --] $br %end pgmodeler-0.9.2/schemas/sql/element.sch000066400000000000000000000010031360462764600200620ustar00rootroot00000000000000# SQL definition for operator class elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {function} %then $tb FUNCTION $tb {stg-number} $tb {signature} %end %if {operator} %then $tb OPERATOR $tb {stg-number} $tb {signature} %if ({pgsql-ver} != "9.0") %then %if {opfamily} %then [ FOR ORDER BY ] {opfamily} %else [ FOR SEARCH ] %end %end %end %if {storage} %then $tb STORAGE $tb {type} %end pgmodeler-0.9.2/schemas/sql/eventtrigger.sch000066400000000000000000000015431360462764600211470ustar00rootroot00000000000000# SQL definition for event triggers # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if ({pgsql-ver} >=f "9.3") %then [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE EVENT TRIGGER ] {name} $br $tb [ON ] {event} %if {filter} %then $br $tb [WHEN ] {filter} %end $br $tb [EXECUTE PROCEDURE ] {function}; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br %end pgmodeler-0.9.2/schemas/sql/excelement.sch000066400000000000000000000010211360462764600205620ustar00rootroot00000000000000# SQL definition for exclude constraints elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br $tb $sp $sp %if {column} %then {column} %else %if {expression} %then {expression} %end %end %if {opclass} %then $sp {opclass} %end %if {use-sorting} %then %if {asc-order} %then [ ASC ] %else [ DESC ] %end %if {nulls-first} %then [NULLS FIRST] %else [NULLS LAST] %end %end [ WITH ] {operator} pgmodeler-0.9.2/schemas/sql/extension.sch000066400000000000000000000016231360462764600204550ustar00rootroot00000000000000# SQL definition for extensions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if ({pgsql-ver} != "9.0") %then [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE EXTENSION ] {name} $br %if {schema} %then [WITH SCHEMA ] {schema} %end %if {cur-version} %then $br [VERSION ] '{cur-version}' %end %if {old-version} %then $br [FROM ] '{old-version}' %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br %end pgmodeler-0.9.2/schemas/sql/foreigndatawrapper.sch000066400000000000000000000015251360462764600223260ustar00rootroot00000000000000# SQL definition for foreign data wrappers # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE ] {sql-object} $sp {name} %if ({pgsql-ver} >=f "9.1") %then $br %if %not {handler} %then [NO HANDLER] %else [HANDLER ] {handler} %end %end $br %if %not {validator} %then [NO VALIDATOR] %else [VALIDATOR ] {validator} %end %if {options} %then $br [OPTIONS (] {options} ) %end ; $br [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/foreignserver.sch000066400000000000000000000013321360462764600213160ustar00rootroot00000000000000# SQL definition for foreign server # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE SERVER ] {name} %if {type} %then [ TYPE ] '{type}' %end %if {version} %then [ VERSION ] '{version}' %end $br [FOREIGN DATA WRAPPER ] {fdw} %if {options} %then $br [OPTIONS (] {options} ) %end ; $br [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/foreigntable.sch000066400000000000000000000033041360462764600211000ustar00rootroot00000000000000# SQL definition for foreign tables # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE FOREIGN TABLE ] {name} %if ({pgsql-ver} >=f "10.0") %and {partitioned-table} %then $br [PARTITION OF ] {partitioned-table} $sp %end %if %not {partitioned-table} %or ({pgsql-ver} =f "10.0") %and {partitioned-table} %then $br [FOR VALUES ] {partition-bound-expr} %end %if {ancestor-table} %then $br [ INHERITS(] {ancestor-table} [)] %end $br [SERVER ] {server} %if {options} %then $br [OPTIONS (] {options} [)] %end ; $br [-- ddl-end --] $br %if {gen-alter-cmds} %then %if {columns} %then $br {columns} %end %if {constraints} %then $br {constraints} %end %end %if {comment} %then {comment} %end %if {cols-comment} %then {cols-comment} %end %if {owner} %then {owner} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end %if {initial-data} %then $br {initial-data} $br %end $br pgmodeler-0.9.2/schemas/sql/function.sch000066400000000000000000000024071360462764600202670ustar00rootroot00000000000000# SQL definition for functions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE FUNCTION ] {name} $sp ( %if {parameters} %then {parameters} %end ) $br $tb [RETURNS ] %if {return-table} %then [TABLE ] ( {return-table} ) %else %if {returns-setof} %then [SETOF ] %end {return-type} %end $br $tb [LANGUAGE ] {language} $br %if {window-func} %then $tb WINDOW $br %end $tb {function-type} $sp %if {leakproof} %then LEAKPROOF %end $br $tb {behavior-type} $br $tb {security-type} $br $tb [COST ] {execution-cost} $br %if {returns-setof} %then $tb [ROWS ] {row-amount} $br %end $tb [AS ] %if {library} %then '{library}' %if {symbol} %then [, ] '{symbol}' %end %else [$$] $br {definition} $br [$$] %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/genericsql.sch000066400000000000000000000006551360462764600206010ustar00rootroot00000000000000# SQL definition for generic sql objects # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: Generic SQL Object --] $br {definition} # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! $br [-- ddl-end --] $br $br pgmodeler-0.9.2/schemas/sql/idxelement.sch000066400000000000000000000011021360462764600205670ustar00rootroot00000000000000# SQL definition for index elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br $tb $sp $sp %if {column} %then {column} %else %if {expression} %then ({expression}) %end %end %if ({pgsql-ver} != "9.0") %and {collation} %then [ COLLATE ] {collation} %end %if {opclass} %then $sp {opclass} %end %if {use-sorting} %then %if {asc-order} %then [ ASC ] %else [ DESC ] %end %if {nulls-first} %then [NULLS FIRST] %else [NULLS LAST] %end %end pgmodeler-0.9.2/schemas/sql/index.sch000066400000000000000000000024331360462764600175500ustar00rootroot00000000000000# SQL definition for indexes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE ] %if {unique} %then [UNIQUE ] %end [INDEX ] %if {concurrent} %then [ CONCURRENTLY ] %end {name} [ ON ] {table} %if {index-type} %then $br $tb [USING ] {index-type} %end $br $tb ( {elements} $br $tb ) %if {expression} %then $tb ({expression}) $sp %end %if {stg-params} %then $br $tb [WITH (] %if {factor} %then [FILLFACTOR = ] {factor} %end %if {fast-update} %then %if {factor} %then [, ] %end [FASTUPDATE = ON] %end %if {buffering} %and ({pgsql-ver} >=f "9.2") %then %if {factor} %then [, ] %end [BUFFERING = ON] %end [)] %end %if {tablespace} %then $br $tb [TABLESPACE ] {tablespace} %end %if {predicate} %then $br $tb [WHERE (] {predicate} [)] %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/language.sch000066400000000000000000000016411360462764600202240ustar00rootroot00000000000000# SQL definition for procedural languages # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE ] %if {trusted} %then %if {handler} %then [TRUSTED ] %end %end [ LANGUAGE ] {name} %if {handler} %then $br $tb [HANDLER ] {handler} %end %if {validator} %then $br [VALIDATOR ] {validator} %end %if {inline} %then $br [INLINE ] {inline} %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/opclass.sch000066400000000000000000000015021360462764600201010ustar00rootroot00000000000000# SQL definition for operator classes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE OPERATOR CLASS ] {name} %if {default} %then [ DEFAULT ] %end [ FOR TYPE ] {type} $br [ USING ] {index-type} %if {family} %then [ FAMILY ] {family} %end [ AS] $br {elements}; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/operator.sch000066400000000000000000000022761360462764600203010ustar00rootroot00000000000000# SQL definition for operators # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE OPERATOR ] {name} [ (] $br $tb [PROCEDURE = ] {operfunc} %if {left-type} %then $br $tb [, LEFTARG = ] {left-type} %end %if {right-type} %then $br $tb [, RIGHTARG = ] {right-type} %end %if {commutator-op} %then $br $tb [, COMMUTATOR = ] OPERATOR({commutator-op}) %end %if {negator-op} %then $br $tb [, NEGATOR = ] OPERATOR({negator-op}) %end %if {restriction} %then $br $tb [, RESTRICT = ] {restriction} %end %if {join} %then $br $tb [, JOIN = ] {join} %end %if {hashes} %then $br $tb [, HASHES ] %end %if {merges} %then $br $tb [, MERGES ] %end ); $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/opfamily.sch000066400000000000000000000013001360462764600202510ustar00rootroot00000000000000# SQL definition for operator family # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE OPERATOR FAMILY ] {name} [ USING ] {index-type}; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/parameter.sch000066400000000000000000000006561360462764600204260ustar00rootroot00000000000000# SQL definition for function parameters # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {variadic} %then VARIADIC %else %if {in} %then IN %end %if {out} %then OUT %end %end %if {reduced-form} %then $sp {type}, $sp %else $sp {name} $sp {type} %if {default-value} %then [ DEFAULT ] {default-value} %end , $sp %end pgmodeler-0.9.2/schemas/sql/partitionkey.sch000066400000000000000000000005701360462764600211630ustar00rootroot00000000000000# SQL definition for partition key elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {column} %then {column} %else %if {expression} %then ({expression}) %end %end %if {collation} %then [ COLLATE ] {collation} %end %if {opclass} %then $sp {opclass} %end pgmodeler-0.9.2/schemas/sql/permission.sch000066400000000000000000000023531360462764600206320ustar00rootroot00000000000000# SQL definition for permissions on objects # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] PERMISSION [ --] %if {privileges} %then $br %if {revoke} %then [REVOKE ] %else [GRANT ] %end {privileges} $br %if {parent} %then $sp $sp [ ON TABLE ] {parent} $br %else $sp $sp [ ON ] {type} $sp {object} $br %end $sp $sp %if {revoke} %then [ FROM ] %else [ TO ] %end %if {roles} %then {roles} %if {revoke} %and {cascade} %then [ CASCADE] %end %else PUBLIC %end ; $br %end %if {privileges-gop} %then $br %if {revoke} %then [REVOKE GRANT OPTION FOR ] %else [GRANT ] %end {privileges-gop} $br %if {parent} %then $sp $sp [ ON TABLE ] {parent} $br %else $sp $sp [ ON ] {type} $sp {object} $br %end $sp $sp %if {revoke} %then [ FROM ] {roles} %if {cascade} %then [ CASCADE] %end ; $br %else [ TO ] {roles} [ WITH GRANT OPTION]; $br %end %end # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br $br pgmodeler-0.9.2/schemas/sql/policy.sch000066400000000000000000000023241360462764600177370ustar00rootroot00000000000000# SQL definition for policy # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if ({pgsql-ver} >=f "9.5") %then [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE POLICY ] {name} [ ON ] {table} %if ({pgsql-ver} >=f "10.0") %then %if {permissive} %then $br $tb [AS PERMISSIVE] %else $br $tb [AS RESTRICTIVE] %end %end $br $tb [FOR ] {command} $br $tb [TO ] %if {roles} %then {roles} %else PUBLIC %end %if {using-exp} %then $br $tb [USING (] {using-exp} [)] %end %if {check-exp} %then $br $tb [WITH CHECK (] {check-exp} [)] %end ;$br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br %end pgmodeler-0.9.2/schemas/sql/relationship.sch000066400000000000000000000005441360462764600211430ustar00rootroot00000000000000# SQL definition for relationships # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {rel1n} %then {constraints} %end #%if {relgen} %then # [ALTER TABLE ] {table} [ INHERIT ] {ancestor-table}; $br $br #%end %if {relnn} %then {table} {constraints} %end pgmodeler-0.9.2/schemas/sql/role.sch000066400000000000000000000026471360462764600174110ustar00rootroot00000000000000# SQL definition for type roles # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE ROLE ] {name} [ WITH ] %if {superuser} %then $br $tb SUPERUSER %end %if {createdb} %then $br $tb CREATEDB %end %if {createrole} %then $br $tb CREATEROLE %end %if {inherit} %then $br $tb INHERIT %end %if {login} %then $br $tb LOGIN %end %if {replication} %and ({pgsql-ver} != "9.0") %then $br $tb REPLICATION %end %if {bypassrls} %and ({pgsql-ver} >=f "9.5") %then $br $tb BYPASSRLS %end %if {password} %then $br $tb %if {encrypted} %then ENCRYPTED %else UNENCRYPTED %end [ PASSWORD ] '{password}' %end %if {connlimit} %then $br $tb [CONNECTION LIMIT ] {connlimit} %end %if {validity} %then $br $tb [VALID UNTIL ] '{validity}' %end %if {ref-roles} %then $br $tb [IN ROLE ] {ref-roles} %end %if {member-roles} %then $br $tb [ROLE ] {member-roles} %end %if {admin-roles} %then $br $tb [ADMIN ] {admin-roles} %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/rule.sch000066400000000000000000000014601360462764600174070ustar00rootroot00000000000000# SQL definition for rules # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE RULE ] {name} [ AS ] {event-type} $br $tb [TO ] {table} $br %if {condition} %then $tb [WHERE ] {condition} $br %end $tb [DO ] {exec-type} $sp %if {commands} %then ({commands}) %else NOTHING %end ;$br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/schema.sch000066400000000000000000000012301360462764600176730ustar00rootroot00000000000000# SQL definition for schemas # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE SCHEMA ] {name}; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/sequence.sch000066400000000000000000000023611360462764600202510ustar00rootroot00000000000000# SQL definition for sequences # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE SEQUENCE ] {name} $br %if {increment} %then $tb [INCREMENT BY ] {increment} $br %end %if {min-value} %then $tb [MINVALUE ] {min-value} $br %end %if {max-value} %then $tb [MAXVALUE ] {max-value} $br %end %if {start} %then $tb [START WITH ] {start} $br %end %if {cache} %then $tb [CACHE ] {cache} $br %end %if {cycle} %then $tb CYCLE %else $tb [NO CYCLE] %end $br $tb [OWNED BY ] %if {owner-col} %then {owner-col} %else NONE %end ; $br %if {owner-col} %and %not {col-is-identity} %then $br [ALTER TABLE ] {table} [ ALTER COLUMN ] {column} $br [ SET DEFAULT nextval('] {name} ['::regclass);] $br %end # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/table.sch000066400000000000000000000047661360462764600175430ustar00rootroot00000000000000# SQL definition for tables # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE] %if ({pgsql-ver} != "9.0") %and {unlogged} %then [ UNLOGGED] %end [ TABLE ] {name} %if ({pgsql-ver} >=f "10.0") %and {partitioned-table} %then $br [PARTITION OF ] {partitioned-table} $sp %end %if %not {partitioned-table} %or ({pgsql-ver} =f "10.0") %and {partitioned-table} %then %if {partition-bound-expr} %then $br [FOR VALUES ] {partition-bound-expr} %else DEFAULT %end %end %if ({pgsql-ver} >=f "10.0") %and {partitioning} %then $br [PARTITION BY ] {partitioning} [ (] {partitionkey} [)] %end %if {ancestor-table} %then $br [ INHERITS(] {ancestor-table} [)] %end %if ({pgsql-ver} <=f "11.0") %and {oids} %then $br [WITH ( OIDS = TRUE )] %end %if {tablespace} %then $br [TABLESPACE ] {tablespace} %end ; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {gen-alter-cmds} %then %if {columns} %then $br {columns} %end %if {constraints} %then $br {constraints} %end %end %if {comment} %then {comment} %end %if {cols-comment} %then {cols-comment} %end %if {owner} %then {owner} %end %if ({pgsql-ver} >=f "9.5") %and {rls-enabled} %then [ALTER TABLE ] {name} [ ENABLE ROW LEVEL SECURITY;] $br [-- ddl-end --] $br %if {rls-forced} %then [ALTER TABLE ] {name} [ FORCE ROW LEVEL SECURITY;] $br [-- ddl-end --] $br %end %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end %if {initial-data} %then $br {initial-data} $br %end $br pgmodeler-0.9.2/schemas/sql/tablespace.sch000066400000000000000000000013231360462764600205410ustar00rootroot00000000000000# SQL definition for tablespaces # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE TABLESPACE ] {name} $br %if {owner} %then $tb [OWNER ] {owner} $br %end $tb [LOCATION ] {directory}; $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/trigger.sch000066400000000000000000000025761360462764600201140ustar00rootroot00000000000000# SQL definition for triggers # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE ] %if {constraint} %then [CONSTRAINT ]%end [TRIGGER ] {name} $br $tb {firing-type} $sp {events} $br $tb [ON ] {table} $br %if {constraint} %then %if {ref-table} %then $tb [FROM ] {ref-table} $br %end %if {deferrable} %then $tb [DEFERRABLE ] {defer-type} $br %else $tb [NOT DEFERRABLE ] $br %end %end %if {old-table-name} %or {new-table-name} %and ({pgsql-ver} >=f "10.0") %then $tb REFERENCING %if {old-table-name} %then [ OLD TABLE AS ] {old-table-name} %end %if {new-table-name} %then [ NEW TABLE AS ] {new-table-name} %end $br %end $tb [FOR EACH ] %if {per-line} %then ROW %else STATEMENT %end $br %if {condition} %then $tb WHEN $sp ({condition}) $br %end $tb [EXECUTE PROCEDURE ] {trigger-func}( %if {arguments} %then {arguments} %end ); $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/typeattribute.sch000066400000000000000000000004571360462764600213520ustar00rootroot00000000000000# SQL definition for user defined type attributes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ ] {name} $sp {type} %if ({pgsql-ver} != "9.0") %and {collation} %then [ COLLATE ] {collation} %end , $br pgmodeler-0.9.2/schemas/sql/usermapping.sch000066400000000000000000000011711360462764600207710ustar00rootroot00000000000000# SQL definition for user mapping # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE USER MAPPING FOR ] %if {owner} %then {owner} %else PUBLIC %end $br [SERVER ] {server} %if {options} %then $br [OPTIONS (] {options} ) %end ; $br [-- ddl-end --] $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/sql/usertype.sch000066400000000000000000000050731360462764600203240ustar00rootroot00000000000000# SQL definition for user defined types # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} [CREATE TYPE ] {name} %if {reduced-form} %then ; $br [-- ddl-end --] $br $br %else %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end %if {base} %then [ (] $br %else [ AS] $br %end %if {composite} %then ( $br {typeattrib} $br ); %end %if {enumeration} %then [ ENUM ] ( %if {enumerations} %then {enumerations} %end [);] %end %if ({pgsql-ver} >=f "9.2") %and {range} %then [RANGE (] $br [SUBTYPE = ] {subtype} %if {collation} %then $br [, COLLATE = ] {collation} %end %if {opclass} %then $br [, SUBTYPE_OPCLASS = ] {opclass} %end %if {canonical} %then $br [, CANONICAL = ] {canonical} %end %if {subtypediff} %then $br [, SUBTYPE_DIFF = ] {subtypediff} %end ); %end %if {base} %then %if {input} %then $tb [INPUT = ] {input}, $br %end %if {output} %then $tb [OUTPUT = ] {output} $br %end %if {receive} %then $tb [, RECEIVE = ] {receive} $br %end %if {send} %then $tb [, SEND = ] {send} $br %end %if {tpmodin} %then $tb [, TYPMOD_IN = ] {tpmodin} $br %end %if {tpmodout} %then $tb [, TYPMOD_OUT = ] {tpmodout} $br %end %if {analyze} %then $tb [, ANALYZE = ] {analyze} $br %end %if {internal-length} %then $tb [, INTERNALLENGTH = ] {internal-length} $br %end %if {by-value} %then $tb [, PASSEDBYVALUE ] $br %end %if {alignment} %then $tb [, ALIGNMENT = ] {alignment} $br %end %if {storage} %then $tb [, STORAGE = ] {storage} $br %end %if {default-value} %then $tb [, DEFAULT = ] {default-value} $br %end %if {element} %then $tb [, ELEMENT = ] {element} $br %end %if {delimiter} %then $tb [, DELIMITER = ] '{delimiter}' $br %end %if {like-type} %then $tb [, LIKE = ] {like-type} $br %end %if {category} %then $tb [, CATEGORY = ] '{category}' $br %end %if {preferred} %then $tb [, PREFERRED = ] true $br %end %if {collatable} %then $tb [, COLLATABLE = ] true $br %end ); %end $br # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! [-- ddl-end --] $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br %end pgmodeler-0.9.2/schemas/sql/view.sch000066400000000000000000000023051360462764600174110ustar00rootroot00000000000000# SQL definition for views # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [-- object: ] {name} [ | type: ] {sql-object} [ --] $br [-- ] {drop} %if {prepended-sql} %then {prepended-sql} $br [-- ddl-end --] $br $br %end [CREATE ] %if ({pgsql-ver} >=f "9.3") %then %if {recursive} %then [RECURSIVE ] %else %if {materialized} %then [MATERIALIZED ] %end %end %end VIEW $sp {name} %if {columns} %then [ (] {columns} [)] %end $br %if ({pgsql-ver} >=f "9.3") %then %if {materialized} %and {tablespace} %then TABLESPACE $sp {tablespace} $br %end %end [AS ] $br #Commom table expression (CTE) %if {cte-exp} %then [WITH ] {cte-exp} %end $br {definition} %if ({pgsql-ver} >=f "9.3") %then %if {materialized} %and {with-no-data} %then $br [WITH NO DATA] %end %end # This is a special token that pgModeler recognizes as end of DDL command # when exporting models directly to DBMS. DO NOT REMOVE THIS TOKEN! $br [-- ddl-end --] $br %if {comment} %then {comment} %end %if {owner} %then {owner} %end %if {appended-sql} %then {appended-sql} $br [-- ddl-end --] $br %end $br pgmodeler-0.9.2/schemas/xml/000077500000000000000000000000001360462764600157415ustar00rootroot00000000000000pgmodeler-0.9.2/schemas/xml/aggregate.sch000066400000000000000000000013401360462764600203640ustar00rootroot00000000000000# XML definition for aggregate functions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {types} %then {types} %end {state-type} {transition} %if {final} %then {final} %end %if {sort-op} %then {sort-op} %end $br $br pgmodeler-0.9.2/schemas/xml/appendedsql.sch000066400000000000000000000007111360462764600207370ustar00rootroot00000000000000# XML definition for appendend SQL commands # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. #Creates element envolving the appended-sql #The tag is converted to in order #to not cause syntax errors on the schema parser $tb $br pgmodeler-0.9.2/schemas/xml/basetype.sch000066400000000000000000000012361360462764600202560ustar00rootroot00000000000000# XML definition for native types # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [ $br pgmodeler-0.9.2/schemas/xml/cast.sch000066400000000000000000000011701360462764600173710ustar00rootroot00000000000000# XML definition for type casts # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end {source-type} {destiny-type} %if {function} %then {function} %end $br $br pgmodeler-0.9.2/schemas/xml/collation.sch000066400000000000000000000015271360462764600204310ustar00rootroot00000000000000# XML definition for collations # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end $br %if {schema} %then {schema} %end %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %else /> $br %end pgmodeler-0.9.2/schemas/xml/column.sch000066400000000000000000000020341360462764600177340ustar00rootroot00000000000000# XML definition for columns # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [ $br $tb {type} %if {comment} %then $tb {comment} %end $tb $br pgmodeler-0.9.2/schemas/xml/comment.sch000066400000000000000000000006461360462764600201100ustar00rootroot00000000000000# XML definition for comments # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. #Creates element envolving the comment #The tag is converted to in order #to not cause syntax errors on the schema parser $tb $brpgmodeler-0.9.2/schemas/xml/constraint.sch000066400000000000000000000032341360462764600206260ustar00rootroot00000000000000# XML definition for constraints # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {decl-in-table} %then $tb %end [ $br %if {tablespace} %then $tb {tablespace} %end %if {decl-in-table} %then $tb %end %if {src-columns} %then $tb $br %end %if {dst-columns} %then %if {decl-in-table} %then $tb %end $tb $br %end %if {ex-constr} %then {elements} %end %if {ck-constr} %or {ex-constr} %then %if {expression} %then %if {decl-in-table} %then $tb %end $tb $br %end %end %if {comment} %then $tb {comment} %end %if {decl-in-table} %then $tb %end $br %if %not {decl-in-table} %then $br %end pgmodeler-0.9.2/schemas/xml/conversion.sch000066400000000000000000000012371360462764600206300ustar00rootroot00000000000000# XML definition for type encoding conversion # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end {function} $br $br pgmodeler-0.9.2/schemas/xml/customidxs.sch000066400000000000000000000004331360462764600206420ustar00rootroot00000000000000# XML definition for custom object indexes in tables # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br $tb [ $br {objects} $tb pgmodeler-0.9.2/schemas/xml/database.sch000066400000000000000000000017431360462764600202110ustar00rootroot00000000000000# XML definition for tablespaces # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {owner} %then {owner} %end %if {tablespace} %then {tablespace} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end $br $br pgmodeler-0.9.2/schemas/xml/dbmodel.sch000066400000000000000000000030111360462764600200410ustar00rootroot00000000000000# XML definition for database model # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br [] $br $br %if {objects} %then {objects} %end %if {permission} %then {permission} %end $br pgmodeler-0.9.2/schemas/xml/domain.sch000066400000000000000000000015531360462764600177130ustar00rootroot00000000000000# XML definition for domains # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %else #%if {constraint} %then # [ constraint=] "{constraint}" #%end [ not-null=] %if {not-null} %then "true" %else "false" %end %if {default-value} %then [ default-value=] "{default-value}" %end %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end > $br {schema} %if {owner} %then {owner} %end %if {collation} %then {collation} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end {type} %if {constraints} %then {constraints} %end $br $br %end pgmodeler-0.9.2/schemas/xml/domconstraint.sch000066400000000000000000000005671360462764600213340ustar00rootroot00000000000000# XML definition for domain's check constraint # PostgreSQL Version: 9.x # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [] $br $tb $tb $br $tb [] $br pgmodeler-0.9.2/schemas/xml/dtd/000077500000000000000000000000001360462764600165145ustar00rootroot00000000000000pgmodeler-0.9.2/schemas/xml/dtd/aggregate.dtd000066400000000000000000000007351360462764600211440ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/baseelements.dtd000066400000000000000000000015011360462764600216550ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/basetype.dtd000066400000000000000000000012071360462764600210250ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/cast.dtd000066400000000000000000000007271360462764600201510ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/collation.dtd000066400000000000000000000010721360462764600211750ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/column.dtd000066400000000000000000000015131360462764600205060ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/constraint.dtd000066400000000000000000000023061360462764600213760ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/conversion.dtd000066400000000000000000000010731360462764600213770ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/customidxs.dtd000066400000000000000000000004251360462764600214140ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/database.dtd000066400000000000000000000014341360462764600207570ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/dbmodel.dtd000066400000000000000000000053561360462764600206300ustar00rootroot00000000000000 %baseelements; %basetype; %object; %role; %tablespace; %database; %schema; %language; %function; %usertype; %cast; %conversion; %operator; %opfamily; %opclass; %aggregate; %domain; %index; %rule; %trigger; %table; %sequence; %view; %textbox; %relationship; %permission; %collation; %extension; %tag; %customidxs; %eventtrigger; %genericsql; %policy; %foreigndatawrapper; %foreignserver; %usermapping; %foreigntable; pgmodeler-0.9.2/schemas/xml/dtd/domain.dtd000066400000000000000000000010721360462764600204600ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/element.dtd000066400000000000000000000005431360462764600206440ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/eventtrigger.dtd000066400000000000000000000011131360462764600217120ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/extension.dtd000066400000000000000000000010501360462764600212210ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/foreigndatawrapper.dtd000066400000000000000000000007651360462764600231050ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/foreignserver.dtd000066400000000000000000000011011360462764600220620ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/foreigntable.dtd000066400000000000000000000021571360462764600216570ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/function.dtd000066400000000000000000000025511360462764600210410ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/genericsql.dtd000066400000000000000000000005671360462764600213550ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/index.dtd000066400000000000000000000017531360462764600203260ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/label.dtd000066400000000000000000000004271360462764600202730ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/language.dtd000066400000000000000000000007101360462764600207720ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/metadata.dtd000066400000000000000000000032261360462764600207740ustar00rootroot00000000000000 %baseelements; %label; %textbox; %tag; %object; %genericsql; pgmodeler-0.9.2/schemas/xml/dtd/object.dtd000066400000000000000000000013651360462764600204640ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/opclass.dtd000066400000000000000000000011451360462764600206560ustar00rootroot00000000000000 %element; pgmodeler-0.9.2/schemas/xml/dtd/operator.dtd000066400000000000000000000011751360462764600210500ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/opfamily.dtd000066400000000000000000000007551360462764600210400ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/permission.dtd000066400000000000000000000022521360462764600214020ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/policy.dtd000066400000000000000000000010701360462764600205060ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/relationship.dtd000066400000000000000000000036741360462764600217240ustar00rootroot00000000000000 %label; pgmodeler-0.9.2/schemas/xml/dtd/role.dtd000066400000000000000000000017411360462764600201550ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/rule.dtd000066400000000000000000000011111360462764600201520ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/schema.dtd000066400000000000000000000011421360462764600204470ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/sequence.dtd000066400000000000000000000013621360462764600210230ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/table.dtd000066400000000000000000000027611360462764600203060ustar00rootroot00000000000000 %column; %constraint; pgmodeler-0.9.2/schemas/xml/dtd/tablespace.dtd000066400000000000000000000007021360462764600213130ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/tag.dtd000066400000000000000000000007221360462764600177650ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/textbox.dtd000066400000000000000000000011621360462764600207060ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/trigger.dtd000066400000000000000000000021601360462764600206530ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/usermapping.dtd000066400000000000000000000007141360462764600215450ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/usertype.dtd000066400000000000000000000022321360462764600210700ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/dtd/view.dtd000066400000000000000000000024551360462764600201710ustar00rootroot00000000000000 pgmodeler-0.9.2/schemas/xml/element.sch000066400000000000000000000006361360462764600200760ustar00rootroot00000000000000# XML definition for operator classes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [ $br $tb {definition} $tb $br pgmodeler-0.9.2/schemas/xml/eventtrigger.sch000066400000000000000000000012231360462764600211430ustar00rootroot00000000000000# XML definition for event triggers # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {function} %then {function} %end %if {filter} %then {filter} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end $br $br pgmodeler-0.9.2/schemas/xml/excelement.sch000066400000000000000000000014041360462764600205700ustar00rootroot00000000000000# XML definition for exclude constraint elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb $tb $br %if {column} %then $tb $tb $tb [ $br %else #%if {expression} %then $tb $tb $tb $br #%end %end %if {opclass} %then $tb $tb $tb {opclass} %end #%if {operator} %then $tb $tb $tb {operator} #%end $tb $tb $br pgmodeler-0.9.2/schemas/xml/extension.sch000066400000000000000000000013331360462764600204540ustar00rootroot00000000000000# XML definition for extensions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {schema} %then {schema} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end $br $br pgmodeler-0.9.2/schemas/xml/foreigndatawrapper.sch000066400000000000000000000014501360462764600223240ustar00rootroot00000000000000# XML definition for indexes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [ $br %else %if {options} %then [ options=] "{options}" %end %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end > $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {handler} %then {handler} %end %if {validator} %then {validator} %end $br $br %end pgmodeler-0.9.2/schemas/xml/foreignserver.sch000066400000000000000000000015371360462764600213260ustar00rootroot00000000000000# XML definition for servers # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [ $br %else %if {type} %then [ type=] "{type}" %end %if {version} %then [ version=] "{version}" %end %if {options} %then [ options=] "{options}" %end %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end > $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {fdw} %then {fdw} %end $br $br %end pgmodeler-0.9.2/schemas/xml/foreigntable.sch000066400000000000000000000026631360462764600211100ustar00rootroot00000000000000# XML definition for tables # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end {server} %if {tag} %then {tag} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end {position} %if {columns} %then {columns} %end %if {constraints} %then {constraints} %end %if {col-indexes} %then {col-indexes} %end %if {constr-indexes} %then {constr-indexes} %end %if {initial-data} %then $tb $br $br $tb $br %end $br $br pgmodeler-0.9.2/schemas/xml/function.sch000066400000000000000000000031661360462764600202730ustar00rootroot00000000000000# XML definition for functions # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end $br %else %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end $br $tb $tb window-func=%if {window-func} %then "true" %else "false" %end $br %if {leakproof} %then $tb $tb leakproof="true" $br %end $tb $tb returns-setof=%if {returns-setof} %then "true" %else "false" %end $br $tb $tb behavior-type="{behavior-type}" $br $tb $tb function-type="{function-type}" $br $tb $tb security-type="{security-type}" $br $tb $tb execution-cost="{execution-cost}" $br $tb $tb row-amount="{row-amount}" > $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {language} %then {language} %end $tb $br %if {return-table} %then {return-table} %else {return-type} %end $tb $br %if {parameters} %then {parameters} %end %if {library} %then $tb [ $br %else $tb $br %end $br $br %end pgmodeler-0.9.2/schemas/xml/genericsql.sch000066400000000000000000000007311360462764600205750ustar00rootroot00000000000000# XML definition for generic sql objects # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br $tb $br %if {objects} %then {objects} %end $br $br pgmodeler-0.9.2/schemas/xml/idxelement.sch000066400000000000000000000013671360462764600206050ustar00rootroot00000000000000# XML definition for indexes elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb $tb $br %if {column} %then $tb $tb $tb [ $br %else #%if {expression} %then $tb $tb $tb $br #%end %end %if {collation} %then $tb $tb {collation} %end %if {opclass} %then $tb $tb $tb {opclass} %end $tb $tb $br pgmodeler-0.9.2/schemas/xml/index.sch000066400000000000000000000020071360462764600175460ustar00rootroot00000000000000# XML definition for indexes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {tablespace} %then {tablespace} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end {elements} %if {predicate} %then $tb $br %end $br $br pgmodeler-0.9.2/schemas/xml/info.sch000066400000000000000000000045341360462764600174010ustar00rootroot00000000000000# XML definition for a single object's metadata # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [ $br %if {position} %then {position} %end %if {appended-sql} %then $tb {appended-sql} %end %if {prepended-sql} %then $tb {prepended-sql} %end $tb %else [/>] %end $br pgmodeler-0.9.2/schemas/xml/label.sch000066400000000000000000000004151360462764600175170ustar00rootroot00000000000000# XML definition for relationship label positioning # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb $brpgmodeler-0.9.2/schemas/xml/language.sch000066400000000000000000000014031360462764600202210ustar00rootroot00000000000000# XML definition for schemas # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [] $br %else [ trusted=] %if {trusted} %then "true" %else "false" %end [>]$br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {handler} %then {handler} %end %if {validator} %then {validator} %end %if {inline} %then {inline} %end $br $br %end pgmodeler-0.9.2/schemas/xml/metadata.sch000066400000000000000000000007411360462764600202220ustar00rootroot00000000000000# XML definition for graphical object metada file # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br [] $br $br %if {info} %then {info} %end pgmodeler-0.9.2/schemas/xml/object.sch000066400000000000000000000010661360462764600177110ustar00rootroot00000000000000# XML definition for custom index for a single column or constraint # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {index} %then $tb %end $tb [ $br pgmodeler-0.9.2/schemas/xml/opclass.sch000066400000000000000000000014641360462764600201110ustar00rootroot00000000000000# XML definition for operator classes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %else [ index-type=] "{index-type}" [ default=] %if {default} %then "true" %else "false" %end %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end > $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {family} %then $tb [] $br %end {type} {elements} $br $br %end pgmodeler-0.9.2/schemas/xml/operator.sch000066400000000000000000000017761360462764600203060ustar00rootroot00000000000000# XML definition for schemas # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [ $br %else %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end > $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {left-type} %then {left-type} %end %if {right-type} %then {right-type} %end %if {commutator-op} %then {commutator-op} %end %if {negator-op} %then {negator-op} %end %if {operfunc} %then {operfunc} %end %if {join} %then {join} %end %if {restriction} %then {restriction} %end $br $br %end pgmodeler-0.9.2/schemas/xml/opfamily.sch000066400000000000000000000012521360462764600202600ustar00rootroot00000000000000# XML definition for operator families # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [ $br %else [name=] "{name}" [ index-type=] "{index-type}" %if {protected} %then [ protected=] "true" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end > $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end $br $br %end pgmodeler-0.9.2/schemas/xml/parameter.sch000066400000000000000000000006731360462764600204260ustar00rootroot00000000000000# XML definition for function parameters # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [$br $tb {type} $tb $br pgmodeler-0.9.2/schemas/xml/partitionkey.sch000066400000000000000000000007651360462764600211720ustar00rootroot00000000000000# XML definition for indexes elements # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb $tb $br %if {column} %then $tb $tb $tb [ $br %else $tb $tb $tb $br %end %if {collation} %then $tb $tb {collation} %end %if {opclass} %then $tb $tb $tb {opclass} %end $tb $tb $br pgmodeler-0.9.2/schemas/xml/permission.sch000066400000000000000000000022231360462764600206270ustar00rootroot00000000000000# XML definition for grants # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $br $tb [] $br %if {roles} %then $tb [] $br %end $tb [] $br $br pgmodeler-0.9.2/schemas/xml/policy.sch000066400000000000000000000016571360462764600177500ustar00rootroot00000000000000# XML definition for policies # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {roles} %then $tb [] %end %if {using-exp} %then $br $tb [] %end %if {check-exp} %then $br $tb [] %end $br pgmodeler-0.9.2/schemas/xml/position.sch000066400000000000000000000003441360462764600203050ustar00rootroot00000000000000# XML definition for object positioning # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [ $br pgmodeler-0.9.2/schemas/xml/prependedsql.sch000066400000000000000000000007151360462764600211310ustar00rootroot00000000000000# XML definition for prepended SQL commands # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. #Creates element envolving the prepended-sql #The tag is converted to in order #to not cause syntax errors on the schema parser $tb $br pgmodeler-0.9.2/schemas/xml/reference.sch000066400000000000000000000013601360462764600203760ustar00rootroot00000000000000# XML definition for view references # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb $br $tb $tb $br %if {columns} %then {columns} %end %if {ref-tables} %then {ref-tables} %end $tb $br %else /> $br %end pgmodeler-0.9.2/schemas/xml/reftable.sch000066400000000000000000000003411360462764600202220ustar00rootroot00000000000000# XML definition for view references # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb $tb [] $br pgmodeler-0.9.2/schemas/xml/relationship.sch000066400000000000000000000054621360462764600211500ustar00rootroot00000000000000# XML definition for relationships # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br $br %else > $br %if {points} %then $tb $br $tb {points} $tb $br %end %if {labels-pos} %then {labels-pos} %end %if %not {relgen} %and %not {reldep} %and %not {relpart} %then %if {columns} %then {columns} %end %if {constraints} %then {constraints} %end %end %if {original-pk} %then {original-pk} %end %if {special-pk-cols} %then $tb [ $br %end %if {partition-bound-expr} %then $tb $br %end $br $br %end pgmodeler-0.9.2/schemas/xml/role.sch000066400000000000000000000027021360462764600174020ustar00rootroot00000000000000# XML definition for roles # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [ $br %else %if {superuser} %then $br [ superuser="true"] %end %if {createdb} %then $br [ createdb="true"] %end %if {replication} %then $br [ replication="true"] %end %if {createrole} %then $br [ createrole="true"] %end %if {inherit} %then $br [ inherit="true"] %end %if {login} %then $br [ login="true"] %end %if {bypassrls} %then $br [ bypassrls="true"] %end %if {encrypted} %then $br [ encrypted="true"] %end %if {connlimit} %then $br [ connlimit=]"{connlimit}" %end %if {validity} %then $br [ validity=]"{validity}" %end %if {password} %then $br [ password=]"{password}" %end %if {protected} %then $br [ protected="true"] %end %if {sql-disabled} %then $br [ sql-disabled="true"] %end > $br %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {ref-roles} %then $tb [] $br %end %if {member-roles} %then $tb [] $br %end %if {admin-roles} %then $tb [] $br %end $br $br %end pgmodeler-0.9.2/schemas/xml/rule.sch000066400000000000000000000015161360462764600174120ustar00rootroot00000000000000# XML definition for indexes # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br %if {comment} %then $tb {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end %if {condition} %then $tb $tb $br %end %if {commands} %then $tb $tb $br %end $br $br pgmodeler-0.9.2/schemas/xml/schema.sch000066400000000000000000000015611360462764600177030ustar00rootroot00000000000000# XML definition for schemas # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. %if {reduced-form} %then $tb %end [ $br %else %if {protected} %then [ protected=] "true" %end %if {rect-visible} %then [ rect-visible=] "true" %end %if {fill-color} %then [ fill-color=] "{fill-color}" %end %if {sql-disabled} %then [ sql-disabled=] "true" %end %if {faded-out} %then [ faded-out=] "true" %end > $br %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end $br $br %end pgmodeler-0.9.2/schemas/xml/sequence.sch000066400000000000000000000016211360462764600202500ustar00rootroot00000000000000# XML definition for sequences # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. [ $br {schema} %if {owner} %then {owner} %end %if {comment} %then {comment} %end %if {appended-sql} %then {appended-sql} %end %if {prepended-sql} %then {prepended-sql} %end $br $br pgmodeler-0.9.2/schemas/xml/style.sch000066400000000000000000000003551360462764600176030ustar00rootroot00000000000000# XML definition for object tag styles # CAUTION: Do not modify this file unless you know what you are doing. # Code generation can be broken if incorrect changes are made. $tb [